Anda di halaman 1dari 15

Sockets com Java Parte I Neste artigo veremos como desenvolver aplicaes em Java que podem comunicar-se via

a rede local ou via internet, usando sockets. Os sockets so compostos por um conjunto de primitivas do sistema operacional e foram originalmente desenvolvidos para o BSD Unix. Podem ser utilizados nos mais variados sistemas operacionais com recursos de comunicao em rede, sendo suportados pela maioria das linguagens de programao. Sockets so suportados em Java desde o JDK 1.0, para sua utilizao devemos fazer uso das classes contidas no pacote java.net. Um exemplo interessante da programao de sockets em Java so os drivers JDBC do tipo 4, que usam sockets para comunicar-se diretamente com a API de rede do banco de dados. Estrutura bsica de uma aplicao de rede Uma aplicao que utiliza sockets normalmente composta por uma parte servidora e diversos clientes. Um cliente solicita determinado servio ao servidor, o servidor processa a solicitao e devolve a informao ao cliente (ver Figura 1). Muitos servios podem ser disponibilizados numa mesma mquina, sendo ento diferenciados no s pelo endereo IP, mas tambm por um nmero de porta. Porm, o mais comum termos uma mquina dedicada oferecendo apenas um ou dois servios, evitando assim a concorrncia.

Figura 1. Fluxo de troca de dados com sockets Como primeiros passos na criao do servidor, necessrio importar o pacote java.net e em seguida instanciar um objeto do tipo ServerSocket, responsvel por atender pedidos via rede e em determinada porta. Aps receber uma conexo, um objeto do tipo Socket deve ser criado para manter a comunicao entre o cliente e o servidor. Vejamos um exemplo. A seguinte linha cria o ServerSocket, que ir esperar conexes na porta 12345 (caso esta porta j esteja em uso, uma exceo ser lanada): ServerSocket server = new ServerSocket(12345);

Em seguida criamos um objeto Socket, o qual ir tratar da comunicao com o cliente, assim que um pedido de conexo chegar ao servidor e a conexo for aceita: Socket client = server.accept(); Como vimos no exemplo, um socket servidor precisa definir o nmero da porta para receber conexes dos clientes. Este nmero pode variar entre 0 e 65535, porm, em nossas aplicaes s devemos utilizar de 1024 em diante, pois as portas com nmeros abaixo deste so reservados para o uso do sistema (por exemplo a porta 80 usada pelo protocolo HTTP, 25 pelo SMTP, 110 pelo POP3, entre vrios outros servios). Endereos IP Cada mquina conectada a uma rede possui um endereo IP nico de maneira que possa ser identificada na rede. A classe InetAdress nos permite obter informaes sobre um computador conectado a rede. Os principais mtodos desta classe so os seguintes: getAddress(): Este mtodo retorna um array de bytes contendo o endereo IP. Para isso, o nome do host que se deseja obter o endereo IP fornecido ao mtodo getByName da classe InetAddress, veja um exemplo; byte[] b = InetAddress.getByName("localhost").getAddress(); System.out.println(b[0] + "." + b[1] + "." + b[2] + "." + b[3]); getHostAddress(): Este mtodo retorna uma String contendo o endereo IP no formato 999.999.999.999, veja um exemplo; System.out.println("Endereo: " + InetAddress.getByName("localhost").getHostAddress() ); getHostName(): Dado um array de bytes contendo o endereo IP de um host, este mtodo retorna uma String com o nome do host, veja um exemplo; byte[] addr = {127,0,0,1}; System.out.println(InetAddress.getByAddress(addr).getHostName());

Leia mais em: Sockets com Java Parte I http://www.devmedia.com.br/sockets-com-javaparte-i/9465#ixzz2lO91nIPT

