Desenvolvendo aplicações peer-to
Transcrição
Desenvolvendo aplicações peer-to
Antonio Augusto Mariano da Silva Ricardo Augusto Miguel Ricardo Ribeiro Tavares Desenvolvendo aplicações peer-to-peer em JAVA com JXTA São Paulo 2003 SUMÁRIO 1. INTRODUÇÃO .................................................................................................................... 6 2. CONCEITOS E ARQUITETURAS DE REDES P2P.....................................................11 2.1 CARACTERÍSTICAS DAS REDES P2P...................................................................... 11 2.2 PROCESSAMENTO DISTRIBUÍDO: SETI@HOME .................................................12 2.3 REDES P2P COM INDEXAÇÃO CENTRALIZADA: O NAPSTER .........................13 2.4 A REDE DESCENTRALIZADA: PROJETO GNUTELLA.........................................14 3. INTRODUÇÃO AO JXTA ................................................................................................ 20 3.1 PRINCIPAIS CONCEITOS DA TECNOLOGIA .........................................................23 3.1.1 JXTA ID ................................................................................................................... 23 3.1.2 ADVERTISEMENTS................................................................................................ 24 3.1.3 PEERS ..................................................................................................................... 24 3.1.4 PEER GROUPS....................................................................................................... 25 3.1.5 PIPES....................................................................................................................... 25 3.1.6 ENDPOINTS............................................................................................................ 26 3.1.7 JXTA MESSAGES.................................................................................................... 26 3.1.8 RENDEZVOUS PEERS ........................................................................................... 27 3.1.9 RELAY PEERS......................................................................................................... 28 3.2 PROTOCOLOS JXTA ................................................................................................... 29 3.2.1 PEER DISCOVERY PROTOCOL (PDP) ................................................................ 30 3.2.2 PEER RESOLVER PROTOCOL (PRP) .................................................................. 31 3.2.3 PEER INFORMATION PROTOCOL (PIP) ............................................................ 33 3.2.5 PIPE BINDING PROTOCOL (PBP)....................................................................... 34 3.2.6 ENDPOINT ROUTING PROTOCOL (ERP)........................................................... 36 4. JXTA SHELL ..................................................................................................................... 39 4.1 CONFIGURAÇÃO INICIAL JXTA SHELL................................................................. 40 4.2 COMANDOS JXTA SHELL ......................................................................................... 43 4.2.1 MAN......................................................................................................................... 43 4.2.2 PEERCONFIG......................................................................................................... 44 4.2.3 RDVSTATUS............................................................................................................ 44 4.2.4 ENV.......................................................................................................................... 44 4.2.5 CAT.......................................................................................................................... 44 4.2.6 GREP ....................................................................................................................... 44 4.2.7 HISTORY ................................................................................................................. 45 4.2.8 VERSION ................................................................................................................. 45 4.2.9 EXIT......................................................................................................................... 45 4.2.10 GROUPS................................................................................................................ 45 4.2.11 PEERS ................................................................................................................... 46 4.2.12 WHOAMI ............................................................................................................... 47 4.3 CRIANDO UM GRUPO NA REDE JXTA ................................................................... 47 4.4 CONVERSANDO NA REDE JXTA ............................................................................. 50 4.5 CACHING DE ADVERTISEMENTS........................................................................... 52 4.6 A IMPORTÂNCIA DOS PIPES .................................................................................... 53 4 5. ESTUDO DE CASO: CHAT P2P DESCENTRALIZADO............................................ 56 5.1 CHAT CLIENTE/SERVIDOR X CHAT P2P ............................................................... 56 5.2 ARQUITETURA HÍBRIDA CLIENTE/SERVIDOR E P2P ........................................58 5.3 EXECUTANDO A APLICAÇÃO ................................................................................. 60 5.4 CONFIGURANDO O AMBIENTE JXTA.................................................................... 61 5.5 ANALISANDO O CÓDIGO FONTE............................................................................ 61 5.6 CLASSE CHAT.CHATAPP.JAVA ............................................................................... 62 6. CONCLUSÃO..................................................................................................................... 69 REFERÊNCIAS BIBLIOGRÁFICAS ................................................................................. 72 GLOSSÁRIO .......................................................................................................................... 77 APÊNDICE A – CÓDIGOS FONTE DA IMPLEMENTAÇÃO .......................................79 5 1. INTRODUÇÃO No final da década de 60 a Internet foi concebida como um sistema originalmente P2P, onde as máquinas participantes dessa rede trocavam informações com apenas alguns servidores robustos. Com a popularização e o avanço dos navegadores, e o aumento da capacidade de processamento dos servidores, a internet tornou-se uma rede de potentes servidores entregando conteúdo para os clientes requisitantes. Como proposta inicial da Internet haveria acesso irrestrito a todos os recursos da rede, a qualquer momento, de qualquer lugar, com o uso de qualquer dispositivo. Apesar disso, a Web, ainda hoje está sujeita a um modelo de rede capaz de inibir o acesso a recursos, restringir a riqueza e a profundidade do conteúdo e até mesmo impedir o crescimento da própria Web. A Tecnologia P2P é um esforço concebido, com o objetivo de fornecer acesso total a Web, acompanhando sua constante expansão e aprofundamento. A popularidade de tecnologias de rede P2P aumentou dramaticamente nos últimos anos. Esses serviços estão se proliferando cada vez mais, pela conveniência da comunicação instantânea que proporcionam e pela redução constante dos limites de tráfego que permite a distribuição de filmes, músicas e outros recursos com grande volume de dados. As pessoas buscam, então, acesso a um conteúdo cada vez com maior qualidade. 6 A Web atual utiliza um modelo cliente-servidor no qual servidores centralizados executam tarefas para clientes distribuídos. No modelo P2P, qualquer cliente autorizado pode ter acesso a qualquer serviço na rede comunicando-se com o servidor em que o serviço está residente. Quanto à comunicação P2P, se necessitarmos de caminho inverso ou até mesmo para uma máquina cliente conectar-se a um outro ponto remoto, diversos problemas e dificuldades ainda são enfrentados, basta lembrar o funcionamento do popular software de mensagem instantâneas ICQ. Utilizar o ICQ corretamente via um servidor proxy e principalmente através de um firewall é uma tarefa que exige configurações especiais nesses servidores. As maiorias das redes protegidas permitem apenas o tráfego de informações por http/https, geralmente na porta 80/443. Para envio de mensagens assíncronas alguns softwares usam técnicas como postagem de conteúdo xml e web-services para um servidor que conhece ambos os nós, porém para a transferência de arquivos entre nós remotos isto é praticamente impossível. Outro exemplo clássico das dificuldades enfrentadas por aplicativos P2P como os famosos compartilhadores de arquivos Kazaa e o antigo Napster, é a utilização adequada da largura de banda. Precisamos considerar nestes aplicativos que a utilização de banda ocorre principalmente na hora da transferência de arquivos entre as máquinas. Uma rede local compartilhando 10 máquinas com uma banda de 256 k para download e 128 k para upload (como atualmente ser fornecem os serviços de ADSL mais comuns no Brasil) é praticamente sobrecarregada tanto agindo como cliente P2P ou como aplicação servidora de arquivos. 7 Porém uma das características de sucesso das redes P2P é que ela pode ser totalmente descentralizada. O maior problema enfrentado pelo Napster foi a questão jurídica da troca de arquivos .mp3 entre os usuários. O que realmente o condenou ao “desaparecimento” foi o fato de ser um aplicativo que utilizava metodologias de redes P2P híbridas. Sendo assim a lista de arquivos .mp3 de seus usuários ficavam centralizadas em seu servidor, que “negociava” depois a conexão dos pontos remotos. Com essa centralização tirá-lo do ar foi uma tarefa relativamente simples para os advogados das grandes gravadoras. A solução do Napster tecnicamente é uma solução bastante interessante, pois garantindo a centralização dos dados diminui-se a redundância dos arquivos e ao mesmo tempo agiliza e facilita o processo de pesquisa de arquivos, porém para um assunto tão polêmico como compartilhamento de mp3, esta característica significou a morte desta rede. Diante dessa questão da sobrevivência da rede independente de um servidor centralizado, muitas técnicas surgiram e hoje são utilizados em aplicativos como o compartilhador de arquivos e-donkey. A técnica é basicamente fazer com que cada cliente “compartilhe” além dos arquivos também os nós de rede conhecidos e próximos. A grande desvantagem é a forma como é realizada a pesquisa dos arquivos. Uma consulta simples pode viajar por diversos nós até encontrar uma resposta, e mesmo você não tendo arquivo algum a compartilhar seus recursos estarão sendo utilizado. Como se tem visto nos últimos anos, os usuários da internet querem muito mais do que receber conteúdo pela porta 80, e a explosão da utilização dos softwares descritos anteriormente prova isso mesmo enfrentando os problemas mencionados acima. 8 Tentaremos resgatar neste estudo a real necessidade da cooperação entre os computadores participantes da internet, utilizando assim uma estrutura de rede menos centralizada e restrita. Apesar do assunto principal discutido aqui ser redes P2P não teremos como fugir de conceitos computacionais tradicionais como criptografia, segurança, algoritmos de compactação,redes tcp/ip entre outros, pois os mesmo sempre estarão sendo aplicados na construção de aplicativos P2P. Para o arquiteto de soluções P2P, muitos outros problemas acontecem, como por exemplo a escolha adequada da tecnologia e plataforma a serem utilizadas. Neste estudo estaremos mostrando a importância do framework JXTA para o desenvolvimento de aplicações P2P em JAVA. O objetivo principal de qualquer framework de desenvolvimento é aumentar a produtividade e encapsular funcionalidades, permitindo ao desenvolvedor concentrar-se nas características de sua aplicação, e não reescrevendo e testando funcionalidades que não dizem respeito diretamente ao escopo inicial do seu projeto. "O Projeto JXTA ampliará o acesso à Web e a profundidade do contúdo disponível", Joy Bill (Sun Microsystems,Inc). Através do JXTA a computação distribuída e as tecnologias não-hierárquicas entram em ação. 9 Apesar de ser baseado na tecnologia P2P, o JXTA é muito mais do que uma proposta P2P, pois oferece mecanismos para a criação e o fornecimento de uma categoria de serviços e aplicativos inteiramente nova e para a ampliação dos serviços Web de locais fixos ou centralizados para a borda da rede. Considerando as dificuldades do tema abordado e para fixar e exemplificar os conceitos aqui apresentados, estaremos desenvolvendo uma aplicação case onde os pontos (Nós da rede) trocam mensagens de texto como em uma aplicação de chat tradicional. Estaremos disponibilizando os códigos fonte para quem tiver interessado. 10 2. CONCEITOS E ARQUITETURAS DE REDES P2P 2.1 CARACTERÍSTICAS DAS REDES P2P Nos últimos anos tivemos diversas aplicações P2P sendo usadas por milhões de usuários. Para citar algumas das mais populares podemos lembrar do ICQ (I seek you) e do Napster. Estas duas aplicações revolucionaram a utilização da internet e aproximaram cada vez mais as pessoas conectadas através da internet. Diversas funcionalidades podem ser fornecidas por dispositivos conectados em uma rede P2P: · Compartilhamento de arquivos e publicações. · Armazenamento distribuído e compartilhamento de capacidade de armazenamento. · Busca Semântica e distribuída entre os peers. · Compartilhamento de capacidade de processamento e processamento distribuído · Formação de grupos ou comunidades de peers. · Colaboração de informações, trocas de mensagens instantâneas e comunicação entre os peers. Antes do surgimento das aplicações P2P, a utilização da internet por usuários comuns consistia em uma rede praticamente cliente/servidor, com diversos clientes requisitando conteúdo e serviços publicados por servidores com endereços fixos registrados no DNS (Domain Name System) [TRUELOVE, K., 2001]. 11 Com a inovação tecnológica e a popularização de diversos dispositivos com acesso a Internet, como por exemplo, celulares de última geração e PDA’s (Personal Digital Assistants), passamos a contar com uma rede mais transiente, na qual estes dispositivos também são capazes de fornecer recursos, porém nem sempre estarão conectados ou utilizando-os o mesmos endereços. O aumento da largura de banda, e a maior disponibilidade de acesso fizeram com que os usuários sentissem a necessidade de uma rede mais colaborativa, na qual a busca de conteúdo e serviços, além da interação com outros usuários, deixa de ser privilégio de alguns servidores. Essas talvez tenham sido as motivações para o constante crescimento das redes e aplicativos P2P [TRUELOVE, K., 2001]. Diversas arquiteturas de aplicações tem sido utilizadas ao longo do tempo em aplicações P2P. A seguir abordaremos o funcionamento básico de algumas aplicações importantes na evolução de sistemas P2P. 2.2 PROCESSAMENTO DISTRIBUÍDO: SETI@HOME O grande poder de processamento dos atuais computadores pessoais e a ociosidade da maioria desses computadores, possibilitam o surgimento de aplicações com um processamento realmente distribuído, espalhadas pela internet [SUN MICROSYSTEMS, INC., 2001]. O projeto SETI@HOME (Search for Extraterrestrial Intelligence), com objetivo de identificar vida inteligente fora do planeta terra, é um exemplo bem sucedido deste tipo de aplicação. Ao instalar o screen-saver do projeto, estaremos contribuindo com parte dos cálculos para análise de sinais de rádios, capturados diariamente por potentes telescópios. Depois de realizada a análise dos dados obtidos quando o computador está ocioso, os 12 resultados são enviados para os servidores localizados na Califórnia, que mantém centralizado todos resultados obtidos. Para realizar a análise desses dados em um único computador, uma capacidade de processamento muito grande seria necessária por um longo tempo, e o custo para realização dessa tarefa poderia inviabilizar o projeto. A utilização de recursos ociosos espalhados pela internet, de forma gratuita, era talvez uma das poucas soluções disponíveis que viabilizariam o projeto [Web site SETI@home]. Os diversos resultados obtidos das análises realizadas, e a evolução do projeto, podem ser conferidos no site http://setiathome.ssl.berkeley.edu/. O projeto SETI@HOME foi um dos pioneiros na distribuição de tarefas para processamento distribuído pela internet, e a quantidade de resultados obtidos contribuem para a análise de vida extra terrestre, alem de possibilitar que diversos usuários anônimos pela internet possam dar sua contribuição em termos de recursos para o projeto. 2.3 REDES P2P COM INDEXAÇÃO CENTRALIZADA: O NAPSTER O Napster pode ser considerado um marco na história da internet, especialmente quando falamos de um assunto tão polêmico como compartilhamento de MP3. Criado originalmente com este propósito, o Napster permitia a seus usuários a rápida pesquisa de arquivos .mp3 compartilhados e a troca de mensagens instantâneas entre peers. Depois de configurada a pasta de compartilhamento de conteúdo, o Napster enviava a lista de arquivos compartilhados para um repositório central de dados, que era o responsável também pelo armazenamento e atualização do endereço IP de cada conexão realizada pelo 13 programa. Este repositório central de dados também indica se um determinado usuário está on-line naquele momento ou não [PARAMESWARAN, M.; SUSARLA, A.; WHINSTON , A., 2001]. Essa arquitetura centralizada de indexação de conteúdo foi a grande responsável pela eficiência da procura de arquivos .mp3 no Napster, pois dessa maneira, os servidores responsáveis pela indexação, poderiam retornar todos os peers on-line que possuíam um determinado arquivo em uma busca rápida e precisa. Depois de realizada a busca do conteúdo desejado, toda a comunicação e troca de informações eram feitas diretamente entre os peers, sem carga adicional nos servidores de indexação, que atuavam apenas realizando buscas, autenticando usuários e “apresentando” peers, possibilitando que esses efetuassem a transferência de dados diretamente da melhor forma possível. Esta arquitetura centralizada também foi a grande responsável pelo fim do Napster. Após uma ação judicial, os servidores centrais de indexação de conteúdo foram impedidos de funcionar, e os peers não podiam mais contar com a busca centralizada e não sabiam mais quem possuía um determinado conteúdo. Também ficou fácil para as autoridades saberem quem estava requisitando um determinado tipo de conteúdo, e em pouco tempo, grande parte das buscas que envolviam conteúdos com direitos autorais estavam censuradas, o que levou gradativamente a rede Napster ao fim. 2.4 A REDE DESCENTRALIZADA: PROJETO GNUTELLA 14 O aplicativo compartilhador de arquivos GNUTELLA foi desenvolvido em meados de março de 2000. Sua versão inicial foi desenvolvida por Justin Frankel e Tom Pepper, criadores do famoso player de arquivos de áudio WINAMP. A empresa criada por eles chamada NULLSOFT, detentora inicial do WINAMP foi adquirida pela AOL em 1999 [ANDY, O., 2001]. Desenvolvido em apenas 14 dias, o GNUTELLA ficou poucas horas hospedado nos servidores da AOL, e foi baixado por mais de 10.000 usuários. Imediatamente receosa de futuras ações judiciais por parte das grandes gravadoras musicais, o software foi retirado do ar e o projeto encerrado dentro da empresa. Porém, os 10.000 downloads realizados foram suficientes para a continuidade da rede [ANDY, O., 2001]. Brian Mayland iniciou o processo de engenharia reversa do software original, continuando a idéia em um projeto open source com ajuda de diversos outros programadores espalhados pelo mundo. Atualmente diversos softwares compartilhadores de arquivo utilizam o protocolo de comunicação criado no projeto GNUTELLA, e assim compartilham a mesma rede. Por atuarem tanto como clientes quanto servidores, esses softwares são apelidados de “servents”. Cada servent funciona basicamente como um web server, servindo os conteúdos compartilhados; e como um browser, pesquisando e requisitando os conteúdos armazenados distribuidamente nos servents de outros peers. Toda a comunicação realizada pelos peers é efetuada pela porta 80, utilizando o protocolo HTTP (Hiper Text Transfer Protocol), o mesmo utilizado pelos web browsers [ANDY, O., 2001]. O objetivo inicial do projeto era desenvolver um aplicativo compartilhador de arquivos totalmente descentralizado, e que sobrevivesse a qualquer tipo de intervenção. Para que isso seja possível, a rede formada pelos usuários do GNUTELLA não tem um servidor 15 central de indexação e a busca é realizada ponto a ponto por cada computador participante da rede, utilizando técnicas como flooding, isto é, enviando consultas para todos os computadores conhecidos de um peer, e esses computadores enviam a mesma consulta para todos os seus conhecidos, com objetivo de propagar as consultas para o maior número de peers conhecidos. Cada nó nesta rede é responsável por manter a lista de nós conhecidos, buscar novos peers na rede, e encaminhar cada requisição (Identificada unicamente por uma chave gerada) para os peers conhecidos, até que algum deles responda avisando que possui o conteúdo desejado. Neste caso as respostas percorrem o caminho de volta, identificando o peer que possui o conteúdo. Toda e qualquer requisição de consulta é armazenada em cache, isto é, armazenada localmente pelos peers para uma futura consulta, evitando que as informações sejam desperdiçadas e que requisições duplicadas sejam reenviadas. Além disso, somente a identidade do último peer que encaminhou a requisição é conhecida, garantindo a privacidade na busca de conteúdo. Somente o conteúdo que fez a requisição sabe que uma determinada consulta pertence a ele. Para os participantes da rede, não há como distinguir se o peer que encaminha uma consulta, é realmente o que originou esta consulta ou simplesmente mais um peer encaminhando a consulta, dando assim a continuidade do processo de pesquisa do conteúdo requerido [ANDY, O., 2001]. 16 Figura 1 - Propagação de busca entre peers na rede GNUTELLA. Por ser uma rede totalmente descentralizada, é necessário conectar-se a um host participante da rede para poder ingressá-la. Um cache de host também é fornecido inicialmente e permite a descoberta e a apresentação de outros peers. Um dos notórios problemas dos aplicativos que utilizam o protocolo GNUTELLA, é o seu consumo de banda e a demora na realização de buscas. Isso acontece devido a total descentralização da rede e a repetição das mensagens de busca enviadas. Cada mensagem de busca contém um TTL (Time To Live), caracterizado pelo número de saltos máximos (Hops to Live, HTL) entre peers que a mensagem deve sobreviver na rede. O padrão utilizada no GNUTELLA é de 256 HTLs para cada busca realizada. A cada peer em que a busca é encaminhada este valor é decrementado, evitando que uma mensagem seja propagada infinitamente pela rede [ANDY, O., 2001], [ANDY, O., 2001]. Apesar do consumo de banda excessivo e da demora na obtenção de resultados, as buscas são sempre efetivas e o conteúdo, 17 caso disponível na rede, quase sempre encontrado. Caso o conteúdo procurado seja encontrado, toda e qualquer transferência de dados é realizada diretamente entre o peer que contém o conteúdo e o que iniciou a busca, pois ambos já conhecem os endereços de rede utilizados, caracterizando uma comunicação totalmente P2P. Apesar da descentralização da rede GNUTELLA, alguns softwares clientes possuem algoritmos para análise da rede, permitindo que peers mais capacitados em processamento e recursos de banda, fiquem no topo da hierarquia em relação aos peers menos favorecidos. Desta forma conseguimos manter a descentralização da rede, porém de uma forma mais organizada, otimizando o tempo necessário para propagação de buscas e reduzindo o consumo de banda (Figura 2). Dos diversos softwares que utilizam a rede GNUTELLA nem todos implementam esta funcionalidade ainda, dificultando uma análise efetiva da rede formada [ANDY, O., 2001]. Figura 2 - Rede GNUTELLA organizada por algoritmos de análise de rede. Peers que possuem maior capacidade de processamento ou maior largura de banda ficam no topo da hierarquia, atuando como reendereçadores de mensagens e indexadores de conteúdo. A grande vantagem dessa arquitetura totalmente descentralizada em relação à abordagem cliente/servidor anterior, é a impossibilidade de se acabar com a rede ou inutilizála caso um dos peers participantes saia da rede por algum motivo. A censura de um 18 determinado conteúdo torna-se praticamente impossível dessa forma, e o anonimato e a privacidade dos publicadores e compartilhadores de conteúdo são garantidas. Mas se compararmos a eficiência e a rapidez da busca com a arquitetura cliente/servidor utilizada pelo Napster veremos que esta última leva uma grande vantagem. Recentemente alguns usuários da rede GNUTELLA foram processados por gravadoras que descobriram a sua identidade. Mas como isso foi possível em uma rede descentralizada, sem um controle central de autenticação? A resposta é bem simples. A rede GNUTELLA trata todos os nós da rede da mesma forma. Não seria difícil para um nó arbitrário forjar a publicação de um conteúdo bastante requisitado e descobrir o endereçamento IP dos seus requisitantes. Apesar da pesquisa de conteúdo não revelar a identidade do peer que iniciou a requisição, a transferência de dados do conteúdo, caso aconteça, e feita diretamente entre os peers, permitindo que um deles obtenha o endereço de rede utilizado pelo outro [ANDY, O., 2001]. Com esses dados em mãos a identificação de um usuário em toda a internet é na maioria dos casos bem simples, uma vez que cada provedor de acesso mantém o histórico e a localização física de cada conexão. Figura 3 - Comparação entre as buscas realizadas na rede Napster (Indexação de conteúdo centralizada) e na rede GNUTELLA (Busca distribuída por “flooding”). 19 3. INTRODUÇÃO AO JXTA JXTA (Juxtapose) é um projeto open source de protocolos P2P baseados em mensagens XML para o desenvolvimento de aplicativos distribuídos, permitindo que qualquer dispositivo conectado em uma rede, independente de sua plataforma, natureza, ou protocolo de rede possa interagir, compartilhar recursos, e formar uma rede distribuída, descentralizada e cooperativa. O projeto foi iniciado pela Sun Microsystem em abril de 2001 e teve como arquiteto líder o chefe do departamento de computação da Sun Billy Joe [SUN MICROSYSTEMS, INC.]. O nome vem de juxtapose, uma referência ao modelo oposto de aplicações P2P em relação aos modelos tradicionais utilizados como cliente/servidor. JXTA não é uma linguagem de programação, é uma especificação que tem implementações em diversas linguagens como C e Java. O objetivo do JXTA é facilitar o desenvolvimento de aplicativos P2P, encapsulando funcionalidades e serviços comuns, escondendo a complexidade das implementações para o desenvolvedor de aplicativos, podendo esse se preocupar somente com a lógica e os detalhes pertinentes a sua aplicação [SUN MICROSYSTEMS, INC.]. A idéia básica do JXTA é formar uma camada de rede virtual, independente da rede real utilizada por cada dispositivo, provendo transparência da rede utilizada pelos dispositivos e permitindo que mesmo dispositivos conectados indiretamente à internet através de um proxy, ou por um gateway que realiza o NAT (Network Address Translation), ou até mesmo 20 com restrições de um firewall, possam participar da rede oferecendo serviços. Nessa situação todo o roteamento necessário para a comunicação de peers entre redes distintas é realizado de forma transparente, utilizando-se de peers intermediários que possam encaminhar as requisições entre redes. A especificação JXTA foi concebida para ser independente de uma linguagem específica de programação (como por exemplo C ou Java), plataformas e sistemas operacionais (como Windows e LINUX), e mesmo dos protocolos de rede utilizados (como TCP/IP ou Bluetooth) [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. A forma básica de comunicação entre os participantes dessa rede é através de mensagens XML padronizadas, chamadas advertisements, respeitando os protocolos definidos nas especificações definidas no projeto JXTA. [GONG, Li, 2002]. PeerID PeerID PeerID PeerID PeerID PeerID PeerID PeerID Rede Virtual JXTA Mapeamento Virtual Rede Física Peer Peer TCP/IP Peer Firewall Peer HTTP Peer Peer Peer NAT Peer Figura 4 - JXTA forma uma rede virtual, permitindo a comunicação transparente entre peers que utilizam protocolos diferentes ou pertencem a redes diferentes. Um dos fatores que contribuem para o sucesso da tecnologia P2P atualmente, e conseqüentemente do projeto JXTA, é a diversidade de dispositivos tecnológicos presentes em nossas vidas atualmente. Celulares, PDAs e desktops compartilham muitas informações, 21 mas quase sempre de uma forma indireta, com intermediários, através de servidores e dependendo de uma rede comum, como a Internet ou uma rede local. Utilizando JXTA podemos ter esses diversos dispositivos conectados sem a necessidade de uma estrutura centralizada de rede. O JXTA também permite que a topologia de rede mais adequada para uma aplicação seja definida por seus criadores, possibilitando o surgimento de novos serviços e funcionalidades. Cada aplicação possui requisitos de rede que nem sempre se encaixam nos modelos e arquiteturas tradicionais existentes. Em muitos casos precisamos utilizar mais de uma arquitetura simultaneamente para suprir os requisitos de uma aplicação, como por exemplo, utilizar uma comunicação típica cliente/servidor, e em alguns casos específicos poder comunicar diretamente dois peers sem a necessidade de utilizar um servidor como intermediário. Figura 5 - Diversos dispositivos podem compartilhar informações, independente de sua origem ou protocolo de rede, através da camada de rede virtual oferecida por JXTA. 22 3.1 PRINCIPAIS CONCEITOS DA TECNOLOGIA O JXTA define algumas abstrações importantes de rede que permitem a formação de uma camada de rede virtual: Primeiramente um endereço lógico para cada peer é definido em toda rede, através de um peer ID. Os peers auto-organizam-se em grupos chamados peer groups, formando domínios virtuais com características pré-definidas. Os peers são responsáveis também pela criação de recursos e serviços, como por exemplo os peers groups, que precisam ser publicados para serem válidos para os outros peers participantes da rede JXTA. Cada recurso e serviço possue um tipo específico de advertisement. As operações de bind necessárias em ambientes distribuídos, como traduções de nomes em endereços de rede, são implementadas por mecanismos denominados resolvers. Finalmente pipes são utilizados para comunicação entre peers de uma forma transparente [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. A seguir definiremos as principais abstrações e componentes característicos da rede JXTA. 3.1.1 JXTA ID Cada elemento participante da rede recebe um identificador UUID de 128 bits, garantido sua correta e única identificação na rede [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. 23 3.1.2 ADVERTISEMENTS Todas as entidades participantes da rede P2P (peers) são representadas por advertisements. Peers publicam, isto é, disponibilizam dados na rede, mantém um cache e trocam advertisements para descobrir novos peers e buscar novos recursos na rede. Os advertisements representam uma abstração de um determinado recurso disponível em uma rede JXTA. Toda e qualquer publicação e descoberta de objetos participantes na rede JXTA é feita através de publicação de advertisements específicos [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. <?xml version=”1.0”?> <!DOCTYPE jxta:PGA> <jxta:PGA xmlns:jxta=”http://jxta.org”> <GID>urn:jxta:jxta-NetGroup</GID> <MSID>urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000010206</MSID> <Name>NepPeerGroup</Name> <Desc>NetPeerGroup by default</Desc> </jxta:PGA> Figura 6 - Exemplo de um advertisement para criação de um peer grupo na rede JXTA. 3.1.3 PEERS Peer é qualquer entidade que possa participar e interagir com a rede, seja ela um computador, um processo, um processador ou até mesmo um usuário. Para ser considerado um peer essa entidade deve ao menos entender os protocolos de comunicação básicos definidos pela tecnologia, como o Peer Resolver Protocol e o EndPoint Router Protocol, explicados mais adiante neste capítulo [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; 24 ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. 3.1.4 PEER GROUPS Os peers estão organizados em peer groups. Peers agrupados sob o mesmo grupo tem algo em comum, como por exemplo, o seu conteúdo compartilhado, e seguem as regras definidas e atribuídas pelo seu criador. A criação de peer groups e suas regras de utilização podem ser definidas por qualquer participante da rede JXTA [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. 3.1.5 PIPES Pipes são canais de comunicação virtuais usados para envio e recebimento de mensagens entre peers. Pipes não estão associados fisicamente com a localização/endereço de um peer e são identificados por um pipe ID. Pipes também possibilitam uma comunicação assíncrona, definindo pipes de entrada e saída. Por não estarem associados com o endereço físico de um peer, aplicações e serviços que se comunicam através de pipes não são afetadas pela mudança de localização dos peers e eventuais mudanças de rota que possam acontecer durante a transmissão de dados. Mensagens são enviadas pelos pipes e recebidas pelos “ouvintes” registrados neste pipe. Pipes podem restringir o conteúdo a ser trafegado e prover comunicação segura entre os endPoints [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; 25 HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. Peer B Peer C Pip e Peer D Pipe entre Peer B e Peer E Peer A Peer E Figura 7 - A Comunicação entre peers é realizada através de pipes. 3.1.6 ENDPOINTS É o endereço de rede ao qual um peer está localizado. Ao se estabelecer uma conexão entre peers os pipes se encarregam de saber o endPoint dos participantes, abstraindo os peers de um endereçamento físico [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. 3.1.7 JXTA MESSAGES JXTA Messages são mensagens XML padronizadas, utilizadas para a comunicação entre os peers. A comunicação é feita enviando e recebendo mensagens. Messages podem ser de vários tipos, cada um específico para o tipo de conteúdo trafegado, como por exemplo, 26 dados binários em grande quantidade [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. 3.1.8 RENDEZVOUS PEERS Rendezvous Peers são peers especiais que indexam informações sobre outros peers que ele tem conhecimento. Sendo assim, este peer pode ajudar na busca por um peer específico ou no roteamento de mensagens propagadas na rede. Caso não haja nenhuma informação disponível em seu índice, a requisição é passada adiante para outro rendezvous peer, e assim por diante. Rendezvous peers são de fundamental importância na rede para diminuir o tráfego de mensagens enviadas e para otimizar o processo de busca de recursos, evitando que a busca propague-se pela a rede inteira. A publicação de um Rendezvous peers é feita pela publicação de um advertisements específico para este propósito. [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. 27 Super-Peers Adv Rdv 2 Rdv 1 Index Adv Peer A Índice Adv Index Propagação(2) Resposta(3) Peer B Adv Query(1) Resposta(4) Rede Virtual JXTA Rede Física Peer 2 Peer 1 Firewall NAT Figura 8 - Peers rendezvouz otimizam a procura de advertisements na rede, reduzindo o número de mensagens propagadas, funcionando muitas vezes como um atalho para encontrar os recursos disponíveis na rede. 3.1.9 RELAY PEERS Muito dos peers participantes da rede JXTA possuem conexões temporárias, e freqüentemente tem o acesso direto à internet restrito por um firewall ou por uma conexão a ser realizada através de um NAT. Para conseguir acesso aos recursos da rede JXTA, relay peers podem efetuar o roteamento de mensagens entre peers, possibilitando que ambos se comuniquem. Relay peers ajudam o roteamento de mensagens entre peers, indicando os passos necessários (Hops) para que uma determinada mensagem atinja seu destino. Qualquer peer, desde que tenha as devidas permissões em seu grupo, pode tornar-se um relay peer. A publicação de Relay peers é feita pela publicação de um advertisement específico para esta finalidade [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. 28 Super-Peers Relay D Relay C Peer A Relay Peer B Resposta(4) Rede Virtual JXTA Rede Física Peer C Envio Pulling NAT Envio Firewall Pulling HTTP Figura 9 - Relay peers possibilitam a comunicação entre peers pertencentes a redes distintas ou com restrições de um firewall ou NAT. 3.2 PROTOCOLOS JXTA O JXTA define diversos protocolos, sendo cada um deles responsável por executar uma tarefa específica na rede P2P como, por exemplo, realizar o roteamento de mensagens e possibilitar a comunicação entre peers. Cada protocolo é definido por uma ou mais mensagens em formato XML, trocadas entre os peers participantes da rede. Atualmente estão definidos seis protocolos com suas funcionalidades explicadas a seguir [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]: 29 3.2.1 PEER DISCOVERY PROTOCOL (PDP) Este protocolo habilita um peer a procurar advertisements do tipo peers, peers groups, pipes e conteúdo, além de enviar os advertisements publicados pelo próprio peer para o restante da rede. Este é o principal canal de comunicação do peer com o restante da rede. A descoberta de novos peers na rede, pode ser feita explicitamente, especificando o UUID do peer ou do peer group desejado, neste último caso retornando todos os peers pertencentes ao grupo. A descoberta de todos os peers groups também é possível [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. Figura 10 - XML Schema que define os elementos de uma Discovery Query. <Type> Deve conter o tipo de advertisement que está sendo enviado: 30 0 - Peer Advertisements 1 - Peergroup Advertisements 2 - Qualquer tipo de advertisement <Threshold> Deve conter o número máximo de respostas que um peer deve enviar ao receber este advertisement. <PeerAdv> O conteúdo xml do advertisement específico que deve ser enviado. <Attribute>, <Value> Elementos podem ser definidos e adicionados ao advertisement a ser enviado. Dessa forma, outros peers podem procurar por um advertisement específico, contendo um elemento correspondente ao definido em <Attribute> e também a um valor específicado em <Value>. 3.2.2 PEER RESOLVER PROTOCOL (PRP) O PRP habilita um peer a enviar e receber queries para procura de peers, peers groups, pipes e outras informações na rede. Cada query é associada a um Handler, responsável por processar a mensagem e aguardar as respostas resultantes da query a serem enviadas pelos peers. Peers que provêem compartilhamento de arquivos podem oferecer uma busca avançada de seu repositório de dados para os outros peers [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. 31 Figura 11 - XML Schema para uma Resolver Query, que deve ser enviada a um Handler específico definido na rede JXTA. As respostas, caso disponíveis, serão enviadas seguindo as especificações do Response Query Schema. <jxta:Cred> Credêncial do peer que envia a query. <HandlerName> Deve conter uma string especificando o Handler de destino que receberá esta query. <SrcPeerID> Deve conter o id do peer que originou a query no formato URN. <QueryID> Deve conter o id associado a esta query para futuramente identificar as respostas recebidas. <HC> Indica o número de peers que esta query já percorreu. A cada peer que encaminha esta query, este valor deve ser incrementado. <Query> Deve conter a query a ser enviada. 32 3.2.3 PEER INFORMATION PROTOCOL (PIP) Responsável por obter informações de outros peers, como seu estado atual, tempo de resposta, utilização de recursos e tráfego atual. Podemos enviar uma mensagem de ping e saber se o peer ainda continua na rede ou não. Utiliza o Peer Resolver Protocol para enviar e propagar as requisições de informação [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003], [SUN MICROSYSTEMS, INC., 2002]. Figura 12 - XML Schema definindo os elementos necessários para o envio de queries para obtenção de informações de outros peers. <sourcePid> Contém o peer id do peer que originou a query. <targetPid> Contém o peer id do peer que se quer mais informações. <request> Deve contér o tipo de resposta que se quer obter , como por exemplo, o número de Hops necessários para se comunicar com o peer. 33 3.2.4 RENDEZVOUS PROTOCOL (RVP) Peers podem se tornar peers do tipo Rendezvous, indexando advertisements do grupo a que pertence e propagando mensagens para os ouvintes (Listeners) que estão registrados nele. Este protocolo controla a propagação de mensagens dos peers Rendezvous para os peers que pertencem ao mesmo grupo [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. Figura 13 - XML Schema definindo os elementos necessários para publicação de um Rendezvous Advertisement, transformando um determinado peer como Rendezvous do grupo a que ele pertence. <Name> Pode conter um nome opcional associado a este rendezvous peer. <RdvGroupId> Deve conter o ID do PeerGroup que este peer se tornará um rendezvous peer. <RdvPeerId> Deve conter o ID do Peer que se tornará um rendezvous peer. 3.2.5 PIPE BINDING PROTOCOL (PBP) Protocolo responsável por realizar a conexão de um peer com um ou mais peers. 34 Para cada peer destino que a conexão virtual é estabelecida, um pipe de entrada e saída é aberto (isto é, é realizado um “bind”), permitindo assim comunicação assíncrona entre os participantes. Utiliza o Peer Resolver Protocol para enviar e propagar a requisição de bind dos pipes [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. Figura 14 - XML Schema definindo os elementos necessários para a criação de um Pipe Advertisement. <Id> Deve conter um identificador único para o pipe. <Type> Indica o tipo de pipe que está sendo publicado: JxtaUnicast - Pipe não confiável, não garante a entrega do contéudo, pode entregar o conteúdo mais de uma vez e não garante a ordem da entrega de conteúdo. JxtaUnicastSecure – Fornece as mesmas funcionalidades do tipo JxtaUnicast, porém permite comunicação segura, tendo o seu contéudo criptografado. JxtaPropagate – Pipe de difusão, utilizado para o envio de mensagens de um para muitos (one-to-many) pipes. 35 <Name> Elemento opcional que pode ser adicionado ao advertisement, indicando um nome não único, facilitando a sua identificação na rede JXTA. 3.2.6 ENDPOINT ROUTING PROTOCOL (ERP) Protocolo responsável por informar a rota para comunicação entre dois peers distintos quando uma conexão direta não é possível entre ele. A comunicação direta não será possível quando dois peers utilizarem redes de protocolos diferentes ou quando entre eles há um firewall ou a conexão é realizada por NAT. Neste caso o Endpoint Routing Protocol informa a rota necessária, indicando os gateways necessários para realizar a conexão. Caso a rota entre dois peers mude, ou a topologia da rede mude por qualquer motivo, este protocolo será utilizado para indicar a nova rota de comunicação entre eles. Qualquer peer pode ser um roteador deste tipo implementando o Endpoint Routing Protocol [TRAVERSAT, B.; ABDELAZIZ, M.; DUIGOU, M.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2002], [TRAVERSAT, B.; ARORA, A.; ABDELAZIZ, M.; DUIGOU, M.; HAYWOOD, C.; HUGLY, J.; POUYOUL, E.; YEAGER, B., 2003]. 36 Figura 15 - XML Schema definindo os elementos necessários para o envio de Advertisements, contendo informações de rota para um determinado peer. <DstPID> Deve conter o Peer ID do peer que as informações de rota estão sendo descritas. <APA> Contém uma lista de endereço associados com o peer informado. <Hops> Contém uma coleção de Advertisements descrevendo uma rota para o peer indicado em <DstPID> 37 Protocolos de Serviços Padrão (opcional) Protocolo Peer Discovery Protocolo Pipe Binding Protocolo Peer Information Protocolo Peer Resolver Protocolo Rendezvous Protocolos Core (obrigatório) Protocolo Endpoint Routing Figura 16 - Protocolos opcionais e obrigatórios definidos na tecnologia JXTA. Serviço PeerGroup Serviço Discovery Serviço Pipe Serviço Resolver Serviço Membership SRDI Serviço Rendezvous Serviço Peer Info RPV Walker Serviço Endpoint Mensageiro Virtual Advertisements XML Parser Mensagem ID Gerente de Cache Index Relay Transporte HTTP Transporte TCP/IP Router Transporte TLS Figura 17 - Referência de Implementação JXTA na plataforma Java 2 Standard Edition. 38 4. JXTA SHELL Uma aplicação SHELL permite a digitação e execução de comandos em forma de textos, exibindo o resultado da execução dos comandos para o usuário. Uma das principais aplicações oferecidas para plataforma JXTA atualmente é o JXTA shell. O JXTA shell, é um ambiente que através de comandos simples permite explorar a rede, adicionando peers, peersgroups e enviar qualquer tipo de advertisements, sem a necessidade da utilização de uma linguagem de programação [KRISHNAN, N., 2003]. Para aqueles que já conhecem o básico do shell de qualquer sistema operacional do tipo UNIX like (UNIX, LINUX, e derivados), encontramos diversas semelhanças neste aplicativo, além de muitos comandos com a mesma funcionalidade, como mostramos a seguir. Para instalar o JXTA Shell, basta realizar o download dos arquivos necessários em http://download.jxta.org/easyinstall/install.html. A instalação é simples, bastando seguir as instruções disponibilizadas na página de download. Além do JXTA shell, a instalação básica disponibiliza uma aplicação chamada InstantP2P, na qual podemos trocar mensagens instantâneas entre peers, realizar sessões de chat, compartilhar e pesquisar arquivos compartilhados pelos peers na rede. Tanto o JXTA shell como o InstantP2P são aplicações codificadas em Java. Diversas API´s (Application Program Interface) são disponibilizadas, e tarefas como publicação de advertisements, compartilhamento de arquivos e comunicação entre peers podem ser implementadas para construção de novos aplicativos. 39 4.1 CONFIGURAÇÃO INICIAL JXTA SHELL Depois de realizada a instalação, deve-se realizar as configurações básicas e de segurança de ambas as aplicações. Todas as informações relativas às configurações da aplicação, bem como o cache de informações da rede realizado, é armazenado no diretório de instalação escolhido para aplicação. Depois de instalado, basta iniciar o shell pelo arquivo shell.bat, disponibilizado dentro da pasta shell contida no diretório escolhido para instalação. Caso o sistema operacional utilizado seja o Microsoft Windows, uma pasta no menu iniciar estará disponível, contendo os atalhos correspondentes a cada aplicação. Ao acessar pela primeira vez ambas aplicações, acessaremos automaticamente as telas de configuração da rede. Nessa tela (Figura 18) podemos verificar quatro botões correspondentes aos tipos de configuração. Para configuração utilização inicial siga os passos abaixo [KRISHNAN, N., 2003], [SUN MICROSYSTEMS, INC., 2001], [OAKS, S.; TRAVERSAT, B.; GONG, Li.]: 1 - Clique no botão nomeado "basic" e preecha a configuração básica, informando o nome que será identificado o seu peer na rede. Caso sua conexão seja feita por um servidor proxy é necessário informar o endereço utilizado. 40 Figura 18 - Escolhendo o nome do peer que será identificado na rede JXTA. 2 - Clique no último botão nomeado "security". Escolha um nome de usuário e uma senha, que serão utilizadas posteriormente para acesso ao shell e a rede JXTA. Essa será a identificação de seu peer na rede. Figura 19 - Escolhendo o nome de usuário e senha, dados que são necessários a cada vez que o shell é iniciado. 41 3 – Clique no botão nomeado rendezvous/relays. Clique no botão “download relay and rendezvous lists”. Marque a opção “use a relay”. Figura 20 - Recuperando os peers que serão utilizados como relay e rendezvous. Depois de realizada a configuração, o shell estará pronto para ser utilizado. Ao visualizar o prompt "JXTA>", podemos digitar qualquer comando válido, que o mesmo será executado e sua resposta, caso disponível, será exibida na tela. 42 Figura 21 - Tela inicial do JXTA shell. 4.2 COMANDOS JXTA SHELL Atualmente estão implementados mais de 40 comandos no JXTA Shell [KRISHNAN, N., 2003], [SUN MICROSYSTEMS, INC., 2001]. A seguir explicaremos os principais comandos aproveitando para conhecer a rede JXTA e visualizar alguns conceitos anteriormente explicados. 4.2.1 MAN Lista todos os comandos disponíveis para serem utilizados. Similar ao comando man do UNIX. Pode ser utilizado para obter ajuda sobre um comando específico. Ex: man cat 43 4.2.2 PEERCONFIG Inicia a tela de configuração do Shell novamente na próxima execução do programa. 4.2.3 RDVSTATUS Indica quais são os peers do tipo rendezvous que estamos conectados. Precisamos estar conectados pelo menos em um rendezvous peer para conhecer o restante da rede. 4.2.4 ENV Lista todas as variáveis usados pelo shell. Por padrão são definidas sete variáveis. 4.2.5 CAT Exibe o conteúdo de uma variável definida pelo shell. Similar ao comando cat utilizado no UNIX. Esta é a forma básica de exibir o conteúdo de variáveis e objetos criados no shell. 4.2.6 GREP Procura uma string específica em uma variável. Similar ao comando grep do UNIX. 44 4.2.7 HISTORY Lista o histórico de comandos digitados anteriormente 4.2.8 VERSION Indica a versão atual do shell. 4.2.9 EXIT Encerra a sessão atual do shell. 4.2.10 GROUPS Lista todos os grupos que o shell tem conhecimento em seu cache. Para procurar novos groups na rede devemos enviar o comando groups –r. Para atualizar as informações mantidas no cache, devemos enviar o comando groups –f. Para listar as informações dos grupos conhecidos, podemos utilizar a opção –l 45 Figura 22 - Depois de executado o comando groups -r para a descoberta de novos grupos, exibimos os grupos encontrados com o comando groups. 4.2.11 PEERS Lista todos os peers que o shell tem conhecimento em seu cache. Da mesma forma que o comando anterior, podemos descobrir novos peers com o comando peers –r, e atualizar as informações armazenadas em cache com o comando peers –f. Para listar as informações dos peers conhecidos devemos utilizar a opção –l. 46 Figura 23 - Resultado da execução do comando peers. 4.2.12 WHOAMI Indica as informações do seu peer, exibindo os endereços TCP e HTTP utilizados além dos identificadores(UUID) atribuídos ao peer. Utilizado com a opção –g informa em qual grupo o peer pertence. Figura 24 - Resultado da exibição do comando whoami e whoami –g executados no JXTA shell. 4.3 CRIANDO UM GRUPO NA REDE JXTA Para criar um grupo na rede JXTA, precisamos primeiramente criar o Advertisement correspondente, e depois publicá-lo para os outros componentes da rede. Segue abaixo um 47 exemplo da criação do Advertisement para grupo com o comando mkadv [KRISHNAN, N., 2003], [SUN MICROSYSTEMS, INC., 2001], [OAKS, S.; TRAVERSAT, B.; GONG, Li]. JXTA> grupoAdv=mkadv –g grupoteste Para visualizar o conteúdo do advertisement criado podemos exibir o conteúdo da variável grupoAdv criada com o comando abaixo: JXTA> cat grupoAdv Figura 25 - Ao exibir o advertisement criado, podemos verificar os identificadores atribuídos para a mensagem (<MSID>) e para o grupo (<GID>). Basta agora criarmos o grupo associando o advertisement a ser publicado com o comando mkpgrp JXTA> mkpgrp –d grupoAdv Com o grupo criado podemos visualiza-lo após enviar o comando groups –r e posteriormente groups: JXTA> groups –r JXTA> groups Figura 26 - Resultado da criação do grupo definido anteriormente, sendo listado após a execução do comando groups. 48 Por default todos os peers pertencem ao NetPeerGroup, que é o grupo no topo da hierarquia JXTA. Cada peer pode juntar-se a qualquer grupo JXTA existente na rede desde que possua permissão para integrar o mesmo. Em nosso caso nenhuma forma de autenticação foi especificada. Para fazer parte do grupo criado anteriormente usaremos o comando join: JXTA> join grupoteste Como somos o criador do grupo, podemos especificar o nome dele diretamente no comando join. Para ingressar outros grupos devemos enviar o comando na seguinte forma: JXTA> join –d group1 Ao listarmos os grupos com o comando groups os mesmos serão exibidos inicialmente com o nome seqüencial group1,group2 e assim por diante. Para ingressarmos no grupo remoto, basta informar o “indíce” atribuído para o grupo. No caso acima estamos acessando o primeiro grupo listado. Para deixarmos o grupo basta executar o comando leave. Figura 27 - Por padrão todos os peers pertencem ao NetPeerGroup, como pode ser verificado pela exibição do comando whoami -g ao iniciar o JXTA shell. Após requisitar a entrada no grupo 2, executamos novamente whoami -g, que exibe as informações do grupo atual. 49 4.4 CONVERSANDO NA REDE JXTA Através do comando talk é possível o envio de mensagens instantâneas para os peers conectados na rede JXTA. Basicamente podemos enviar mensagens com ou sem segurança, isto é, podemos enviar mensagens criptografadas aumentando a privacidade e a segurança da comunicação [KRISHNAN, N., 2003], [OAKS, S.; TRAVERSAT, B.; GONG, Li]. Primeiramente precisamos iniciar o comando talk fornecendo um nick: JXTA> talk –register meunick O comando acima basicamente encapsula a criação de um advertisement para os pipes que serão responsáveis pelo envio e recebimento de mensagens. Depois de registrado no serviço talk e escolhido um nick precisamos efetuar o login para iniciar a conversação: JXTA> talk –login meunick Após o login qualquer mensagem enviada por um peer remoto será exibida no console. O comando de login inicia o pipe de entrada, disponibilizando uma thread para verificar a chegada de conteúdo, permitindo a exibição das mensagens recebidas instantaneamente. Para procurar outros peers disponíveis para conversação, podemos utilizar o comando talk-search. Abaixo segue um exemplo para o envio de uma mensagem para você mesmo: JXTA> talk –u meunick meunick 50 Após executar o comando acima basta digitar a mensagem e terminá-la com um ponto final “.”. O comando talk facilita a comunicação na rede evitando a necessidade da criação de advertisements e outros objetos que permitem a comunicação. Caso seja necessário podemos criar os advertisements, pipes e enviar mensagens para os peers com os comandos disponíveis no Shell [KRISHNAN, N., 2003], [OAKS, S.; TRAVERSAT, B.; GONG, Li]. Figura 28 - Exemplo de dois peers (Peer1 e Peer2) conversando na rede JXTA com o comando talk. 51 4.5 CACHING DE ADVERTISEMENTS Na rede JXTA peers são descobertos freqüentemente, porém não podemos garantir que sua conexão está disponível em um outro momento. Esses peers são transientes, e é por isso que as redes P2P são chamadas de redes não confiáveis [KRISHNAN, N., 2003]. Todos as informações e advertisements descobertos pelo shell ficam armazenadas no diretório ./cm, dentro da pasta escolhida para a instalação do JXTA. A cada reinício o shell recupera as informações obtidas anteriormente. Muitas dessas informações armazenadas estarão desatualizadas e em muitos casos inválidas. Para atualizar as informações armazenadas em cache, os comandos peers e groups aceitam um argumento –f, realizando uma atualização (flush) das informações quando solicitado. Essa técnica de cache é fundamental para diminuir o tráfego de mensagens redundantes na rede. Para evitar que os advertisements fiquem armazenados por um longo período no cache das aplicações, um TTL(Time To Live) é especificado junto com o seu envio, definindo assim o tempo de vida de cada recurso criado na rede JXTA. Essa característica é fundamental para a auto-suficiência e atualização da rede sem um controle centralizado [OAKS, S.; TRAVERSAT, B.; GONG, Li.]. 52 O cache de advertisements, apesar de padrão nas API’s de binding JXTA, não é obrigatório e nem padronizado. Cada aplicação escolhe a melhor forma de realizá-lo de acordo com seus recursos disponíveis [OAKS, S.; TRAVERSAT, B.; GONG, Li]. Figura 29 - Caching de advertisements realizado pela aplicação JXTA Shell. Ao executar qualquer aplicação JXTA, um diretório “\.jxta\cm\“ será criado automaticamente no diretório em que a aplicação está sendo executada. Nesta figura podemos observar os diversos tipos de advertisements (PeerGroups, Peers, Messages) armazenados após a primeira execução da aplicação. Ao abrir um dos arquivos em um editor de texto, podemos verificar o conteúdo XML dos advertisements. 4.6 A IMPORTÂNCIA DOS PIPES A descentralização e a natural distribuição dos peers na rede JXTA, torna-se um desafio para a realização de uma comunicação e transferência de dados efetiva. Cada peer poderá juntar-se a rede em apenas alguns momentos, e ainda assim sua conexão poderá ser transiente, além de ser realizada em redes que utilizam protocolos diferentes. O principal objetivo para os desenvolvedores de soluções P2P, é garantir o sucesso na comunicação dos peers independente da forma de conexão e do protocolo de rede utilizado. Além disso, os peers podem estar conectados a rede através de um NAT, ou sofrendo restrições na transmissão de dados por um firewall. Uma das principais soluções adotadas por JXTA para enfrentar essas dificuldades são a utilização de pipes [OAKS, S.; TRAVERSAT, B.; GONG, Li]. Para realizar a comunicação entre dois peers em uma rede transiente, heterogênea e com as dificuldades listadas anteriormente, precisamos realizar várias conexões 53 intermediárias, e utilizar os atalhos e peers roteadores participantes da rede. Por esse motivo, as conexões realizadas por pipes são comumente referidas como conexões virtuais ou lógicas [OAKS, S.; TRAVERSAT, B.; GONG, Li]. Essa é uma importante abstração que permite a efetividade da comunicação e transmissão de dados entre os peers. A forma como é realizada a comunicação entre pipes, permite que as aplicações se adaptem com as constantes falhas da rede, requisito fundamental para redes P2P. Uma das principais características dos pipes é a transparência de rede que eles permitem para o desenvolvedor de aplicativos. Para realizar a comunicação entre dois pipes, precisamos apenas de sua identificação na rede JXTA, e todos os processos intermediários necessários serão executados sempre escolhendo as melhores alternativas e soluções. Em uma rede local, por exemplo, a melhor forma de se estabelecer comunicação entre dois peers pode ser utilizando TCP/IP. Esta solução talvez não seja válida para peers que precisam se comunicar através de um firewall ou pertençam a redes diferentes, e conseqüentemente utilizarão HTTP para efetuar a transmissão de dados [OAKS, S.; TRAVERSAT, B.; GONG, Li]. A abstração na forma como é realizada a comunicação entre peers, permitem aos pipes a utilização dos protocolos TCP/IP e HTTP para a transmissão de dados, de uma forma transparente para o desenvolvedor de aplicações. A utilização do protocolo HTTP ocorre quando é necessária a comunicação de peers pertencentes a redes distintas, ou quando um dos peers tem restrições impostas pela rede utilizada, como por exemplo, um firewall. A comunicação básica entre pipes é unidirecional e assíncrona, e não há garantia de que a mensagem será enviada. Porém outros tipos de conexão estão disponíveis e podem ser utilizadas [OAKS, S.; TRAVERSAT, B.; GONG, Li]: · Síncrona request/response: Após o envio de uma mensagem uma resposta é enviada pelo receptor. 54 · Publish/Subscribe: Um pipe do tipo EndPoint registra-se como ouvinte (Subscribe) para as mensagens enviadas por um publicador(Publish). · Bulk data transfer: Uma conexão confiável para a transferência de dados binários. · Streaming: Realiza uma transferência eficiente de dados através de um canal com controle de fluxo. Figura 30 - Tipos de pipes que podem ser utilizados para comunicação entre peers. 55 5. ESTUDO DE CASO: CHAT P2P DESCENTRALIZADO 5.1 CHAT CLIENTE/SERVIDOR X CHAT P2P Chats são aplicações que permitem a troca de mensagens de texto entre uma ou mais pessoas, e são comumente encontradas em diversos sites da web. A maioria das salas de chat necessitam de um servidor central para que os clientes possam se conectar e receber novas mensagens. Ao estabelecer uma conexão com esse servidor central, qualquer nova mensagem disponível será enviada para o usuário, que recebe todas as mensagens enviada pelos outros participantes da sala. Toda e qualquer comunicação realizada entre os peers nesta arquitetura tem que necessariamente passar por este servidor centralizado, que encarrega-se de enviar a mensagem até o seu correto destino. Essa arquitetura, apesar de suas peculiaridades, é tipicamente cliente/servidor, e o seu funcionamento é ideal em muitos casos. Os benefícios oferecidos por uma aplicação cliente/servidor são diversos, porém muitas desvantagens encontradas nesta arquitetura são cruciais para outros tipos de aplicação. O que aconteceria com nossa aplicação de chat se houvesse uma falha neste servidor centralizado, ou até mesmo na infra-estrutura que conecta o servidor com os diversos clientes? Quantos clientes simultâneos essa arquitetura é capaz de suportar? Qual o custo para manter esta aplicação o mais redundante e confiável possível? Mesmo com os avanços das tecnologias para aplicações de missão crítica qualquer indisponibilidade neste servidor significa a perda da conexão de muitos usuários, e em muitos casos os custos envolvidos para 56 manter uma alta disponibilidade podem inviabilizar o projeto. No caso de uma aplicação de chat, geralmente com o objetivo de puro entretenimento, esta talvez não seja uma questão primordial, porém para aplicações de leilões on-line e negociação em tempo real esta é uma questão crucial. A arquitetura utilizada para a colaboração e publicação de informações nestas aplicações é basicamente a mesma utilizada por um chat, logicamente com inúmeras especificidades que estão além do escopo de nossa aplicação case. Uma alternativa para o atual modelo cliente/servidor é a comunicação totalmente P2P entre os participantes. A comunicação neste caso muda radicalmente e passa a ser totalmente descentralizada. Este modelo de comunicação oferece algumas vantagens, como por exemplo, uma maior tolerância à falhas. Qualquer peer que tenha problemas na sua conexão com a rede, não prejudicará os peers restantes, não comprometendo o funcionamento total da aplicação. Em nossa aplicação, temos ainda a vantagem oferecida por JXTA de comunicar transparentemente dispositivos pertencentes a redes diferentes, sem nos preocupar qual o protocolo utilizado, ou qual a melhor rota para realizar a conexão entre eles. Esta transparência é uma grande funcionalidade oferecida pela tecnologia, e a adição de novas API´s para outras linguagens, além do Java, contribuirão muito para o crescimento da rede e o aperfeiçoamento do JXTA. A principal desvantagem na utilização de uma arquitetura totalmente P2P para uma aplicação de chat é a quantidade de banda utilizada pelos peers para realizar a comunicação com todos os outros participantes da rede quando necessário. No caso de enviarmos uma mensagem para todos os integrantes de uma sala ocupada por 40 usuários, serão necessárias 39 conexões, sendo uma conexão aberta para cada usuário pertencente à sala com exceção do próprio usuário, e a mesma mensagem será enviada repetidamente para cada usuário. 57 Figura 31 - Chat utilizando arquitetura P2P. Em uma sala contendo N peers serão necessárias N-1 conexões para enviar a mesma mensagem para todos os participantes da rede. Neste caso específico, o consumo de banda entre os peers será maior, porém não precisamos de um servidor central replicando as mensagens, o que limita o número de usuários simultaneamente conectados. Figura 32 - Chat utilizando arquitetura Cliente x Servidor. Para cada cliente, a conexão é estabelecida apenas uma vez com o servidor, que replica as mensagens entre os outros usuários conectados. O consumo de banda no servidor e a quantidade de recursos necessários aumentam proporcionalmente ao número de usuários conectados. Para os peers, o consumo de banda e recursos necessários para utilizar a aplicação são mínimos, porém qualquer falha no servidor compromete o funcionamento de todos os clientes. 5.2 ARQUITETURA HÍBRIDA CLIENTE/SERVIDOR E P2P Uma alternativa para minimizar os impactos negativos, tanto da arquitetura P2P quanto da arquitetura cliente/servidor, é a utilização de uma arquitetura híbrida, isto é, uma arquitetura que utilize os modelos cliente/servidor e P2P, aproveitando as vantagens oferecidas por cada modelo. A grande diferença desse modelo para a aplicação aqui apresentada, é no envio de mensagens para todos os usuários de uma sala. Como visto anteriormente, para replicar uma mensagem enviada para todos os participantes da sala, é necessário que se abra uma conexão para cada peer individualmente, enviando a mesma mensagem para cada um deles repetidamente. 58 Utilizando uma arquitetura híbrida, poderíamos manter esta funcionalidade, aproveitando as vantagens oferecidas pelo modelo cliente/servidor. Neste caso elegemos um ou mais peers na rede JXTA para exercer a funcionalidade de um servidor, e seria de responsabilidade deste peer replicar as mensagens para todos os participantes do chat. A única restrição para essa escolha, é que este peer possa se comunicar com os demais sem nenhuma restrição. Esse peer poderia ser escolhido segundo determinados critérios de recursos, como por exemplo, o peer com a melhor conexão em termos de velocidade de rede ou poder de processamento. Caso um peer deseje enviar uma mensagem exclusivamente para outro peer, ou mesmo para poucos peers, este poderia realizar a conexão diretamente, sem a necessidade de enviar esta mensagem para o nosso servidor. Sendo assim, os recursos de banda também seriam otimizados em comparação ao modelo cliente/servidor, pois utilizando uma arquitetura híbrida, somente as mensagens destinadas a todos os usuários da sala passariam pelo controle centralizado. Figura 33 - Chat utilizando arquitetura híbrida P2P e cliente/servidor. A comunicação direta entre os peers é freqüentemente utilizada, sendo o servidor necessário apenas quando uma mensagem para todos os peers é enviada. Dessa forma utilizamos o melhor fornecido por cada arquitetura. Este capítulo demonstra como foi desenvolvida uma aplicação de chat totalmente P2P, utilizando as API´s JXTA existentes para java. Os códigos fontes desta aplicação encontram-se documentados no apêndice A, e os arquivos, compilados e pronto para serem executados, podem ser obtidos no site http://www34.brinkster.com/mackjxta, juntamente com as bibliotecas necessárias para execução do programa. 59 Para executar a aplicação é necessário ter instalado na máquina alguma versão recente do JRE (Java Runtime Enviroment), que pode ser obtida gratuitamente no site http://www.java.sun.com. A aplicação de chat desenvolvida neste estudo tem como objetivo demonstrar os recursos da plataforma JXTA, além das principais API`s java utilizadas para construção de aplicativos P2P. O funcionamento da aplicação é baseado no envio de mensagens simples de texto para todos os participantes do chat, é contém uma área que possibilita a exibição das novas mensagens enviadas. A arquitetura de comunicação utilizada é P2P, totalmente descentralizada, sem a necessidade de um servidor central que replique as mensagens para todos os participantes do chat. Qualquer novo usuário que realizar o login na aplicação de chat, terá sua entrada notificada para os outros participantes através da publicação de um advertisement, definido especificamente para esta aplicação. A descoberta de novos usuários, bem como a verificação se todos os participantes do chat ainda estão disponíveis, é feita periodicamente por cada programa cliente. O envio de mensagens só é possível para todos os participantes do chat, não sendo possível o envio de mensagens reservadas nem direcionadas apenas para um usuário. 5.3 EXECUTANDO A APLICAÇÃO Depois de instalado e configurado o JRE devidamente, basta descompactar o arquivo .zip disponibilizado em qualquer diretório. Para executar a aplicação, execute o arquivo chat.bat, localizado na raiz do diretório onde os arquivos foram descompactados. 60 5.4 CONFIGURANDO O AMBIENTE JXTA Ao acessar a aplicação pela primeira vez, a configuração básica para acesso a rede JXTA será requisitada. Verifique as configurações realizadas na secção “Configuração Inicial JXTA Shell” no capítulo JXTA shell. 5.5 ANALISANDO O CÓDIGO FONTE A aplicação é construída pela compilação das seguintes classes Java: Tabela 1 – Classes utilizadas para implementação da aplicação de chat. Figura 34 – Diagrama UML de classes para a aplicação de chat. Figura 35 – Diagrama de sequência para as classes Java da aplicação de chat. Outros dois arquivos, chat.log e logo.jpg, também compõe a aplicação, porém não contém nenhum código Java , e são apenas arquivos auxiliares para o funcionamento do chat. 61 O arquivo chat.log pode ser analisado para detectar eventuais erros da aplicação, bem como o resultado de cada ação realizada. As classes chat.ChatLoginFrame e chat.ChatFrame realizam apenas tarefas simples, como a escolha do apelido (nick) utilizado, e a exibição de mensagens para o usuário. Figura 36 - Tela de boas-vindas do Chat Figura 37 - Tela de conversas do Chat (Peer1) Figura 38 - Tela de conversas do Chat (Peer2) 5.6 CLASSE CHAT.CHATAPP.JAVA Ao executar o método main desta classe, instanciaremos um objeto representando ela própria, e executaremos o método startJxta(), dando início a rede JXTA. 10 20 public static void main(String args[]){ ChatApp chat=new ChatApp(); 62 30 40 chat.startJxta(); } Exemplo 1 – Após executar o construtor da aplicação, a plataforma JXTA é iniciada. O método startJxta() tem como principal objetivo inicializar o peer atual na rede JXTA. Todos os peers, por padrão, pertecem ao World Peer Group, que é o primeiro grupo da rede JXTA, e pai de todos os outros grupos. O World Peer Group oferece alguns serviços básicos, como por exemplo a descoberta de novos peers, e outras funcionalidades simples. Depois de iniciado os serviços básicos da rede JXTA, nosso peer irá se integrar ao Net Peer Grupo, um grupo especial que oferece serviços e funcionalidades adicionais ao World Peer Group, como por exemplo, o monitoramento de serviços, definições de credenciais e conhecimento de gateways específicos. O principal motivo para a separação do Net Peer Group do World Peer Group, deve-se ao fato de JXTA não fazer nenhuma imposição aos requisitos mínimos do peers participantes da rede. Caso os recursos utilizados por um determinado peer sejam compatíveis com Net Peer Group, este poderá instancia-lo sem restrições, e caso contrário, poderá apenas usufruir dos serviços básicos oferecidos pelo World Peer Group. Após ingressar no Net Peer Group, utilizaremos os métodos getDiscoveryService() e getPipeService() para obter os serviços de Discovery e Pipe, respectivamente. 10 20 30 40 50 60 70 try{ group=PeerGroupFactory.newNetPeerGroup(); }catch(Exception e){ e.printStackTrace(); } discovery=group.getDiscoveryService(); pipeSvc=group.getPipeService(); Exemplo 2 – Depois de iniciado o Net Peer Group, os serviços de Pipe e Discovery são recuperados. 63 A interface DiscoveryService especifica diversos métodos para recuperação, publicação e descoberta de advertisements , implementados pela classe DiscoveryServiceImpl. Publicar advertisements é uma das principais tarefas de qualquer aplicação na rede JXTA, pois é desta maneira que são feitas as descobertas de peers, pipes e outros recursos. Após recuperado os serviços de discovery e pipes, e caso não nenhum erro seja encontrado, instanciaremos a classe chat.ChatLoginFrame, permitindo ao usuário escolher o nick a ser utilizado, e dando início a aplicação. O método responsável por realizar o login deste usuário no chat, é o método public int loginChat(String name). A primeira ação realizada por este método, é verificar se o login na aplicação de chat ainda não foi realizado, alertando o usuário de que não será possível entrar na rede novamente caso o login já tenha sido escolhido. Com o serviço de discovery recuperado corretamente, registraremos a própria classe chat.ChatApp como ouvinte para os eventos de discovery recebidos. 10 20 30 40 if(!loggedIn){ this.nick=name; discovery.addDiscoveryListener(this); } Exemplo 3 - Caso o apelido escolhido esteja disponível, registramos a classe atual como listenet dos eventos recebidos de Discovery recebidos pela aplicação. Para que a classe possa receber eventos de discovery, é necessário que o método public void discoveryEvent(DiscoveryEvent ev) seja implementado, fornecendo as ações que o programa deve realizar ao receber um evento. Nesta aplicação, este método apenas informa o recebimento de um evento, sem qualquer ação específica que envolva a lógica da aplicação. 64 Em seguida procuramos um advertisement localmente para o nick informado. A distinção dos advertisements que pertencem a nossa aplicação é feita pela recuperação do valor contido no elemento <Name> do xml correspondente ao advertisement de pipes encontrados. Todo advertisement enviado pela aplicação de chat, conterá o prefixo que foi definido na constante CHAT_NAME_TAG, além do nick escolhido pelo usuário no início da aplicação: 10 public static final String CHAT_NAME_TAG="ChatMack"; Exemplo 4 – Constante definindo o elemento a ser anexado nos advertisements publicados pela aplcação na rede JXTA, permitindo a identificação futura pelos outros clientes do chat. Caso já exista um advertisement armazenado localmente no cache da aplicação, informaremos que já existe um outro usuário com este mesmo nick participando do chat, e solicitamos a escolha de outro nick para o usuário atual. Não existindo um outro usuário com o mesmo nick na rede JXTA para a aplicação de chat, criamos um novo advertisement para o pipe de entrada, que será utilizado para o recebimento de mensagens, e logo em seguida, realizamos a publicação deste advertisement para os outros peers, alertando a presença deste novo usuário: 10 20 30 40 50 60 70 80 90 100 110 120 130 140 try{ //criando um adv de pipe para este user... adv = (PipeAdvertisement) _ AdvertisementFactory.newAdvertisement _ (PipeAdvertisement.getAdvertisementType()); adv.setPipeID(IDFactory.newPipeID _ (group.getPeerGroupID())); adv.setName(CHAT_NAME_TAG+":"+name); adv.setType(PipeService.PropagateType); }catch(Exception e){ e.printStackTrace(); return -1; } 65 Exemplo 5 - Criação do advertisement para o Pipe que receberá as mensagens do chat. 10 20 30 40 50 60 70 80 90 try{ discovery.publish(adv,DiscoveryService.ADV, _ ADV_LIFETIME,ADV_LIFETIME); discovery.remotePublish(adv,DiscoveryService.ADV, _ ADV_LIFETIME); }catch(Exception e){ e.printStackTrace(); return -1; } Exemplo 6 - Publicação do advertisement de Pipe na rede JXTA. O método private void createInputPipe() é responsável pela criação do pipe de entrada. A partir deste momento qualquer mensagem enviada para este pipe será recebida pelo método public void pipeMsgEvent(PipeMsgEvent pipeMsgEvent): 10 20 30 40 50 60 70 try{ pipeIn=pipeSvc.createInputPipe(userAdv,this); }catch(Exception e){ System.out.println("Erro ao criar _ inputPipe:"+e.getMessage()); return; } Exemplo 7 - Criação do Pipe de entrada que recebe as mensagens enviadas no chat. O parâmetro “this” informado no método createInputPipe, especifica qual classe deve implementar o método de recebimento de eventos de pipe. Nesta aplicação a própria classe chat.ChatApp fornece a implementação, como veremos a seguir: 10 20 30 40 public void discoveryEvent(DiscoveryEvent ev){ DiscoveryResponseMsg res=ev.getResponse(); String name="Unknown"; PeerAdvertisement peerAdv=res.getPeerAdvertisement(); Exemplo 8 - Implementação do método responsável por tratar os eventos de Discovery recebidos. Depois de recuperado o evento recebido, extraímos o remetente e a mensagem enviada por ele, definidas pelos valores contidos nas constantes private static final String SENDER_NAME="ChatSenderName" e private static final String 66 MESSAGE_TAG="ChatSenderMessage", respectivamente. Com a mensagem e o remetente recuperados, executamos o método chatFrame.printMessage(msg,from) da classe chat.ChatFrame, responsável pela exibição formatada da mensagem na tela. O método public void sendMessageToAll(String texto) é responsável pelo envio de mensagens para o chat. A cada mensagem enviada por este usuário, precisamos recuperar todos os advertisements de pipes armazenados no cache local de nossa aplicação, criar um pipe de saída para cada pipe encontrado, e enviar a mensagem, repetidamente para cada peer. O método private Collection getAllPipeLocalAdvertisements() é o responsável por recuperar os advertisements armazenados localmente pela aplicação: 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 private Collection getAllPipeLocalAdvertisements(){ Collection pipes=new ArrayList(); try{ Enumeration enum=discovery.getLocalAdvertisements( _ DiscoveryService.ADV, "Name","*"+CHAT_NAME_TAG+":*"); if(enum!=null){ while(enum.hasMoreElements()){ try{ PipeAdvertisement _ adv=(PipeAdvertisement)_ enum.nextElement(); pipes.add(adv); }catch(Exception e){ continue; } } } }catch(Exception e){ e.printStackTrace(); } return pipes; } Exemplo 9 - Recuperação dos Advertisements armazenados em cache pela aplicação. Ao criar um pipe de saída para cada advertisement recuperado, estabelecemos um timeout de 100 ms para realizar a conexão. Se o peer responsável pela publicação do pipe não 67 puder ser contato, ignoramos este advertisement e repetimos o mesmo processo para os restantes encontrados. 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 public void sendMessageToAll(String texto){ Collection pipes=getAllPipeLocalAdvertisements(); if(pipes!=null){ Iterator it=pipes.iterator(); while(it.hasNext()){ PipeAdvertisement adv=(PipeAdvertisement) _ it.next(); OutputPipe pipeOut=null; try{ pipeOut=pipeSvc.createOutputPipe(adv,100); }catch(Exception e){ System.out.println("\nErro ao Criar _ pipeOut para "+adv.getName()); } if(pipeOut!=null){ Message msg=null; String userInput=null; InputStream inputStream=null; try{ msg=pipeSvc.createMessage(); //inputStream = new _ ByteArrayInputStream() StringMessageElement sme=new _ StringMessageElement(SENDER_NAME,_ nick,null); StringMessageElement sme2=new _ StringMessageElement(MESSAGE_TAG,_ texto,null); msg.replaceMessageElement(sme); msg.replaceMessageElement(sme2); pipeOut.send(msg); }catch(Exception e){ System.out.println("Erro ao enviar_ conteudo para pipeOut:" _ +e.getMessage()); } } } } } Exemplo 10 - Envio da mensagem para cada pipe recuperado através dos advertisements armazenados no cache da aplicação. 68 6. CONCLUSÃO A necessidade de um tipo de computação descentralizada, mais colaborativa, transiente e adaptativa aumenta à medida que surgem novos dispositivos e plataformas. Com a popularização dos dispositivos móveis, como os Palm Tops, Hand Helds e celulares de última geração, torna-se clara a necessidade de comunicação entre dispositivos pertencentes a redes diferentes e plataformas distintas. A iniciativa do projeto JXTA, com o objetivo de especificar protocolos independentes de plataforma, dispositivo ou linguagem de programação, torna-se fundamental para a construção de novas aplicações P2P, além da possibilidade de integrar, sem grandes dificuldades, as novas aplicações que serão construídas seguindo as futuras especificações a serem definidas em JXTA. Outro fator fundamental para o sucesso futuro do projeto, é o fato dele não ser proprietário, apesar de ter sido iniciado e ainda incentivado pela Sun Microsystem. Atualmente o projeto JXTA é mantido sob uma variação da Apache Software License, o que garante a continuidade do projeto independente de qualquer empresa, além da contribuição constante da comunidade open-source, e a transparência de como o desenvolvimento da tecnologia é conduzido. Muitas dificuldades e problemas ainda precisam ser resolvidos. O consumo excessivo de banda para realização de buscas em redes P2P, utilizando técnicas como flooding, precisa 69 ser melhorado. A falta de implementações em outras linguagens além do java, ainda torna restrito o uso da tecnologia, fato que deve ser resolvido em breve com novas implementações. A versão JXTA 2.1.1, sendo a mais recente lançada até o momento, traz diversas otimizações em relação à primeira versão, como a possibilidade da utilização de sockets, similares aos disponíveis na versão J2SE, além da criação de pipes bidirecionais, otimizando a troca de mensagens entre peers. Muitas outras otimizações relativas aos recursos de rede utilizados foram adicionadas, e diversas API´s foram alteradas para simplificar o desenvolvimento e aperfeiçoar as já existentes. A cada versão disponibilizada, torna-se fundamental a participação da comunidade envolvida no projeto, que através de listas de discussões, identifica os pontos falhos e analisa novas necessidades para que em um futuro breve, esta tecnologia possa ser utilizada em larga escala pela indústria com sucesso. Diversos sub-projetos estão sendo desenvolvidos paralelamente ao projeto JXTA, disponibilizando soluções e alternativas importantes para a indústria de tecnologia. Entre esses sub-projetos, podemos destacar o vop2p (Voice Over Peer to Peer), disponível em http://vop2p.jxta.org/servlets/ProjectHome, que tem como objetivo a possibilidade de criação de uma rede telefônica descentralizada para comunicação entre peers. Além do vop2p, outros projetos merecem destaque, como o gamePlataform (Plataforma para jogos on-line possibilitando vários participantes), disponível em http://gameplatform.jxta.org/servlets/ProjectHome, e o p2pConference, disponível em http://p2pconference.jxta.org/servlets/ProjectHome, que permite a criação de conferências virtuais sobre a plataforma JXTA. Outros sub-projetos estão sendo adicionados mensalmente ao projeto JXTA, e o amadurecimento e a estabilidade das próximas versões da plataforma, devem favorecer o surgimento de aplicações realmente inovadoras para o setor de tecnologia. 70 Apesar das dificuldades existentes, o desenvolvimento e amadurecimento para construção de redes P2P vêm sendo notado a cada ano, bastando observar o sucesso na utilização de aplicativos compartilhadores de arquivos e de troca de mensagens instantâneas. A adoção de aplicações P2P por empresas privadas deve popularizar a tecnologia, e conseqüentemente disponibilizar e capacitar mão de obra para o desenvolvimento de novas aplicações P2P em JXTA. Mesmo com poucos anos de desenvolvimento, a implementação para linguagem java da plataforma JXTA ,mostra-se bastante avançada, permitindo a construção de aplicações P2P sem grandes dificuldades e com resultados satisfatórios. Porém, a melhora da documentação, sendo traduzida em outras linguagens além do inglês, além da publicação de novos livros e artigos sobre o assunto, será fundamental para a adoção desta tecnologia por diversos arquitetos de soluções P2P e pelas empresas de tecnologia. A aplicação de chat desenvolvida neste trabalho, pode servir de ponto de partida para os interessados nas API´s java para desenvolvimento de aplicação P2P utilizando a plataforma JXTA, além de permitir o entendimento de vários sub-projetos e códigos disponibilizados no site oficial do projeto. 71 REFERÊNCIAS BIBLIOGRÁFICAS [1] TRUELOVE, Kelly. 2001. Gnutella and the Transient Web. Online, disponível em http://www.openP2P.com/lpt/a/705. Publicado em março de 2001; último acesso em outubro de 2003. [2] ANDY, Oram. 2000. Gnutella and Freenet represent true technological innovation. Online, disponível em http://www.oreillynet.com/lpt/a/208. Publicado em maio de 2000; último acesso em outubro de 2003. [3] ORAM, Andy. 2001. O poder transformador das redes P2P. Berkeley Brasil, 2001. [4] SUN MICROSYSTEMS, INC.. 2001. Project JXTA: An open, Innovative Collaboration. Online, disponível em http://www.jxta.org/project/www/docs/OpenInnovative.pdf. Publicado em abril de 2001; último acesso em outubro de 2003. [5] Web site SETI@home. Online, disponível em http://setiathome.ssl.berkeley.edu/. Último acesso em outubro de 2003. [6] PARAMESWARAN, Manoj; SUSARLA, Anjana; WHINSTON , Andrew B.. 2001. P2P Networking: An information –Sharing Alternative. Online, disponível em http://cism.bus.utexas.edu/works/articles/PARA.Cxs2final.pdf. Publicado em julho de 2001; último acesso em outubro de 2003. [7] GONG, Li. 2001. JXTA: A network programming environment. Online, disponível em http://www.jxta.org/project/www/docs/JXTAnetworkProgEnv.pdf. Publicado em junho de 2001; último acesso em outubro de 2003. [8] GONG, Li. 2002. Project JXTA: A Technology Overview. Online, disponível em http://www.jxta.org/project/www/docs/jxtaview_01nov02.pdf. Publicado em Outubro de 2002; último acesso em outubro de 2003. 72 [9] TRAVERSAT, Bernard; ABDELAZIZ, Mohamed; DUIGOU, Mike; HUGLY, JeanChristophe; POUYOUL, Eric; YEAGER, Bill. 2002. Project JXTA Virtual Network. Online, disponível em http://www.jxta.org/docs/JXTAprotocols.pdf. Publicado em fevereiro de 2002; último acesso em outubro de 2003. [10] TRAVERSAT, Bernard; ARORA, Ahkil; ABDELAZIZ, Mohamed; DUIGOU, Mike; HAYWOOD, Carl; HUGLY, Jean-Christophe; POUYOUL, Eric; YEAGER, Bill. 2003. Project JXTA 2.0 Super-Peer Virtual Network. Online, disponível em http://www.jxta.org/project/www/docs/JXTA2.0protocols1.pdf. Publicado em maio de 2003; último acesso em outubro de 2003. [11] KRISHNAN, Navaneeth. 2003. Master the Jxta shell, Part 1. Online, disponível em http://www.javaworld.com/javaworld/jw-01-2002/jw-0111-jxtashell_p.html. Publicado em janeiro de 2003; último acesso em outubro de 2003. [12] SUN MICROSYSTEMS, INC.. 2001 Project JXTA: Technical Shell Overview. Online, disponível em http://www.jxta.org/project/www/docs/GettingStarted.pdf. Publicado em abril de 2001; último acesso em outubro de 2003. [13] OAKS, Scott; TRAVERSAT, Bernard; GONG, Li. Getting Started with JXTA, Part 1. Online, disponível em http://www.onjava.com/lpt/a/2619. Último acesso em outubro de 2003. [14] OAKS, Scott; TRAVERSAT, Bernard; GONG, Li. Getting Started with JXTA, Part 2. Online, disponível em http://www.onjava.com/lpt/a/2620. Último acesso em outubro de 2003. [15] OAKS, Scott; TRAVERSAT, Bernard; GONG, Li. Getting Started with JXTA, Part 3. Online, disponível em http://www.onjava.com/lpt/a/2621. Último acesso em outubro de 2003. [16] OAKS, Scott; TRAVERSAT, Bernard; GONG, Li. Getting Started with JXTA, Part 4. Online, disponível em http://www.onjava.com/lpt/a/2726. Último acesso em outubro de 2003. [17] OAKS, Scott; TRAVERSAT, Bernard; GONG, Li. Getting Started with JXTA, Part 5. Online, disponível em http://www.onjava.com/lpt/a/2725. Último acesso em outubro de 2003. 73 [18] KURNIAWAN, Budi. A JXTA Chat. Online, disponível em http://www.fawcette.com/javapro/2001_12/magazine/features/bkurniawan/. Último acesso em outubro de 2003. [19] MINAR, Nelson. 2001. JXTA Chat, Sans Server. Online, disponível em http://www.openP2P.com/lpt/a/912. Publicado em junho de 2001; último acesso em outubro de 2003. [20] BAEHNI, Sebastien. Wire chat. Online, disponível em http://lpdwww.epfl.ch/sbaehni/work/jxta/wireChat/pages/wireChat.html. Último acesso em outubro de 2003. [21] SUN MICROSYSTEMS, INC.. 2003. Project JXTA Technology:Creating Connected Communities. Online, disponível em http://jxta-wire.jxta.org/project/www/docs/JXTA-ExecBrief-032803.pdf. Publicado em março de 2003; último acesso em outubro de 2003. [22] SUN MICROSYSTEMS, INC.. Project JXTA. Online, disponível em http://wwws.sun.com/software/jxta/. Último acesso em outubro de 2003. [23] CLAßEN, Michael. 2001. Project JXTA: An Open, Peer-to-Peer Collaboration Platform using Java and XML. Online, disponível em http://www.webreference.com/xml/column32/index.html. Publicado em maio de 2001; último acesso em outubro de 2003. [24] SUN MICROSYSTEMS, INC.. Project JXTA: Scenarios. Online, disponível em http://wwws.sun.com/software/jxta/features/scenarios.html. Último acesso em outubro de 1003. [25] KRISHNAN, Navaneeth. 2001. The Jxta solution to P2P. Online, disponível em http://www.javaworld.com/javaworld/jw-10-2001/jw-1019-jxta_p.html. Publicado em outubro de 2001; último acesso em outubro de 2003. 74 [26] KRIKORIAN, Raffi. 2001. Hello JXTA!. Online, disponível em http://www.onjava.com/lpt/a/802. Publicado em abril de2001; último acesso em outubro de 2003. [27] DORNFEST, Rael. 2001. JXTA Takes Its Position. Online, disponível em http://www.openP2P.com/pub/a/P2P/2001/04/25/jxta_position.html. Publicado em abril de 2001; último acesso em outubro de 2003. [28] SUN MICROSYSTEMS, INC.. 2002. Five Abstractions. Online, disponível em http://www.sun.com/2002-0604/feature/five-ab.html. Publicado em junho de 2002; último acesso em outubro de 2003. [29] SUN MICROSYSTEMS, INC.. 2002. Six Protocols. Online, disponível em http://www.sun.com/2002-0604/feature/six.html. Publicado em junho de 2002; último acesso em outubro de 2003. [30] HALEPOVIC, Emir; DETERS, Ralph. The Costs of Using JXTA. Online, disponível em http://bistrica.usask.ca/madmuc/Grads/Emir/pub/P2P03_Halepovic_CostsOfUsingJXTA.pdf. Último acesso em outubro de 2003. [31] ROCHA, Rafael R.. 2003. Redes Peer-to-Peer para Compartilhamento de Arquivos. Online, disponível em http://www.gta.ufrj.br/seminarios/semin2003_1/rafael/principal.htm. Publicado em junho de 2003; último acesso em outubro de 2003. [32] SUNDSTED, Todd. 2001. The practice of peer-to-peer computing: Introduction and history. Online, disponível em http://www-106.ibm.com/developerworks/java/library/j-P2P/. Publicado em março de 2001; último acesso em outubro de 2003. [33] SUNDSTED, Todd.. 2001. The practice of peer-to-peer computing: Discovery. Online, disponível em http://www-106.ibm.com/developerworks/java/library/j-P2Pdisc/. Publicado em novembro de 2001. último acesso em outubro de 2003. [34] LI, Sing. 2002. P2P interoperable: Creating JXTA systems. Online, disponível em 75 http://www-106.ibm.com/developerworks/java/library/j-P2Pint3/. Publicado em abril de 2002; último acesso em outubro de 2003. [35] SUNDSTED, Todd.. 2002. The practice of peer-to-peer computing: IP Multicast-based discovery. Online, disponível em http://www-106.ibm.com/developerworks/java/library/jP2Pdisc2/. Publicado em janeiro de 2002; último acesso em outubro de 2003. 76 GLOSSÁRIO Browser Designação genérica do tipo de programa que nos permite navegar na Internet (Internet Explorer, Netscape Navigator, etc). Cache Refere-se ao local onde os dados são armazenados temporariamente. Distributed Network Uma rede na qual o processamento, o armazenamento e outras funções são executados em unidades (nós) separados, e não concentradas em um único computador. Firewall Um sistema de segurança ( hardware e/ou software ) cujo principal objetivo é filtrar os acessos a uma rede. As empresas utilizam o firewall para proteger as suas redes internas conectadas à Internet contra a entrada de pessoas não autorizadas. (Hackers). Existem diversas tecnologias possíveis para a construção de um Firewall. Gateway Sistema que permite o intercâmbio de serviços e informações entre redes com tecnologias iguais ou distintas. HTTP Hyper Text Transfer Protocol (Protocolo de transferência de Hipertexto). O HTTP é o protocolo usado para a transmissão de dados no sistema World-Wide Web. JXTA Sigla para a JustaPose, uma tecnologia para construção de aplicativos P2P independente de plataforma e dispositivos, liderada pela SUN Microsystem. 77 NAT Sigla para Network Address Translation. Ocorre quando vários endereços IP em uma LAN (Local área network) privada são convertidos para um endereço público. Esse endereço público é enviado para a Internet. A NAT acrescenta níveis de segurança porque o endereço IP de um PC conectado a LAN privada nunca é transmitido para a Internet. O usuário pode ter vários endereços privados mascarados pelo endereço único fornecido pelo Provedor Internet. A NAT evita rejeições de serviço (DoS) de redes externas em hosts internos. P2P Peer to Peer, comunicação direta entre dois pontos sem a necessidade de um intermediário. Os peers geralmente possuem capacidades e responsabilidades iguais em uma rede. Uma rede P2P é formada pelo conjunto de diversos peers participantes. Proxy Sevidor que atua como um intermediário entre a estação de trabalho e a Internet ou alguma outra rede, garantindo um certo nível de segurança por realizar uma comunicação indireta. Serviços como controle administrativo, limitação de recursos utilizados e cache podem ser fornecidos, dependendo da implementação utilizada. TCP/IP Transmission Control Protocol/Internet Protocol. Conjunto de protocolos da Internet que definem como se processam as comunicações entre vários computadores PDAs. 78 APÊNDICE A – CÓDIGOS FONTE DA IMPLEMENTAÇÃO Arquivo ChatApp.java package chat; import import import import import import import import import import import import import import import import import import import import import import import import import import import java.io.InputStream; java.text.DateFormat; java.util.ArrayList; java.util.Collection; java.util.Date; java.util.Enumeration; java.util.Iterator; java.util.Locale; net.jxta.discovery.DiscoveryEvent; net.jxta.discovery.DiscoveryListener; net.jxta.discovery.DiscoveryService; net.jxta.document.AdvertisementFactory; net.jxta.endpoint.Message; net.jxta.endpoint.StringMessageElement; net.jxta.id.IDFactory; net.jxta.peergroup.PeerGroup; net.jxta.peergroup.PeerGroupFactory; net.jxta.pipe.InputPipe; net.jxta.pipe.OutputPipe; net.jxta.pipe.PipeMsgEvent; net.jxta.pipe.PipeMsgListener; net.jxta.pipe.PipeService; net.jxta.protocol.DiscoveryResponseMsg; net.jxta.protocol.PeerAdvertisement; net.jxta.protocol.PipeAdvertisement; net.jxta.rendezvous.RendezVousService; org.apache.log4j.Logger; /** * Classe principal para aplicação do chat P2P, implementa as interfaces PipeMsgListener * para recebimento de eventos de pipes e DiscoveryListener para eventos de Discovery * de novos peers. */ public class ChatApp implements PipeMsgListener, DiscoveryListener { /** * Nome do elemento que definirá qual advertisement de pipe pertence a este chat. */ public static final String CHAT_NAME_TAG = "ChatMack"; /** * Tempo de vida do advertisement de pipe na rede. Após isso o chat parará de funcionar. */ private static final long ADV_LIFETIME = 210 * 1000; /** 79 * Frame responsável por exibir e enviar as mensagens para outros usuários. */ private static ChatFrame chatFrame; /** * Frame responsável por recuperar o nick escolhido. */ private static ChatLoginFrame chatLoginFrame; /** * Log 'chat' definido em classes/log4j.xml. */ private static Logger log = Logger.getLogger("chat"); /** * Nome do elemento que conterá mensagem enviada por um usuário. */ private static final String MESSAGE_TAG = "ChatSenderMessage"; /** * Nome do elemento que conterá o nome do enviador da mensagem */ private static final String SENDER_NAME = "ChatSenderName"; /** * Tempo de espera antes de tentar recuperar após um advertisement após um publish. */ private static final int WAITING_TIME = 5 * 1000; private DiscoveryService discovery; private PeerGroup group; /** * Indica se o flush de advertisements já foi realizado. */ private boolean isFlushed; /** * Indica se o usuário atual já esta logado. */ private boolean loggedIn; /** * Nick escolhido pelo usuário. */ private String nick; private PipeService pipeSvc; private RendezVousService rdv; /** * Irá procurar remotamente novos advertisements. */ private Thread thread; /** 80 * Utilizado para recebimento das mensagens enviadas para este usuário. */ private PipeAdvertisement userAdv; /** *Método para exibição formatada de data *@return String contendo data no formato dd/mm/aa hh:mm *@see <code>java.text.DateFormat#getDateTimeInstance(int, int, java.util.Locale)</code> */ public static String getShortDate() { DateFormat df = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, new Locale("pt", "BR")); return df.format(new Date(System.currentTimeMillis())); } public static void main(String args[]) { ChatApp chat = new ChatApp(); log.debug("Aplicação iniciada..."); chat.startJxta(); } /** * Cria um input pipe e adiciona a própria classe como ouvinte de eventos recebido * por este pipe */ private void createInputPipe() { InputPipe pipeIn = null; try { pipeIn = pipeSvc.createInputPipe(userAdv, this); } catch (Exception e) { log.fatal("Impossível criar pipe de entrada:" + e.getMessage()); System.exit(-1); } log.info("Pipe de entrada criado com sucesso..."); } /** * Recebe os eventos de discovery para esta classe. Apenas registra no log * os advertisements recebidos pertencente a este chat, e mostra * quais foram as respostas recebidas e por quem foram enviadas * * @param ev Evento de Discovery recebido */ public void discoveryEvent(DiscoveryEvent ev) { DiscoveryResponseMsg res = ev.getResponse(); String name = "Unknown"; PeerAdvertisement peerAdv = res.getPeerAdvertisement(); if (peerAdv != null) { name = peerAdv.getName(); } log.debug( 81 res.getResponseCount() + " resposta[s] de discovery recebida[s] de " + name + "..."); PipeAdvertisement adv = null; Enumeration enum = res.getAdvertisements(); if (enum != null) { while (enum.hasMoreElements()) { try { adv = (PipeAdvertisement) enum.nextElement(); log.debug( "Pipe para usuário '" + adv.getName() + "' recuperado no evento de discovery:\n" + adv.toString()); } catch (Exception e) { } } } } /** * Procura por advertisements de pipe de um determinado usuário localmente * e remotamente * @param name Nick de qual usuário que desejamos procurar advs * @return <code>PipeAdvertisement</code> contendo o advertisement recuperado * para este usuário ou null, caso nenhum tenha sido encontrado. * @see #findUserAdvLocal(String). * @see #findUserAdvRemote(String). */ private PipeAdvertisement findUserAdv(String name) { PipeAdvertisement adv = findUserAdvLocal(name); if (adv == null) { adv = findUserAdvRemote(name); adv = findUserAdvLocal(name); } return adv; } /** * Realiza o flush dos advertisements locais, e recupera * os advertisements ainda validos que correspondam a esta aplicação de chat, * procurando por um usuário específico. * * @param name Nick do usuário desejado. * @return null ou PipeAdvertiment já atribuído a este usuário anteriormente. */ private PipeAdvertisement findUserAdvLocal(String name) { Enumeration enum = null; try { if(isFlushed){ discovery.flushAdvertisements(null, DiscoveryService.ADV); 82 log.info(" flush de advertisements executados com sucesso..."); } enum = discovery.getLocalAdvertisements( DiscoveryService.ADV, "Name", CHAT_NAME_TAG + ":" + nick); if (enum != null) { PipeAdvertisement adv = null; while (enum.hasMoreElements()) { try { adv = (PipeAdvertisement) enum.nextElement(); if ((CHAT_NAME_TAG + ":" + name) .equals(adv.getName())) { return adv; } } catch (Exception e) { } } } } catch (Exception e) { log.error( "Erro ao recuperar advertisements de cache:" + e.getMessage()); } return null; } /** * Procura remotamente os advertisements de pipe desta aplicação * e que correspondam a um determinado usuário informado. * * @param name Nick do usuário desejado * @return null ou <code>PipeAdvertiment</code> deste usuário válido na rede JXTA */ private PipeAdvertisement findUserAdvRemote(String name) { PipeAdvertisement adv = null; try { //ache todos os advertisiments locais de pipes publicados por esta aplicação.... discovery.getRemoteAdvertisements( null, DiscoveryService.ADV, "Name", "*" + CHAT_NAME_TAG + ":*", 2); try { Thread.sleep(WAITING_TIME); } catch (Exception e) { } } catch (Exception e) { log.error( "Erro ao recuperar advertisements remotos:" + e.getMessage()); 83 } return null; } /** * Recupera todos os advertisements locais desta aplicação, * verificando qual corresponde a PipeAdvertisement. * * @return <code>Collection</code> contendo todos os PipeAdvertisement encontrados. */ private Collection getAllPipeLocalAdvertisements() { Collection pipes = new ArrayList(); try { Enumeration enum = discovery.getLocalAdvertisements( DiscoveryService.ADV, "Name", "*" + CHAT_NAME_TAG + ":*"); if (enum != null) { while (enum.hasMoreElements()) { try { PipeAdvertisement adv = (PipeAdvertisement) enum.nextElement(); pipes.add(adv); } catch (Exception e) { continue; } } } } catch (Exception e) { log.error( "Erro ao recuperar cache de advertisements:" + e.getMessage()); } return pipes; } public String getNick() { return nick; } /** * Efetua o login na aplicação de chat, criando um PipeAdvertisement * para este usuário, e publicando este pipe localmente e remotamente * na rede JXTA. Após realizada a publicação do advertisement,o frame que exibe e permite * o envio de mensagens é exibido, uma mensagem para todos é enviada * alertando a presença de um novo usuário, e uma thread é iniciada para descoberta * de novos advertisements na rede JXTA. Caso haja algum problema antes de terminar a rotina, * a aplicação é encerrada com código de erro -1. * * @param name Nick escolhido pelo usuário na tela de login * @return <code>int</code> , -1 caso o usuário já tenha realizado * o login anteriormente, ou 1 caso tudo tenha sido realizado com sucesso. 84 */ public int loginChat(String name) { if (!loggedIn) { this.nick = name; discovery.addDiscoveryListener(this); PipeAdvertisement adv = findUserAdv(name); if (adv != null) { log.fatal( "Erro, Advertisiment já existente para este usuário, saindo da aplicação..."); System.exit(-1); } try { //criando um adv de pipe para este user... adv = (PipeAdvertisement) AdvertisementFactory.newAdvertisement( PipeAdvertisement.getAdvertisementType()); adv.setPipeID(IDFactory.newPipeID(group.getPeerGroupID())); adv.setName(CHAT_NAME_TAG + ":" + name); adv.setType(PipeService.PropagateType); } catch (Exception e) { log.fatal( "Impossível criar advertisement de pipe:" + e.getMessage()); System.exit(-1); } try { discovery.publish( adv, DiscoveryService.ADV, ADV_LIFETIME, ADV_LIFETIME); discovery.remotePublish( adv, DiscoveryService.ADV, ADV_LIFETIME); } catch (Exception e) { log.fatal( "Impossível publicar advertisement de pipe:" + e.getMessage()); System.exit(-1); } adv = findUserAdvLocal(name); if (adv == null) { log.fatal( "Impossível recuperar advertisement de pipe para este usuário..."); System.exit(-1); } userAdv = adv; loggedIn = true; createInputPipe(); chatFrame.setTitle(getNick() + " - JXTA Chat P2P "); chatFrame.show(); sendMessageToAll(" Entrei no chat...."); 85 //thread que vai recuperar novos pipes de tempos em tempos... log.info("Criando thread para Discovery de pipes..."); DiscoveryPipes discoveryPipes = new DiscoveryPipes(discovery); } else { log.fatal("Atenção , você já esta logado no chat..."); return -1; } return 1; } public void pipeMsgEvent(PipeMsgEvent pipeMsgEvent) { try { Message message = pipeMsgEvent.getMessage(); String from = message.getMessageElement(SENDER_NAME).toString(); String msg = message.getMessageElement(MESSAGE_TAG).toString(); chatFrame.printMessage(msg, from); } catch (Exception e) { log.error("Erro ao receber evento de pipe:" + e.getMessage()); } } public void sendMessageToAll(String texto) { Collection pipes = getAllPipeLocalAdvertisements(); if (pipes != null) { Iterator it = pipes.iterator(); while (it.hasNext()) { PipeAdvertisement adv = (PipeAdvertisement) it.next(); OutputPipe pipeOut = null; try { pipeOut = pipeSvc.createOutputPipe(adv, 100); } catch (Exception e) { log.error( "Erro ao criar OutputPipe para '" + adv.getName() + "':" + e.getMessage()); } if (pipeOut != null) { Message msg = null; String userInput = null; InputStream inputStream = null; try { msg = pipeSvc.createMessage(); //inputStream=new ByteArrayInputStream() StringMessageElement sme = new StringMessageElement(SENDER_NAME, nick, null); StringMessageElement sme2 = new StringMessageElement(MESSAGE_TAG, texto, null); msg.replaceMessageElement(sme); msg.replaceMessageElement(sme2); pipeOut.send(msg); } catch (Exception e) { log.error( 86 "Erro ao enviar mensagem para '" + adv.getName() + "':" + e.getMessage()); } } } } } public void startJxta() { try { group = PeerGroupFactory.newNetPeerGroup(); log.info("NetPeerGroup iniciado com sucesso..."); } catch (Exception e) { log.fatal("Erro ao iniciar netPeerGroup:" + e.getMessage()); System.exit(-1); } discovery = group.getDiscoveryService(); rdv = group.getRendezVousService(); log.info("Rendezvous service recuperado..."); while (rdv.isConnectedToRendezVous()) { try { log.info("Aguardando conexão com Rendezvous..."); Thread.sleep(2000); } catch (InterruptedException e) { } } log.info( "Conexão com Rendezvous estabelecida, recuperando serviço de pipe..."); pipeSvc = group.getPipeService(); chatLoginFrame = new ChatLoginFrame(this); chatFrame = new ChatFrame(this); } } Arquivo DiscoveryPipes.java package chat; import net.jxta.discovery.DiscoveryService; import org.apache.log4j.Logger; /** * Esta classe implementa a interface Runnable, e inicia uma * thread que procura por novos advertisements na rede a cada 60 segundos. */ public class DiscoveryPipes implements Runnable { private DiscoveryService discoverySvc; /** * Log 'chat' definido em classes/log4j.xml. 87 */ private static Logger log = Logger.getLogger("chat"); /** * Construtor da classe que recebe o serviço de discovery (DiscoveryService) * da classe chat.ChatApp, e inicia uma nova thread para a procura de Advertisements. * @see chat.ChatApp */ public DiscoveryPipes(DiscoveryService discoverySvc) { this.discoverySvc = discoverySvc; Thread t = new Thread(this); t.start(); log.info("Thread para Discovery de pipes criada e iniciada...."); } public void run() { while (true) { try { log.info("Tentando descobrir novos pipes remotamente..."); discoverySvc.getRemoteAdvertisements( null, DiscoveryService.ADV, null, null, 100); Thread.sleep(60 * 1000); } catch (InterruptedException e) { } } } } Arquivo ChatLoginFrame.java package chat; import import import import import import import import import import import import import import java.awt.Color; java.awt.MediaTracker; java.awt.Rectangle; java.awt.event.ActionEvent; java.awt.event.KeyEvent; java.awt.event.KeyListener; javax.swing.BorderFactory; javax.swing.ImageIcon; javax.swing.JButton; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JOptionPane; javax.swing.JPanel; javax.swing.JTextField; 88 import javax.swing.border.Border; import javax.swing.border.TitledBorder; import org.apache.log4j.Logger; public class ChatLoginFrame extends JFrame implements KeyListener { private static Logger log = Logger.getLogger("chat"); JTextField jtLogin = new JTextField(); JButton jbLogin = new JButton(); JLabel jLabelNick = new JLabel(); JLabel jLabelLogoMack = new JLabel(); TitledBorder titledBorder1; JLabel jLabel1 = new JLabel(); JLabel jLabel2 = new JLabel(); Border border1; JLabel jLabel3 = new JLabel(); JLabel jLabel4 = new JLabel(); JPanel jPanel1 = new JPanel(); JLabel jLabel5 = new JLabel(); private ChatApp chat; public ChatLoginFrame() { } public ChatLoginFrame(ChatApp app) { chat = app; try { jbInit(); } catch (Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { this.setTitle("Implementação JXTA chat P2P"); border1 = BorderFactory.createLineBorder(Color.white, 1); jtLogin.setBounds(new Rectangle(5, 184, 171, 21)); this.getContentPane().setLayout(null); jbLogin.setBounds(new Rectangle(244, 182, 95, 23)); jbLogin.setText("Entrar"); this.setResizable(false); jLabelNick.setText("Digite abaixo o seu nick:"); jLabelNick.setBounds(new Rectangle(6, 163, 141, 15)); jLabel1.setFont(new java.awt.Font("SansSerif", 1, 12)); jLabel1.setText("Implementação JXTA CHAT"); jLabel1.setBounds(new Rectangle(8, 0, 175, 23)); jLabel2.setText("Antonio Augusto Mariano Da Silva"); jLabel2.setBounds(new Rectangle(5, 12, 197, 17)); jLabel3.setText("Ricardo Augusto Miguel"); jLabel3.setBounds(new Rectangle(6, 36, 205, 20)); jLabel4.setText("Ricardo Ribeiro Tavares"); jLabel4.setBounds(new Rectangle(7, 65, 155, 17)); jPanel1.setBorder(BorderFactory.createEtchedBorder()); jPanel1.setLayout(null); jPanel1.setBounds(new Rectangle(7, 52, 209, 99)); jLabel5.setFont(new java.awt.Font("SansSerif", 1, 12)); jLabel5.setForeground(Color.red); jLabel5.setText("Orientador: Prof. Rogério Oliveira"); 89 jLabel5.setBounds(new Rectangle(7, 25, 201, 20)); jPanel1.add(jLabel4, null); jPanel1.add(jLabel3, null); jPanel1.add(jLabel2, null); jtLogin.addKeyListener(this); this.getContentPane().add(jtLogin, null); this.getContentPane().add(jLabelNick, null); this.getContentPane().add(jPanel1, null); this.getContentPane().add(jbLogin, null); this.getContentPane().add(jLabel5, null); this.getContentPane().add(jLabel1, null); this.getContentPane().add(jLabelLogoMack, null); try { MediaTracker tracker = new MediaTracker(this); ImageIcon img = new ImageIcon(getClass().getResource("logo.gif")); tracker.addImage(img.getImage(), 0); tracker.waitForAll(); jLabelLogoMack.setIcon(img); jLabelLogoMack.setBounds( new Rectangle( 230, 10, img.getIconWidth() + 8, img.getIconHeight() + 8)); } catch (Exception e) { log.warn("Erro ao carregar imagens:" + e.getMessage()); } this.setSize(380, 250); this.setDefaultCloseOperation(3); jbLogin.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { doLogin(); } }); show(); } private void hideFrame() { this.hide(); } private void doLogin() { String nick = jtLogin.getText(); hideFrame(); int resultado = chat.loginChat(nick); if (resultado < 0) { JOptionPane.showMessageDialog( null, "Atenção, já existe um usuário com este nick no chat, escolha outro!"); log.fatal("Atenção, já existe um usuário com este nick no chat, escolha outro!"); System.exit(0); } jtLogin.setText(""); } public void keyPressed(KeyEvent arg0) { 90 if (arg0.getKeyCode() == 10) { doLogin(); } } public void keyReleased(KeyEvent arg0) { } public void keyTyped(KeyEvent arg0) { } } Arquivo ChatFrame.java package chat; import import import import import import import import import import import import import import import java.awt.MediaTracker; java.awt.Rectangle; java.awt.event.ActionEvent; java.awt.event.KeyEvent; java.awt.event.KeyListener; java.util.Date; javax.swing.ImageIcon; javax.swing.JButton; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JOptionPane; javax.swing.JScrollPane; javax.swing.JTextArea; javax.swing.JTextField; org.apache.log4j.Logger; public class ChatFrame extends JFrame implements KeyListener { private static Logger log = Logger.getLogger("chat"); private ChatApp chat; JButton jbEnviar = new JButton(); JLabel jLabelLogoJxta = new JLabel(); JLabel jLabelLogoMack = new JLabel(); JScrollPane jScrollPane1 = new JScrollPane(); JTextField jtMsg = new JTextField(); JTextArea jtMsgAll = new JTextArea(); public ChatFrame(ChatApp chatApp) { try { jbInit(); this.chat = chatApp; } catch (Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { jtMsg.setBounds(new Rectangle(13, 272, 395, 19)); this.setDefaultCloseOperation(3); this.getContentPane().setLayout(null); jbEnviar.setBounds(new Rectangle(439, 272, 77, 21)); jbEnviar.setText("Enviar"); 91 //jScrollPane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SC ROLLBAR_ALWAYS); jScrollPane1.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); jScrollPane1.setAutoscrolls(true); jScrollPane1.setBounds(new Rectangle(13, 8, 402, 251)); jtMsgAll.setWrapStyleWord(true); jtMsgAll.setBounds(new Rectangle(13, 8, 350, 200)); jtMsgAll.setEditable(false); jScrollPane1.getViewport().add(jtMsgAll, null); try { MediaTracker tracker = new MediaTracker(this); ImageIcon img = new ImageIcon(getClass().getResource("logo.gif")); ImageIcon img2 = new ImageIcon(getClass().getResource("logo_jxta.gif")); tracker.addImage(img.getImage(), 0); tracker.addImage(img2.getImage(), 0); tracker.waitForAll(); jLabelLogoMack.setIcon(img); jLabelLogoMack.setBounds( new Rectangle( 430, 10, img.getIconWidth() + 8, img.getIconHeight() + 8)); jLabelLogoJxta.setIcon(img2); jLabelLogoJxta.setBounds( new Rectangle( 430, 120, img2.getIconWidth() + 8, img2.getIconHeight() + 8)); } catch (Exception e) { log.warn("Erro ao carregar imagens:" + e.getMessage()); } jbEnviar.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { sendMessage(jtMsg.getText()); jtMsg.setText(""); } }); this.getContentPane().add(jScrollPane1, null); this.getContentPane().add(jbEnviar, null); this.getContentPane().add(jtMsg, null); this.getContentPane().add(jLabelLogoJxta, null); this.getContentPane().add(jLabelLogoMack, null); setSize(580, 360); setResizable(false); jtMsg.requestFocusInWindow(); jbEnviar.setFocusPainted(true); jtMsg.addKeyListener(this); } public void keyPressed(KeyEvent arg0) { 92 //user apertou enter if (arg0.getKeyCode() == 10) { if ("".equals(jtMsg.getText())) { System.out.println("Mensagem inválida, digite algo..."); JOptionPane.showMessageDialog(null, "Mensagem inválida!"); } else { sendMessage(jtMsg.getText()); jtMsg.setText(""); } } } public void keyReleased(KeyEvent arg0) { } public void keyTyped(KeyEvent arg0) { } public void printMessage(String msg) { jtMsgAll.append("\n" + new Date() + " - " + msg); } public void printMessage(String msg, String from) { String msgFormatada = ChatApp.getShortDate() + " - " + from + " fala para todos:" + msg; jtMsgAll.append("\n" + msgFormatada); } public void sendMessage(String mensagem) { chat.sendMessageToAll(mensagem); } } Arquivo log4j.xml log4j.rootLogger=WARN,root log4j.appender.root=org.apache.log4j.ConsoleAppender log4j.appender.root.layout=org.apache.log4j.PatternLayout log4j.appender.root.layout.ConversionPattern=%d - %-4r- %3x - [%t] %-5p (%F:%L) - %m%n log4j.logger.chat=WARN,a #log4j.additivity.login=false log4j.appender.a=org.apache.log4j.RollingFileAppender log4j.appender.a.File=chat.log log4j.appender.a.layout=org.apache.log4j.PatternLayout log4j.appender.a.layout.ConversionPattern=%d - %-4r- %3x - [%t] %-5p (%F:%L) - %m%n 93 Antonio Augusto Mariano da Silva Ricardo Augusto Miguel Ricardo Ribeiro Tavares Desenvolvendo aplicações peer-topeer em JAVA com JXTA Trabalho apresentado à disciplina de Trabalho de Graduação Interdisciplinar II, como parte das exigências para a obtenção do título de Bacharel em Sistemas de Informação pela Faculdade de Computação e Informática da Universidade Presbiteriana Mackenzie Orientador: Rogério de Oliveira São Paulo Outubro de 2003 RESUMO Nos dias atuais, para o desenvolvimento e melhor obtenção de recursos da Internet, necessitaremos de uma computação distribuída com compartilhamento de recursos, conteúdo, e estrutura de rede independente, redundante e segura em tempo real. Neste estudo estaremos apresentando os principais modelos e implementações atuais de aplicações P2P e as necessidades existentes. Os conceitos envolvidos em uma construção serão apresentados detalhadamente, e posteriormente aplicados em um projeto open source Java JXTA, que permitirá um novo tipo de computação distribuída tornando muito mais fácil as tarefas que as pessoas executam na Web atualmente: encontrar, obter, utilizar. Codificaremos em JAVA algumas aplicações JXTA simples que exemplificam o potencial dessa tecnologia. ABSTRACT Nowadays, for a development and to get Internet resources, need a the distributed computing and sharing of resources over the internet need a distributed computation with resource sharing, content, and independent, redundant and a security network infrastructure in real time. In this study we are showing the core models and implementations for peer-to-peer applications and the real necessity of use it. The concepts involved in construction of peer-to-peer applications are showing deeply, and after that, we are introducing the main concepts of JXTA, that it will allow a new type of distributed computation that it becomes much more easy the tasks that the people run in the Web: search, get, use.To exemplify the power of this technology we are coding some simple examples like a chat in JAVA with JXTA framework. After read this study you’ll be able to understand the main concepts of peer-to-peer, and the challeng involved in it, in addition to develop simple applications using JAVA with JXTA framework.
Documentos relacionados
Implementação de um Algoritmo para Busca em Redes Peer-to-Peer
Sistemas altamente estruturados são também caracterizados por serem menos flexíveis em um ambiente com população de usuários muito transitória, pois há um custo alto para manter a estrutura necess...
Leia mais