Aplicaciones de igual a igual simplificadas

Se ha dicho que Kazaa, la aplicación para compartir archivos de igual a igual (P2P), genera más tráfico de red que cualquier otra aplicación. ¡El sitio web de Kazaa afirma que ha tenido más de 385.000.000 de descargas! A modo de comparación, vi las descargas principales de Download.com, que enumera Ad Aware como la descarga más popular, con solo 117.000.000 de descargas. De las 25 descargas principales de Download.com, reconocí 11 aplicaciones P2P. Solo a partir de estas observaciones, las aplicaciones P2P obviamente están ganando popularidad. Pero el intercambio de archivos no es el único tipo de aplicación P2P. La mayoría de las operaciones de una aplicación de mensajería instantánea típica son P2P. Otros ejemplos son foros y bases de datos distribuidas. Y la lista sigue creciendo.

Para crear aplicaciones P2P como estas, debe tener un medio para descubrir e interactuar con otros pares. La mayoría de las dificultades involucradas en la creación de aplicaciones P2P están relacionadas con el mantenimiento de la red de pares, el formato y el paso de mensajes, el descubrimiento de otros pares y otros problemas similares. Project Jxta y su enlace Java manejan estos aspectos de su aplicación. Al usar Jxta, puede concentrarse en su aplicación, no en problemas genéricos de P2P.

Jxta es una versión abreviada de la palabra yuxtaponer,que significa lado a lado. La Guía del programador de Jxta define a Jxta como "una plataforma informática abierta diseñada para la informática P2P". No es específico de ninguna plataforma ni de ningún lenguaje de programación. Fue concebido en Sun Microsystems y se ha lanzado a la comunidad de código abierto para su mantenimiento y crecimiento. Junto con su lanzamiento, se emitió una implementación inicial de Java. Me centro en esa implementación en este artículo mientras discuto cómo usar Jxta en un entorno Java. También cubro las seis operaciones más comunes de las aplicaciones Jxta implementadas en Java y presento las herramientas que necesita para comenzar a escribir sus propias aplicaciones P2P. Después de leer este artículo, espero que se haya dado cuenta de lo fácil y emocionante que puede ser crear aplicaciones P2P. Las aplicaciones P2P seguirán creciendo no solo en popularidad, sino también en diversidad,y los desarrolladores del mañana deben comenzar a aprender estas tecnologías hoy mismo para mantenerse a la vanguardia.

Java y Jxta

El primer paso para usar Jxta es descargarlo de la página de descargas de Jxta. Como la mayoría de los lectores estarán de acuerdo, a veces los proyectos de código abierto pueden ser difíciles de adquirir y configurar para su uso. Jxta es un ejemplo de un gran proyecto de código abierto que también es muy fácil de descargar y usar de inmediato. Si tiene dificultades y necesita más información sobre cómo descargar y usar Jxta, consulte la Guía del programador de Jxta.

Cuando ejecute por primera vez una aplicación habilitada para Jxta desde un nuevo directorio, se le proporcionará el configurador de GUI.

¿Qué es exactamente un par? Según Daniel Brookshire (un conocido committer de Jxta y llamado "campeón"), es un "punto de comunicación virtual", donde diferentes pares pueden ejecutarse en el mismo dispositivo. El dispositivo no se limita a una PC; puede ser un teléfono celular, un servidor o incluso un elemento tan simple como un sensor. Hay compañeros especiales, los dos que debemos tener en cuenta son el encuentro y el relevo. Un par de encuentro permite que los pares se comuniquen fuera del alcance de la subred local, y se utiliza un par de retransmisión para transmitir información a través de firewalls.