Sockets com Java Parte II O protocolo TCP Quando necessitamos de uma troca confivel de informaes, isto , quando necessria a confirmao de recebimento da mensagem enviada, devemos utilizar o protocolo TCP (Transmission Control Protocol). Este protocolo estabelece uma conexo entre dois pontos interligados. Por exemplo, uma mensagem enviada de um host (o termo host representa uma mquina conectada na rede) a outro confirmada pelo host receptor indicando o correto recebimento da mensagem. Uma mensagem pode ser enviada em vrios pacotes, o TCP cuida para que os pacotes recebidos sejam remontados no host de destino na ordem correta (caso algum pacote no tenha sido recebido, o TCP requisita novamente este pacote). Somente aps a montagem de todos os pacotes que as informaes ficam disponveis para nossas aplicaes. A programao do TCP com sockets utiliza streams, o que simplifica muito o processe de leitura e envio de dados pela rede. Streams so objetos Java que permitem obter dados de qualquer fonte de entrada, seja o teclado, um arquivo ou at mesmo um fluxo de bytes recebidos pela rede (o que o nosso caso). Isto torna a manipulao de dados da rede como se fossem arquivos, ao ler dados enviados como se estivssemos lendo um arquivo e ao enviar dados como se estivssemos gravando dados em um arquivo. Um primeiro servidor TCP Vamos comear agora a trabalhar na prtica com sockets. Primeiro vamos montar um servidor TCP que permite a seus clientes solicitarem a data e a hora atuais do servidor. A primeira verso deste servidor tem uma limitao (que mostraremos mais tarde como resolver): apenas um cliente pode ser atendido por vez. Uma das caractersticas importantes do TCP que os pedidos de conexes dos clientes vo sendo mantidos em uma fila pelo sistema operacional at que o servidor possa atend-los. Isto evita que o cliente receba uma negao ao seu pedido, pois o servidor pode estar ocupado com outro processo e no conseguir atender o cliente naquele momento. Cada sistema operacional pode manter em espera um nmero limitado de conexes at que sejam atendidas. Quando o sistema operacional recebe mais conexes que esse limite, as conexes mais antigas vo sendo descartadas. Veja como funciona o nosso primeiro exemplo: Ao ser iniciado o servidor fica ouvindo na porta 12345 a espera de conexes de clientes; O cliente solicita uma conexo ao servidor; O servidor exibe uma mensagem na tela com o endereo IP do cliente conectado; O servidor aceita a conexo e envia um objeto Date ao cliente; O cliente recebe o objeto do servidor e faz o cast necessrio, em seguida exibe na tela as informaes de data; O servidor encerra a conexo. Na Listagem 1 apresentado o cdigo do nosso primeiro exemplo de servidor e na Listagem 2 apresentado o cdigo do cliente que utiliza o nosso servidor. Listagem 1. Cdigo do servidor TCP bsico