Comencemos repasando las seis operaciones de aplicaciones Jxta más comunes, según se definen en "Los costos de usar Jxta" (IEEE Computer Society, septiembre de 2003). Se enumeran a continuación en el orden en que ocurren normalmente.

  1. Iniciar Jxta: Iniciar Jxta es bastante simple y simplemente es cuestión de unas pocas líneas de código.
  2. Unirse a un grupo de compañeros: Un grupo de compañeros es un conjunto de compañeros que tienen un conjunto común de intereses que se han agrupado. En este artículo, cubro cómo unirse a grupos de pares existentes y cómo crear otros nuevos.
  3. Publicación de anuncios: los anuncios, en pocas palabras, son de lo que se trata Jxta. Jxta utiliza publicidad para descubrir pares, grupos de pares y otros recursos de una manera independiente de la plataforma. Hablo de leer, crear y enviar anuncios nuevos más adelante en este artículo.
  4. Apertura de una tubería de entrada: una tubería es un mecanismo que usan los pares para comunicarse entre sí. Las tuberías son " canales de comunicación virtuales ", virtuales en el sentido de que los usuarios de las tuberías no conocen la dirección real del otro par. Hablo del uso de canalizaciones para enviar mensajes en la sección de este artículo sobre canalizaciones.
  5. Descubrir otros recursos de compañeros: antes de que pueda comunicarse con otros compañeros, primero debe encontrar algunos, de los que también hablaré.
  6. Abrir una tubería de salida: las tuberías de salida se utilizan para enviar mensajes a otros pares. Hay dos clases de conductos de salida: punto a punto, o uno a uno, y propagación, o uno a muchos.

Ahora que sabe a dónde lo llevará este artículo, comencemos nuestro viaje.

Grupos de pares

Los grupos de pares son simplemente una colección de pares con un conjunto de intereses comunes. Los grupos de pares, al igual que los pares, pueden proporcionar servicios, pero un servicio de grupo de pares no depende necesariamente de un par específico que cumpla con las solicitudes. Siempre que un único miembro del grupo proporcione el servicio, el servicio estará disponible. Cada par es miembro del grupo mundial de pares y también, típicamente, del grupo de pares de la red, y puede elegir unirse y dejar otros grupos a voluntad. ¿Cuál es la motivación para crear grupos de pares? Aquí hay algunas razones:

  • Mantenga una región segura: si tiene un grupo de pares seguro, los pares del grupo no tienen que exponer su información crítica.
  • Proporcionar servicios comunes: por lo general, muchos compañeros querrán usar / proporcionar los mismos servicios que otros compañeros, por lo que hacerlo en el grupo tiene sentido. Por ejemplo, podría proporcionar una impresora o un servicio de base de datos distribuida a todos los compañeros del grupo.
  • Límite de alcance de ID: los nombres de las tuberías coinciden con el grupo en el que se crearon. Si dos tuberías tienen el mismo nombre, pero no se crearon en el mismo grupo, no hay problemas para abordarlas.

Examinemos cómo podemos crear y unirnos a un grupo de pares. Los métodos proporcionados por la PeerGroupinterfaz se enumeran a continuación.

  • newGroup(Advertisement pgAdv): normalmente se utiliza para crear instancias de un grupo que ya existe con el anuncio de grupo descubierto
  • newGroup(PeerGroupID gid, Advertisement impl, String name, String description): generalmente se usa para construir nuevos grupos de pares
  • newGroup(PeerGroupID gid): se utiliza para crear una instancia de un grupo de pares existente y publicado con solo el ID del grupo de pares ( gid)

Crear grupos de pares

Crear un grupo de pares básico es relativamente sencillo. Veamos un código:

try { //We will create a new group based on the netPeerGroup so let's copy its //impl advertisement and modify it. ModuleImplAdvertisement implAdv = netPeerGroup.getAllPurposePeerGroupImplAdvertisement(); myPeerGroup = netPeerGroup.newGroup( null, //Create a new group id for this group. implAdv, //Use the above advertisement. "Group name", //This is the name of the group. "Group description" //This is the description of the group. );

System.out.println("---Peer group created successfully, id: " + myPeerGroup.getPeerGroupAdvertisement().getID() ); //Now that the group is created, it is automatically published and stored locally, //but we need to publish it remotely so other peers can discover it. discoveryService.remotePublish( myPeerGroup.getPeerGroupAdvertisement() ); System.out.println("---Published peer group advertisement remotely"); } catch (Exception e) { System.out.println("An error occurred"); e.printStackTrace(); }

La llamada a newGroup()crea y publica el grupo en la caché local. Lo más probable es que desee publicar este anuncio para otros compañeros cuando lo cree, lo que puede hacer llamando remotePublish(). Este método enviará el anuncio del grupo de pares a otros pares. Si necesita asegurarse de enviar el anuncio a los pares en otra subred, debe asegurarse de estar conectado a un par de encuentro. Para hacer esto, use el siguiente código, asumiendo que su compañero de encuentro está activo y configurado correctamente:

private void connectToRdv(PeerGroup peerGroup) { if( rdv == null) { //Get the rdv service rdv = peerGroup.getRendezVousService(); } //Make sure that we are connected before proceeding while( !rdv.isConnectedToRendezVous() ) { try { Thread.sleep(5000); } catch (InterruptedException e1) { System.out.println("rdv connect interrupted"); e1.printStackTrace(); } } } 

Unirse a grupos de compañeros

Unirse a un grupo de compañeros puede ser más difícil que crear uno. Incluso si tenemos un grupo de pares no seguro, aún debemos crear credenciales, vaciar las credenciales y enviar estas credenciales al grupo de pares al que estamos intentando unirnos.

Dado que tenemos un anuncio de grupo de pares, debemos crear todas las credenciales necesarias y unirnos al grupo. Antes de ver el joinGroup()método, veamos una de las clases que usa, la MembershipServiceclase. Hay tres métodos en MembershipServiceque nos interesa, en concreto apply(), join()y resign(). Pasamos al apply()método el tipo de autenticación deseado, y si ese tipo es compatible, nos devuelve un Authenticator. Usamos esto Authenticatorpara unirnos al grupo. Lo pasamos como argumento al join()método y verifica nuestras credenciales. Cuando un compañero quiere dejar un grupo, la llamada a resign()facilita esto.

Ahora veamos el joinGroup()método:

private void joinGroup() { //Assuming myPeerGroup has been instantiated //before calling this method. System.out.println("Trying to join the peer group"); try { //Create the document that will identity this peer. StructuredDocument identityInfo = null; //No identity information required for our group.

AuthenticationCredential authCred = new AuthenticationCredential( myPeerGroup, //Peer group that it is created in null, //authentication method. ); MembershipService membershipService = myPeerGroup.getMembershipService(); Authenticator auth = membershipService.apply(authCred); //See if the group is ready to be joined. //Authenticator currently makes no distinction between //failed and unfinished authentication. if( auth.isReadyForJoin() ) { Credential myCred = membershipService.join(auth); System.out.println("Joined myPeerGroup"); System.out.println("Group id: " + myPeerGroup.getPeerGroupID() ); } else { System.out.println("Unable to join the group"); } } catch (Exception e) { System.out.println("An error occurred"); e.printStackTrace(); } }

Now that we have successfully joined the group, we are able to employ provided peer group services and send messages to the members. When developing P2P applications, thinking about where you want your peer group boundaries ahead of time will assist you in the long run. Keep in mind that peer group boundaries can span many networks.

The joining process can seem daunting at first, but it is pretty straightforward once you do it a few times. Now it is possible to employ many different methods to secure a peer group—the complexity of the joining process depends on the type of authentication desired. I do not discuss these methods here.

Pipes

As explained earlier, a pipe is a virtual channel of communication between two peers. Pipes can be confusing for beginners because newbies try to relate them to what they already know—sockets. While I discuss pipes, keep in mind that they are much more abstract then sockets.

In the most basic form, there are two types of pipes; input pipes and output pipes. Applications use input pipes to receive information, and output pipes, to send information. Pipes can be used in two addressing modes:

  • Unicast (point-to-point) pipes: These pipes connect one output pipe to a single input pipe, but a single input pipe can receive messages from different output pipes
  • Propagate pipes: These pipes connect a single output pipe to many different input pipes

Pipes are an unreliable, unidirectional, and asynchronous means of communication. Beefed-up implementations of pipes are available that provide reliability, bidirectional capabilities, and secure transit.

To create a pipe, first you must create a pipe advertisement and publish it. Then you need to get the pipe service from the peer group and use it to create the pipe. Each pipe has a pipe ID associated with it, which is used to address the pipe.

To create a new pipe ID, we use the IDFactory in the net.jxta.id package. Here is a sample of how to create and print the ID:

 ID id = IDFactory.newPipeID( peerGroup.getPeerGroupID() ); System.out.println( id.toURI() ); 

Note:peerGroup is the peer group for which you want to create the pipe.

Para que dos pares puedan comunicarse entre sí, deben conocer los ID de las tuberías con las que desean comunicarse. Hay algunas formas de asegurarse de que ambos conozcan esta información:

  • Ambos pares leen en el mismo anuncio de canalización desde un archivo
  • La identificación de la tubería está codificada en las aplicaciones
  • Publicar y descubrir el ID de canalización en tiempo de ejecución
  • La identificación de la tubería se genera a partir de una identificación conocida