public class ServidorTCPBasico { public static void main(String[] args) { try { // Instancia o ServerSocket ouvindo a porta 12345 ServerSocket servidor = new ServerSocket(12345); System.out.println("Servidor ouvindo a porta 12345"); while(true) { // o mtodo accept() bloqueia a execuo at que // o servidor receba um pedido de conexo Socket cliente = servidor.accept(); System.out.println("Cliente conectado: " + cliente.getInetAddress().getHostAddress()); ObjectOutputStream saida = new ObjectOutputStream(cliente.getOutputStream()); saida.flush(); saida.writeObject(new Date()); saida.close(); cliente.close(); } } catch(Exception e) { System.out.println("Erro: " + e.getMessage()); } finally {...} } } Listagem 2. Cdigo do cliente TCP bsico public class ClienteTCPBasico { public static void main(String[] args) { try { Socket cliente = new Socket("paulo",12345); ObjectInputStream entrada = new ObjectInputStream(cliente.getInputStream()); Date data_atual = (Date)entrada.readObject(); JOptionPane.showMessageDialog(null,"Data recebida do servidor:" + data_atual.toString()); entrada.close(); System.out.println("Conexo encerrada"); } catch(Exception e) { System.out.println("Erro: " + e.getMessage()); } } } Na Figura 2 podemos ver as mensagens exibidas pelo servidor ao receber conexes e na Figura 3 apresentada a data atual do servidor recebida pelo cliente.

Figura 2. Mensagens exibidas pelo servidor ao receber conexes de clientes

Figura 3. Data e hora recebidas pelo cliente Leia mais em: Sockets com Java Parte II http://www.devmedia.com.br/sockets-com-javaparte-ii/9466#ixzz2lO9nbM4x

Sockets com Java Parte III Aprenda a desenvolver aplicaes em Java que comunicam-se via rede local ou internet O protocolo UDP Quando necessitamos de uma troca no confivel de informaes podemos usar o protocolo UDP (User Datagram Protocol), pois este protocolo no garante a entrega dos pacotes (o UDP no espera uma mensagem de confirmao do host de destino). de responsabilidade da aplicao receptora a remontagem dos pacotes na ordem correta e a solicitao de reenvio de pacotes que no foram recebidos. O UDP utiliza datagram sockets para a troca de mensagens. As principais aplicaes do UDP so aplicaes como transmisses de vdeo, skype, voip, etc... Para exemplificar imagine um servio de voz sobre IP onde um pacote perdido enquanto dois usurios conversam, no faz sentido reenviar o pacote pois o usurio da outra ponta precisaria saber que ainda faltam pacotes a receber. Veja uma simulao abaixo da conversa entre dois usurios: Erika: Ola Paulo Paulo: Ola Erika Erika: Como voc est? Paulo: Tudo bem e vc? (este pacote foi perdido)

No exemplo acima o TCP enviaria novamente o pacote e o usurio da outra ponta deveria ficar esperando. No faria nenhum sentido isso tratando-se de uma ligao telefnica. Este um tpico caso onde o UDP se aplica perfeitamente. Os datagram sockets so mensagens que podem ser enviadas pela rede quando no existe a necessidade de confirmao de entrega, de tempo de entrega e nem mesmo garantia de contedo. Datagramas so teis em aplicaes que no necessitam do estabelecimento de uma conexo para o envio da mensagem. Um bom exemplo do seu uso o envio de mensagens em broadcast para clientes de uma rede (o servidor pode enviar um datagrama para todos os clientes avisando que ir reiniciar, por exemplo). Em Java podemos trabalhar com datagramas utilizando as classes DatagramPacket e DatagramSocket do pacote java.net. Um servidor UDP bsico Antes de mostramos como criar um servidor TCP capaz de receber vrias conexes simultneas, vamos mostrar como criar um servidor UDP. Como vimos, o UDP envia os pacotes sem esperar por uma resposta do receptor. Este protocolo pode ser til em situaes como o envio de pacotes multimdia, por exemplo, ou um servio de voz sobre ip, o que muito comum. Nosso servidor UDP envia mensagens para os clientes de uma determinada rede local. Perceba neste exemplo que no UDP o cliente tambm aguarda mensagens que podero ser enviadas pelo servidor, ou seja, mantm um DatagramSocket em uma determinada porta. Por exemplo, o seguinte trecho cria o DatagramSocket que ir esperar mensagens na porta 12346. DatagramSocket serverdgram = new DatagramSocket(12346); Veja na Listagem 3 o remetente UDP exemplo e na Listagem 4 o cdigo do receptor UDP, na Figura 4 voc pode ver a mensagem sendo enviada pelo remetente. Na Figura 5 temos o receptor sendo inicializado para receber as mensagens e na Figura 6 a mensagem recebida

pelo receptor. Como estamos usando UDP neste caso o remetente sempre vai mostrar a mensagem indicando que a mensagem foi enviada, porm no existe a confirmao de que a mensagem foi recebida. Listagem 3. Classe RemetenteUDP public class RemetenteUDP { public static void main(String[] args) { if(args.length != 3) { System.out.println("Uso correto: <Nome da maquina> <Porta> <Mensagem>"); System.exit(0); } try { //Primeiro argumento o nome do host destino InetAddress addr = InetAddress.getByName(args[0]); int port = Integer.parseInt(args[1]); byte[] msg = args[2].getBytes(); //Monta o pacote a ser enviado DatagramPacket pkg = new DatagramPacket(msg,msg.length, addr, port); // Cria o DatagramSocket que ser responsvel por enviar a mensagem DatagramSocket ds = new DatagramSocket(); //Envia a mensagem ds.send(pkg); System.out.println("Mensagem enviada para: " + addr.getHostAddress() + "\n" + "Porta: " + port + "\n" + "Mensagem: " + args[2]); //Fecha o DatagramSocket ds.close(); } catch(IOException ioe) {...} } } Listagem 4. Classe ReceptorUDP public class ReceptorUDP { public static void main(String[] args) { if(args.length != 1) { System.out.println("Informe a porta a ser ouvida"); System.exit(0); } try { //Converte o argumento recebido para inteiro (numero da porta) int port = Integer.parseInt(args[0]); //Cria o DatagramSocket para aguardar mensagens, neste momento o mtodo fica bloqueando //at o recebimente de uma mensagem DatagramSocket ds = new DatagramSocket(port); System.out.println("Ouvindo a porta: " + port); //Preparando o buffer de recebimento da mensagem byte[] msg = new byte[256]; //Prepara o pacote de dados

DatagramPacket pkg = new DatagramPacket(msg, msg.length); //Recebimento da mensagem ds.receive(pkg); JOptionPane.showMessageDialog(null,new String(pkg.getData()).trim(), "Mensagem recebida",1); ds.close(); } catch(IOException ioe) {...} } }

Figura 4. Remetente UDP em ao (enviando mensagem ao receptor)

Figura 5. Receptor sendo inicializado para receber mensagens na porta 1234

Figura 6. Mensagem UDP recebida pelo receptor

Leia mais em: Sockets com Java Parte III http://www.devmedia.com.br/sockets-com-javaparte-iii/9467#ixzz2lOAmckPj

Sockets com Java Parte IV Um servidor TCP com mltiplos threads Como vimos no nosso primeiro exemplo de servidor TCP, um servidor de produo no deve se limitar a processar uma conexo de cada vez, devendo ser capaz de atender inmeras conexes simultaneamente. Veremos agora como montar um servidor TCP mais profissional usando threads. Um caso prtico do uso de sockets em Java Vamos ver agora o exemplo de um cliente que solicita arquivos de imagem ao servidor. O cliente deve informar o caminho do arquivo no servidor, ao receber o pedido o servidor enviar o arquivo ao cliente. A aplicao exemplo solicita um arquivo JPG presente em um diretrio do servidor, e ao receber o arquivo, exibe um JLabel o contedo do arquivo. Para cada solicitao de cliente ser criada uma nova thread para gerenciar a troca de mensagens, deixando assim o servidor livre para esperar por novas conexes. Vejamos detalhadamente este processo. Na Listagem 5 temos o cdigo do servidor de arquivos e na Listagem 6 o cdigo da thread que trata do pedido especfico. Na Figura 7 temos a aplicao em ao solicitando arquivos ao servidor e na Figura 8 temos o console de atividades do servidor. Na Listagem 7 voc pode ver o cdigo do boto Buscar da aplicao exemplo. Listagem 5. Servidor de arquivos multithreaded public class ServidorArquivo { public static void main(String[] args) { if(args.length < 1) { System.out.println("Informe a porta a ser ouvida pelos servidor"); System.exit(0); } try { //Converte o parametro recebido para int (nmero da porta) int port = Integer.parseInt(args[0]); System.out.println("Incializando o servidor..."); //Iniciliza o servidor ServerSocket serv = new ServerSocket(port); System.out.println("Servidor iniciado, ouvindo a porta " + port); //Aguarda conexes while(true) { Socket clie = serv.accept(); //Inicia thread do cliente new ThreadCliente(clie).start(); } } catch(Exception e) {...} } }

Listagem 6. Thread para tratar conexes recebidas pelo servidor class ThreadCliente extends Thread { private Socket cliente; public ThreadCliente(Socket cliente) { this.cliente = cliente; } public void run() { try { //ObjectInputStream para receber o nome do arquivo ObjectInputStream entrada = new ObjectInputStream(cliente.getInputStream()); DataOutputStream saida = new DataOutputStream(cliente.getOutputStream()); //Recebe o nome do arquivo String arquivo = (String)entrada.readObject(); //Buffer de leitura dos bytes do arquivo byte buffer[] = new byte[512]; //Leitura do arquivo solicitado FileInputStream file = new FileInputStream(arquivo); //DataInputStream para processar o arquivo solicitado DataInputStream arq = new DataInputStream(file); saida.flush(); int leitura = arq.read(buffer); //Lendo os bytes do arquivo e enviando para o socket while(leitura != - 1) { if(leitura != - 2) { saida.write(buffer,0,leitura); } leitura = arq.read(buffer); } System.out.println("Cliente atendido com sucesso: " + arquivo + cliente.getRemoteSocketAddress().toString()); entrada.close(); saida.close(); cliente.close(); } catch(Exception e) { System.out.println("Excecao ocorrida na thread: " + e.getMessage()); try { cliente.close(); } catch(Exception ec) {} } } } Listagem 7. Cdigo do boto buscar arquivo presente na aplicao exemplo (Figura 6) private void btnBuscarActionPerformed(java.awt.event.ActionEvent evt) { try { //Cria o Socket para buscar o arquivo no servidor Socket rec = new Socket(txtServidor.getText(),Integer.parseInt(txtPorta.getText()));

//Enviando o nome do arquivo a ser baixado do servidor ObjectOutputStream saida = new ObjectOutputStream(rec.getOutputStream()); saida.writeObject(txtArquivo.getText()); // DataInputStream para processar os bytes recebidos DataInputStream entrada = new DataInputStream(rec.getInputStream()); //FileOuputStream para salvar o arquivo recebido FileOutputStream sarq = new FileOutputStream(txtSaida.getText()); byte[] br = new byte[512]; int leitura = entrada.read(br); while(leitura != -1) { if(leitura != -2) { sarq.write(br,0,leitura); } leitura = entrada.read(br); } saida.close(); entrada.close(); sarq.close(); rec.close(); ImageIcon img = new ImageIcon(txtSaida.getText()); lblImagem.setText(""); lblImagem.setIcon(img); } catch(Exception e) { JOptionPane.showMessageDialog(null,"Exceo:" + e.getMessage(),"Erro",2); } }

Figura 7. Aplicao de exemplo que busca um arquivo JPG no servidor

Figura 8. Mensagens exibidas pela thread do servidor

Leia mais em: Sockets com Java Parte IV http://www.devmedia.com.br/sockets-com-javaparte-iv/9468#ixzz2lOEdlrW5

Sockets com Java Parte V Broadcast Broadcast significa enviar datagram sockets para todos os clientes conectados em uma determinada rede, uma das situaes onde o broadcast aplicado o envio de mensagens de notificao (um exemplo clssico um servidor informando a seus clientes que ir reinicializar). Multicasting Como vimos o broadcast muito til porm o fato de enviar mensagens a todos os clientes da rede em algumas situaes no desejado, pois necessrio o envio de mensagens apenas para um grupo de clientes da rede. Para resolver este problema usamos multicast, uma tcnica que possibilita enviar datagramas para um grupo de clientes conectados na rede. Os clientes da rede interessados em receber estas mensagens devem participar de um grupo de multicasting. O multicast suportado pelo UDP, o que consiste em mais uma diferena em relao ao TCP. Em Java temos a classe MulticastSocket do pacote java.net a qual nos permite trabalhar com multicast. Ela se assemelha bastante com um socket datagram porm com capacidades adicionais como formao de grupos multicast. Os endereos reservados para o multicast esto entre 224.0.0.0 e 239.255.255.255, sendo os endereos com prefixo 239 reservados para uso em intranets. Veja abaixo um exemplo de cliente assinante de multicast. InetAddress addrgrp = InetAddress.getByName("239.0.0.1"); // Cria o Multicast para a porta 12347 que ira permitir ao cliente particicar de um grupo de multicasting MulticastSocket mcs = new MulticastSocket(12347); // Aps a criao do MulticastSocket necessrio utilizar o mtodo joinGroup(InetAddress) para que o MulticastSocket // seja associado ao endereo de multicasting, o que significa fazer a assinatura mcs.joinGroup(addrgrp); // Quando no desejar mais participar do grupo de multicasting, basta executar o mtodo leaveGroup mcs.leaveGroup(addrgrp); Um servidor e um cliente Multicast Vamos montar agora um servidor e um cliente multicast. Neste exemplo temos a seguinte situao: O cliente assina um grupo multicast, no nosso caso 239.0.0.1, a partir deste momento o cliente aguarda por mensagens do servidor;

O servidor envia mensagens multicast para o grupo 239.0.0.1; O cliente recebe a mensagem e a exibe na tela.

Na Listagem 8 temos o cdigo do servidor, o qual envia mensagens para um grupo de clientes e na Listagem 9 temos o cdigo do cliente o qual espera por uma mensagem multicast do servidor. Nas Figuras 9 e 10 temos respectivamente as atividades do servidor e do cliente. Listagem 8. Servidor multicast que envia mensagens para um grupo de clientes public class ServidorMulticast { public static void main(String[] args) { if(args.length != 3) { System.out.println("Digite <endereco multicast> <porta> <mensagem>"); System.exit(0); } try { byte[] b = args[2].getBytes(); InetAddress addr = InetAddress.getByName(args[0]); DatagramSocket ds = new DatagramSocket(); DatagramPacket pkg = new DatagramPacket(b, b.length, Integer.parseInt(args[1])); ds.send(pkg); } catch(Exception e) { System.out.println("Nao foi possivel enviar a mensagem"); } } } Listagem 9. Cliente multicast que aguarda mensagens do servidor public class ClienteMulticast { public static void main(String[] args) { while(true) { try { MulticastSocket mcs = new MulticastSocket(12347); InetAddress grp = InetAddress.getByName("239.0.0.1"); mcs.joinGroup(grp); byte rec[] = new byte[256]; DatagramPacket pkg = new DatagramPacket(rec, rec.length); mcs.receive(pkg); String data = new String(pkg.getData()); System.out.println("Dados recebidos:" + data); } catch(Exception e) { System.out.println("Erro: " + e.getMessage()); } } } }

addr,

pcsocketjmp1fig09.JPG Figura 9. Servidor multicast enviando mensagens aos clientes do grupo 239.0.0.1

pcsocketjmp1fig10.JPG Figura 10. Mensagens de multicast recebidas pelo cliente Referencias Java, guia do programador Peter Jandl Junior, editora Novatec Java, como programar 6 Edio H. M. Deitel e P. J. Deitel, editora Prentice Hall Java network programming 3rd Edition Elliotte Rusty Harold, editora OREILLY

Concluses Desenvolver aplicaes que se comunicam em rede local ou internet hoje uma necessidade crescente. Neste artigo aprendemos a desenvolver este tipo de aplicao usando Java e sockets. Os sockets em Java representam um recurso poderoso para desenvolvimento de aplicaes que podem comunicar-se via rede. Apesar de existirem frameworks que facilitam o desenvolvimento de aplicaes em rede com Java importante ao leitor entender o fundamento da comunicao com sockets que a base para toda e qualquer aplicao que utiliza comunicao em rede. Leia mais em: Sockets com Java Parte V http://www.devmedia.com.br/sockets-com-javaparte-v/9469#ixzz2lOFit2Fx

Anda mungkin juga menyukai