Вы находитесь на странице: 1из 19

Programao de Sockets em Java

Atualmente, a programao em redes de computadores tem se tornado uma regra, deixando de ser apenas uma tecnologia presente em poucos sistemas, mas que vem ganhando espao nos mais diversos tipos de aplicaes. A principal vantagem nesse modelo de programao a capacidade, fsica e lgica, de distribuir operaes computacionalmente pesadas e grandes quantidades de dados e informaes entre diversas mquinas que, trabalhando em conjunto, ocasionam a descentralizao de tarefas. O modelo de programao distribuda, realizada atravs da separao de aplicaes entre servidores (aplicaes que fornecem servios a serem consumidos) e clientes (aplicaes que consomem servios disponibilizados por outras mquinas), foi a principal arquitetura de distribuio nos anos de 1990. Por meio desta arquitetura, houve aumento na confiabilidade e reduo de custos. A confiabilidade tornou-se um fator importante nesta arquitetura, pois, mesmo havendo falha durante um processo em uma determinada mquina, o sistema no se inviabilizava como um todo, e com a utilizao de mquinas mais simples executando servios isoladamente, houve uma grande diminuio nos custos para execuo de operaes por mquinas mais poderosas. Os aplicativos de servidor e cliente so programas que, executados em diferentes mquinas, trocam informaes por meio de redes de computadores. A aplicao cliente capaz de realizar requisies de servios que so providos pela aplicao servidora. Para isso, o consumidor (ou cliente) deve conhecer o fornecedor dos servios (ou servidor) a partir de um endereo alm de ter conhecimento sobre o protocolo pr-estabelecido utilizado para realizar a solicitao. No entanto, pelo fato de haver a necessidade de trocas de mensagens entre as mquinas envolvidas no processo, h um custo e tempo adicional para efetivar essa troca. Outra caracterstica importante que os dispositivos envolvidos na troca de mensagens devem utilizar a mesma linguagem ou protocolo. Em uma rede de computadores h diversos protocolos, organizando regras sobre o modo como so realizadas as comunicaes entre as partes envolvidas em uma comunicao. Um dos principais conjuntos de protocolos na programao de redes de computadores estabelecido pela arquitetura TCP/IP, operando por meio de um software oferecido pelo sistema operacional a partir de uma mquina ligada na rede. A tecnologia Java suporta a troca de bytes entre um cliente e um servidor TCP atravs do estabelecimento de uma conexo entre eles. Pode-se entender uma conexo como uma ligao direta realizada entre dois processos, na qual dados podem fluir nos dois sentidos. Para estabelecer uma conexo TCP, as extremidades das mquinas envolvidas nos processos de servidor e cliente devem ser identificadas. As extremidades dessa conexo so denominadas de sockets ou soquetes, identificados por um endereo de rede e um nmero de porta.

Neste artigo, voc ir aprender os conceitos de computao distribuda por meio de sockets utilizando a tecnologia Java, bem como aplicar todo o conhecimento adquirido, facilitando assim o desenvolvimento e comunicao de aplicaes cliente-servidor. O que so sockets? Socket ou soquete apenas um conceito ou uma abstrao. O termo socket utilizado para representar um ponto de conexo para uma rede de computadores que utiliza o protocolo TCP/IP. Quando dois computadores necessitam manter uma comunicao, cada um deles utiliza um socket. Um computador, denominado server ou servidor, disponibiliza um socket e aguarda o recebimento de uma solicitao de conexo, enquanto outro computador, denominado client ou cliente, executa um socket para se comunicar mquina servidora, conforme demonstrado na Figura 1. Para estabelecer uma nova conexo, necessrio apenas um endereo de destino e um nmero de porta. Caso no ocorra nenhum problema, o servidor aceita a conexo gerando um novo socket em uma porta qualquer do seu lado, criando assim um canal de comunicao entre o cliente e o servidor. A Figura 2 demonstra esse canal de comunicao. Cada computador em uma rede TCP/IP possui um endereo exclusivo. As portas representam conexes individuais dentro desse endereo, porm os dados transmitidos passam por um processo de roteamento dentro de cada computador a partir de um nmero da porta. Quando um socket criado, ele necessita estar associado a uma determinada porta e deve haver apenas um socket associado a essa porta. A principal caracterstica de uma mquina servidora a de receber e manipular conexes a partir de solicitaes dos clientes, portanto, seu comportamento tpico o de permanecer em loop aguardando novas conexes e criando sockets com a finalidade de atender as requisies dos clientes, conforme demonstrado na Figura 3.

Figura 1.

Socket de servidor aguardando conexes.

Figura 2.

Canal de comunicao criado aps conexo de cliente ser recebida.

Figura 3.

Aplicao cliente-servidor baseada em conexes.

Sockets em Java Assim como todas as outras funcionalidades fornecidas pela tecnologia Java, existe um pacote especfico que contm os mecanismos necessrios para se trabalhar com sockets: o pacote java.net. O pacote java.net contm todas as classes necessrias para criar aplicaes de rede. As classes ServerSocket e Socket tambm fazem parte desse pacote e so utilizadas para aplicaes que fazem uso do protocolo TCP. Alm dessas classes, tambm existem outras para conexo com servidores web, criao de secure sockets ou sockets seguros, entre outras funcionalidades.

Para mais informaes, veja a seo Modos de transmisso de sockets. A classe ServerSocket responsvel pela manipulao de sockets do lado do servidor. Por meio dela, possvel disponibilizar um socket para receber conexes e manipular um novo socket quando uma requisio de conexo realizada. Uma vez que uma requisio de conexo realizada, o socket de servidor criar um novo socket para que seja possvel manter uma conexo direta com o cliente que requisitou o canal de comunicao. A classe Socket responsvel pela manipulao de sockets do lado do cliente. Utilizando-se um socket desse tipo, possvel realizar a solicitao de conexo com um socket fornecido por um servidor, desde que este esteja aguardando uma requisio por meio de uma porta previamente disponibilizada. O estabelecimento da conexo entre duas aplicaes d-se por meio da instanciao de um objeto da classe Socket, a partir do processo cliente. Uma vez que a conexo entre o cliente e servidor tenha sido estabelecida pela criao dos correspondentes sockets, os dados da aplicao podem fluir atravs de streams a ela associados. Quando h a necessidade de utilizao do protocolo UDP, deve-se utilizar as classes DatagramSocket e DatagramPacket tambm presentes no pacote java.net. A classe DatagramSocket responsvel pelo envio e recebimento de datagramas. Utiliza-se esse tipo de socket tanto para aplicaes servidoras quanto para clientes. Como no h controle da sequncia de envio e recebimento de datagramas, mltiplos pacotes enviados de uma mquina a outra podem ser roteados de forma diferente e at chegar em ordens diferentes, alm de que a entrega de pacotes no garantida. A classe DatagramPacket responsvel pela insero de dados na forma de bytes em um pacote UDP denominado datagrama. Os pacotes de datagramas so utilizados para implementar um servio de entrega de pacotes sem conexo. Cada mensagem roteada da mquina remetente at a destinatria baseandose na informao contida dentro do datagrama.
Nota Devman 1: Datagrams ou Datagramas: Um datagrama , em uma rede de computadores, uma estrutura unitria utilizada para transmitir uma sequncia de dados em um canal de comunicao que utilize a comutao de pacotes. Uma informao a ser transmitida geralmente quebrada em inmeros pacotes, facilitando e agilizando seu envio pela rede. Juntamente com a informao, o datagrama possui um cabealho, contendo informaes que auxiliam sua transmisso, como os endereos do destinatrio e remetente, soma para checagem de erros (checksum), definio de prioridades, entre outros dados.

Modos de transmisso de sockets A tecnologia de sockets permite o desenvolvimento de aplicaes distribudas a partir de dois modos principais de operao: o modo baseado em conexes e o modo sem conexo. Analogicamente, possvel comparar o modo baseado em conexes com um telefone; eles tm de estabelecer uma conexo e suspender a ligao. Todos os dados que fluem entre esses dois eventos chegam na mesma ordem em que foram transmitidos. Entretanto, os sockets no orientados a conexo podem ser comparados ao sistema de correios, onde a entrega no garantida, e os diferentes itens de correspondncia podem chegar em uma ordem diferente daquela em que foram enviados.

A escolha do modo a ser utilizado determinada a partir das necessidades de uma aplicao distribuda. Caso a confirmao de entrega e a sequncia de dados sejam importantes, ento a operao baseada em conexes , sem dvidas, a melhor opo. Por exemplo, os servidores de arquivos precisam fazer todos os seus dados chegarem corretamente e em sequncia. Se alguma parte dos dados se perdesse, a utilidade da aplicao servidora seria invalidada. Porm, o processo realizado pelas aplicaes para garantir a sequncia e a correo dos dados exigem processamento extra e maior utilizao da memria, ocasionando uma reduo no tempo de resposta de um servidor. O modo baseado em conexes utiliza o TCP ou Transport Control Protocol para se estabelecer uma conexo com o dispositivo de destino antes de transmitir os dados. Assim que a conexo for estabelecida, os sockets so acessados por uma interface de fluxo de dados, representando as operaes de: abertura, leitura, escrita e fechamento. Por meio dessa conexo, tudo que enviado por um socket recebido pela outra extremidade da conexo, na mesma ordem em que foi transmitido. Apesar de a operao baseada em conexes ser menos eficiente, pelo tempo extra de processamento e resposta, do que a operao sem conexo, ela mais garantida e confivel. O modo sem conexo utiliza o UDP ou User Datagram Protocol. O termo datagram ou datagrama utilizado para determinar uma unidade autnoma que possui todas as informaes necessrias para tentar realizar sua entrega. Analogicamente, um datagrama possui as mesmas caractersticas que um envelope, pois possui os endereos de destinatrio e remetente alm de conter em seu interior os dados a serem transmitidos. Um socket nesse modo de operao no necessita estabelecer uma conexo com um socket de destino; ele simplesmente envia o datagrama. Caso o dispositivo de destino esteja esperando o datagrama, ele o recebe; caso contrrio, o datagrama perdido. A operao sem conexo rpida e eficiente, porm no garante a entrega nem a ordem dos dados. Um pouco sobre streams... Em Java, utiliza-se o termo stream para conceituar quase todas as operaes que se baseiam nas mais diferentes formas de se realizar a leitura e escrita de dados a partir das mais diversas fontes e para os mais diferentes destinos. Uma stream uma abstrao que representa uma fonte genrica de entrada de dados ou um destino genrico para escrita de dados, de acesso sequencial e independente de dispositivos fsicos, formatos e at mesmo de mecanismos de otimizao de leitura e escrita. Por ser uma abstrao, deve sempre ser associada a uma entidade fsica de suporte a dados, como um disco rgido, um CD-ROM, um DVD-ROM, outro computador da rede, entre outros dispositivos. A Figura 4 exemplifica o uso de streams.

Figura 4.

Streams como abstrao de leitura e escrita.

Para que seja possvel ler uma determinada informao, um programa abre uma stream sobre uma fonte de dados, por exemplo, um socket, e l essa informao sequencialmente, byte a byte ou caractere a caractere. Inversamente, um programa pode enviar informao para um destino externo abrindo uma stream de escrita e escrevendo dados de modo sequencial no fluxo de informaes. Para a leitura sequencial de bytes utiliza-se um objeto da classe InputStream, obtido como retorno do mtodo getInputStream(). Para transferncia de texto, a ponte DataInputStream pode ser utilizada para usar um reader. Similarmente, para a transferncia de dados no sentido deste socket para o outro extremo da conexo, utiliza-se um objeto da classe OutputStream. Para transferncia de texto neste sentido, a ponte utilizada DataOutputStream, permitindo a obteno de um writer associado a esse stream. Desenvolvimento de sockets TCP Conforme apresentado anteriormente, sockets TCP ou orientado a conexes so altamente utilizados quando se necessita de confirmao de conexo entre o cliente e o servidor para que seja possvel a transmisso correta e confivel de dados. Para essa comunicao, tambm se torna necessria a definio de um fluxo de dados, para que os dados sejam enviados e recebidos sequencialmente, garantindo o sucesso da operao. Implementao de socket TCP de servidor A principal funcionalidade do socket do lado do servidor a de aguardar por solicitaes de conexes e, aps serem requeridas, trat-las e servi-las. Para realizar a implementao de um socket de servidor, existem alguns passos a serem seguidos: 1. Estabelecer um socket de servidor que monitore uma determinada porta para receber conexes. Para isso, deve-se criar uma instncia da classe ServerSocket, seguindo uma das quatro maneiras possveis: a. ServerSocket() - Simplesmente cria uma instncia de ServerSocket conforme sua implementao nativa do Java, buscando os valores padres;

b. ServerSocket(int porta) - Cria uma instncia de ServerSocket e vincula o socket a uma determinada porta; c. ServerSocket(int porta, int backlog) - Alm de criar uma instncia de ServerSocket e vinculla a uma determinada porta, tambm define o tamanho da fila de requisies; d. ServerSocket(int porta, int backlog, InetAddress endereco) - Cria uma instncia de ServerSocket, vincula-a a uma determinada porta estabelecendo o tamanho da fila de requisies e associa-a ao endereo InetAddress passado como parmetro. ServerSocket server = new ServerSocket(1234); 2. A prxima etapa determinar a criao de uma socket assim que uma requisio de conexo for realizada. Para isso, deve-se recuperar a instncia de Socket utilizando-se o mtodo accept() do socket do servidor; Socket socket = server.accept(); 3. Aceitando a requisio de conexo vinda de um cliente e tendo recuperado o socket por meio do mtodo accept(), deve-se criar um canal de comunicao direita entre o servidor e o cliente. Para ser possvel receber dados pelo canal de comunicao, recupera-se uma instncia de DataInputStream do socket do cliente por meio do mtodo getInputStream(). Para ser possvel enviar dados pelo canal de comunicao, recupera-se uma instncia de DataOutputStream do socket recuperado durante a conexo por meio do mtodo getOutputStream(). DataInputStream dis = new DataInputStream (socket.getInputStream()); DataOutputStream dos = new DataOutputStream (socket.getOutputStream()); 4. Utilizando-se essas duas instncias do socket recuperado e invocando os mtodos necessrios, j possvel receber e enviar dados de diversos tipos como boolean, byte, char, double, float, int, long, short e cadeias de caracteres por meio de UTF (Unicode Transformation Format). Para exemplificar segue, respectivamente, as codificaes para recebimento e envio de dados UTF, utilizando-se os mtodos readUTF() e writeUTF(); String mensagem = dis.readUTF(); dos.writeUTF(mensagem); 5. Assim que todo o processo de requisio e processamento com o cliente for concludo, o servidor deve encerrar os canais de comunicao utilizando-se o mtodo close() das instncias de DataInputStream e DataOutputStream, assim como a instncia do socket do cliente e tambm do socket do servidor.

dis.close(); dos.close(); socket.close(); server.close(); A Listagem 1 apresenta uma implementao de socket TCP de servidor. Em resumo, criada uma instncia de ServerSocket, aguardando conexes na porta 1234. Assim que uma nova conexo solicitada a esse servidor, um socket de cliente recuperado pelo mtodo accept(). Por meio do socket recuperado, obtm-se uma instncia para controlar o fluxo de dados para recebimento de dados (DataInputStream) e outra para o envio de dados (DataOutputStream). Utilizando-se o mtodo readUTF() aguardamos o recebimento de uma string pelo canal de comunicao que, em seguida, exibido no console Java. Em resposta, o servidor envia outra cadeia de caracteres pelo canal de comunicao por meio do mtodo writeUTF() e encerra tanto as instncias de controle de dados stream como os sockets por meio do mtodo close().
package servidor; import import import import import java.io.DataInputStream; java.io.DataOutputStream; java.net.ServerSocket; java.net.Socket; java.util.Date;

public class SocketServidor { private static final int PORTA = 1234; public static void main(String[] args) { try { ServerSocket server = new ServerSocket(PORTA); Socket socket = server.accept(); DataInputStream dis = new DataInputStream (socket.getInputStream()); DataOutputStream dos = new DataOutputStream (socket.getOutputStream()); String mensagem = dis.readUTF(); System.out.println("Servidor: Mensagem recebida => \"" + mensagem + "\""); mensagem = "Mensagem recebida com sucesso s " + new Date(); System.out.println("Servidor: Mensagem enviada => \"" + mensagem + "\""); dos.writeUTF(mensagem); dis.close(); dos.close(); socket.close(); server.close(); } catch (Exception ex) { /* tratar exceo */ } } }

Listagem 1. SocketServidor.java: Implementao de socket TCP de servidor Tendo desenvolvido a aplicao do lado do servidor, basta implementar a aplicao do lado do cliente, responsvel por conectar-se ao socket e realizar as requisies de envio e recebimento de dados. UTF ou Unicode Transformation Format: um padro estabelecido pela Unicode Consortium que permite aos computadores representar e manipular, de maneira consistente, textos de qualquer escrita existente, sendo tambm compatvel com o ASCII.

Implementao de socket TCP de cliente O principal objetivo do socket do lado do cliente o de solicitar uma conexo com um socket de servidor e comunicar-se por meio de um canal de comunicao estabelecido logo aps a requisio de conexo. A implementao de uma aplicao cliente baseada em conexes pode ser realizada seguindo as instrues: 1. O primeiro passo solicitar a conexo com um servidor, seguindo uma das duas maneiras disponveis: a. Criando uma instncia de Socket. Para isso, deve-se informar apenas o nome ou IP do host de conexo e a porta disponibilizada pelo socket de servidor. Para criar uma instncia de Socket, necessrio utilizar um dos sete construtores disponveis na classe Socket, sendo os mais usados: Socket() - Simplesmente cria uma instncia de Socket conforme sua implementao nativa do Java, buscando os valores padres; Socket(InetAddress endereco, int porta) - Cria uma instncia de Socket, conectando-se a um endereo especfico e a uma determinada porta; Socket(String host, int porta) - Cria uma instncia de Socket, conectando-se a um host especfico e a uma determinada porta. Socket socket = new Socket(127.0.0.1, 1234); b. Conectando ao servidor sem a passagem de parmetros durante a instanciao de Socket. Neste caso, torna-se necessrio utilizar a classe SocketAddress. Socket socket = new Socket(); socket.connect(new SocketAddress(127.0.0.1, 1234)); 2. A criao das instncias de manipulao de stream do lado do cliente exatamente igual a do servidor. Para ser possvel receber dados pelo canal de comunicao, recupera-se uma instncia de DataInputStream do socket recuperado por meio do mtodo getInputStream(). Para ser possvel enviar dados pelo canal de comunicao, recupera-se uma instncia de DataOutputStream do socket do cliente durante a conexo por meio do mtodo getOutputStream(). DataInputStream dis = new DataInputStream (socket.getInputStream()); DataOutputStream dos = new DataOutputStream (socket.getOutputStream()); 3. Utilizando-se as instncias de entrada e sada de dados do canal de comunicao, recuperados a partir do socket conectado, j possvel receber e enviar informaes de

diversos tipos. Para exemplificar segue, respectivamente, as instrues utilizadas para recebimento e envio de dados UTF, por meio dos mtodos readUTF() e writeUTF(): String mensagem = dis.readUTF(); dos.writeUTF(mensagem); 4. Assim que todo o processo de requisio e processamento com o cliente for concludo, o servidor deve encerrar os canais de comunicao utilizando-se o mtodo close() das instncias de DataInputStream e DataOutputStream, bem como finalizar as instncias dos sockets do cliente e do servidor. dis.close(); dos.close(); socket.close(); server.close(); A Listagem 2 apresenta uma implementao de socket TCP de cliente. Um socket de cliente criado e tenta conectar-se ao endereo 127.0.0.1 por meio da porta 1234. Utiliza-se o endereo 127.0.0.1 ou localhost quando se deseja realizar testes de conexo na mquina local, funcionando tanto como servidor como cliente. Caso o servidor esteja sendo executado em alguma outra mquina na rede, necessita-se recuperar o IP da mquina e troc-lo na aplicao desenvolvida. Assim que o socket da aplicao cliente obter sucesso na conexo com o socket da aplicao servidora, necessrio obter uma instncia para controlar o fluxo de dados para recebimento de dados (DataInputStream) e outra para o envio de dados (DataOutputStream). Utilizando-se o mtodo writeUTF() possvel enviar uma string pelo canal de comunicao criado entre o cliente e o servidor. Aps o envio da cadeia de caracteres da aplicao cliente para a aplicao servidora, utiliza-se o mtodo readUTF() para fazer com que a aplicao aguarde o recebimento de dados pelo canal de comunicao. Assim que uma string for transmitida em resposta pelo servidor, ela ser exibida no console Java. Ao final do fluxo de dados e do processamento, encerram-se tanto as instncias de controle de dados stream como os sockets atravs do mtodo close().
package cliente; import import import import java.io.DataInputStream; java.io.DataOutputStream; java.net.Socket; java.util.Date;

public class SocketCliente { private static final String HOST = "127.0.0.1"; private static final int PORTA = 1234; public static void main(String[] args) { try { Socket socket = new Socket(HOST, PORTA); DataInputStream dis = new DataInputStream (socket.getInputStream()); DataOutputStream dos = new DataOutputStream (socket.getOutputStream()); String mensagem = "Conectado s " + new Date(); System.out.println("Cliente: Mensagem enviada => \"" + mensagem + "\"");

dos.writeUTF(mensagem); mensagem = dis.readUTF(); System.out.println("Cliente: Mensagem recebida => \"" + mensagem + "\""); dis.close(); dos.close(); socket.close(); } catch (Exception ex) { /* tratar exceo */ } } }

Listagem 2. SocketCliente.java: Implementao de socket TCP de cliente.

Aps o desenvolvimento do servidor, conforme Listagem 1, e do cliente, demonstrado na Listagem 2, possvel testar a comunicao entre essas duas aplicaes. Para isso, deve-se executar, primeiramente, o servidor e, logo em seguida, o cliente. Assim que a conexo for estabelecida com sucesso, os aplicativos Java sero capazes de enviar e receber mensagens na forma de string pelo canal de comunicao criado por meio dos sockets de rede. Desenvolvimento de sockets UDP Conforme apresentado anteriormente, sockets UDP ou no orientado a conexes so utilizados quando no h a necessidade de estabelecer uma conexo entre a mquina cliente e a servidora. Um socket UDP envia um datagram ou datagrama que, similar a um envelope, contm informaes sobre o destinatrio, remetente e os dados a serem enviados. Comparado ao modelo orientado a conexo, o protocolo UDP mais rpido e eficiente, porm a entrega e sequncia das informaes no garantida ou confirmada, cabendo ao programa se responsabilizar pela validao e segurana. Com um socket UDP, caso o destinatrio no esteja aguardando uma mensagem, ela perdida. A Figura 5 demonstra o envio de um datagrama por meio de um socket. O cabealho UDP extremamente simples, contendo apenas os nmeros das portas de origem e destino, comprimento da mensagem e checksum, um campo utilizado para conferncia da integridade dos dados transmitidos. Os campos em laranja, exibidos na Figura 5, so opcionais.

Figura 5. Envio de datagrama por socket UDP.

Para o desenvolvimento de aplicaes que fazem uso do protocolo UDP, a tecnologia Java conta com as classes DatagramSocket e DatagramPacket, presentes no pacote java.net, assim como as classes ServerSocket e Socket. Ao contrrio da classe Socket, um DatagramSocket no estabelece uma conexo com uma mquina remota, porm necessita apenas de uma conexo local com a rede de computadores para que seja possvel enviar e receber pacotes. Os pacotes enviados e recebidos por meio de sockets UDP so instncias da classe DatagramPacket, contendo informaes sobre o remetente e destinatrio e os dados a serem transmitidos. Implementao de socket UDP de servidor A implementao de sockets que utilizam o protocolo UDP realizada por meio de instncias de DatagramSocket e DatagramPacket. Utilizando-se uma instncia de DatagramSocket, possvel determinar qual porta ser reservada para o envio e recebimento de dados na forma de pacotes, enquanto a de DatagramPacket utilizada para a montagem de uma datagrama a ser enviado, informando-se o host e porta do cliente, e at mesmo para aguardar informaes transmitidas por outros sockets UDP. Para o desenvolvimento de sockets UDP, existem alguns passos a serem seguidos: 1. Estabelecer um socket de datagrama que disponibilize uma porta para as operaes de envio e recebimento de dados. Para isso, deve-se criar uma instncia de DatagramSocket, conforme apresentado a seguir: a. DatagramSocket(int porta) - Cria uma instncia de DatagramSocket e vincula o socket a uma determinar porta, pela qual sero realizados o envio e recebimento de informaes. DatagramSocket datagramSocket = new DatagramSocket(1234); 2. Recuperar uma instncia de InetAddress, responsvel por armazenar o host a ser utilizado no processo de envio de datagramas. Para isso, deve-se criar uma instncia de InetAddress utilizando-se getByName() desta mesma classe, informando, como parmetro, uma string com o nome ou IP do host; InetAddress address = InetAddress. getByName(127.0.0.1); 3. Preparar um arranjo (array) de bytes, com tamanho pr-definido, a ser utilizado como buffer durante a troca de dados; byte[] buffer = new byte[1024]; 4. Criar uma instncia de DatagramPacket, responsvel por ser um datagrama de envio e recebimento de dados. A classe DatagramPacket pode ser instanciada de duas formas:

a. DatagramPacket(byte[] buffer, int tamanho) - Cria uma instncia de DatagramPacket utilizada para o recebimento de dados. As informaes recuperadas sero armazenadas em um arranjo de bytes, passado como parmetro do construtor, juntamente com o tamanho determinado; DatagramPacket datagramPacket = new Datagram Packet(buffer, buffer.length); b. DatagramPacket(byte[] buffer, int tamanho, InetAddress endereo, int porta) - Cria uma instncia de DatagramPacket utilizada para o envio de dados. Os dados a serem transmitidos devem ser transformados em um arranjo de bytes por meio do mtodo getBytes() da classe String. O arranjo de bytes passado como parmetro do construtor da classe DatagramPacket. String mensagem = "Mensagem recebida com sucesso s " + new Date(); buffer = mensagem.getBytes(); DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length, address, 1235); 5. Possuindo as instncias de DatagramSocket e DatagramPacket, torna-se possvel realizar as operaes de envio e recebimento de dados. Conforme mencionado anteriormente, utiliza-se as mesmas instncias para as duas tarefas. a. Para o recebimento de dados, utiliza-se o mtodo receive(DatagramPacket datagrama), invocado a partir da instncia de DatagramSocket. Em seguida, deve-se recuperar os bytes transmitidos, utilizando-se o mtodo getData() e transform-los em uma cadeia de caracteres, passando o arranjo de bytes como parmetro do construtor da classe String. datagramSocket.receive(datagramPacket); buffer = datagramPacket.getData(); String mensagem = new String(buffer); b. Para o envio de dados, utiliza-se o mtodo send(DatagramPacket datagrama), invocado a partir da instncia de DatagramSocket. datagramSocket.send(datagramPacket); 6. Aps o processamento das operaes, deve-se concluir a aplicao encerrando o datagrama por meio do mtodo close(). datagramSocket.close(); A Listagem 3 apresenta uma implementao de socket UDP de servidor.

O objetivo desta aplicao aguardar o recebimento de um datagrama por uma porta e, logo em seguida, enviar um novo datagrama para uma mquina por meio de um host e de uma porta, sem a necessidade de se estabelecer uma conexo.
package servidor; import import import import java.net.DatagramPacket; java.net.DatagramSocket; java.net.InetAddress; java.util.Date;

public class SocketServidor { private private private private static static static static final String HOST = "127.0.0.1"; final int PORTA_SERVIDOR = 1234; final int PORTA_CLIENTE = 1235; int BUFFER_LENGTH = 1024;

public static void main(String[] args) { try { DatagramSocket datagramSocket = new DatagramSocket(PORTA_SERVIDOR); InetAddress address = InetAddress.getByName(HOST); byte[] buffer = new byte[BUFFER_LENGTH]; DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length); datagramSocket.receive(datagramPacket); buffer = datagramPacket.getData(); String mensagem = new String(buffer); System.out.println("Servidor: Mensagem recebida => \"" + mensagem + "\""); mensagem = "Mensagem recebida com sucesso s " + new Date(); System.out.println("Servidor: Mensagem enviada => \"" + mensagem + "\""); buffer = mensagem.getBytes(); datagramPacket = new DatagramPacket (buffer, buffer.length, address, PORTA_CLIENTE); datagramSocket.send(datagramPacket); datagramSocket.close(); } catch (Exception ex) { System.out.println(ex.getMessage()); } } }

Listagem 3. SocketServidor.java: Implementao de socket UDP de servidor.

Tendo desenvolvido a aplicao do lado do servidor, basta implementar a aplicao do lado do cliente, responsvel por aguardar o recebimento de dados e transmitir um datagrama de resposta. Implementao de socket UDP de cliente Conforme informado anteriormente, tanto a aplicao servidora quanto a cliente so implementadas por meio de instncias de DatagramSocket e DatagramPacket. Portanto, a aplicao cliente ser desenvolvida utilizando-se os mesmos conceitos j apresentados. A Listagem 4 apresenta uma implementao de socket UDP de cliente.
package cliente; import import import import java.net.DatagramPacket; java.net.DatagramSocket; java.net.InetAddress; java.util.Date;

public class SocketCliente { private private private private static static static static final String HOST = "127.0.0.1"; final int PORTA_SERVIDOR = 1234; final int PORTA_CLIENTE = 1235; int BUFFER_LENGTH = 1024;

public static void main(String[] args) { try { DatagramSocket datagramSocket = new DatagramSocket(PORTA_CLIENTE); InetAddress address = InetAddress.getByName(HOST); String mensagem = "Conectado s " + new Date(); System.out.println("Cliente: Mensagem enviada => \"" + mensagem + "\""); byte[] buffer = mensagem.getBytes(); DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length, address, PORTA_SERVIDOR); datagramSocket.send(datagramPacket); buffer = new byte[BUFFER_LENGTH]; datagramPacket = new DatagramPacket (buffer, buffer.length); datagramSocket.receive(datagramPacket); buffer = datagramPacket.getData(); mensagem = new String(buffer); System.out.println("Cliente: Mensagem recebida => \"" + mensagem + "\""); datagramSocket.close(); } catch (Exception ex) { System.out.println(ex.getMessage()); } } }

Listagem 4. SocketCliente.java: Implementao de socket UDP de cliente. O objetivo desta aplicao preparar uma mensagem para ser enviada por um datagrama para um determinado host e porta e aguardar o recebimento de dados por meio de uma porta disponibilizada pela aplicao, sem a necessidade de se estabelecer uma conexo. Com os exemplos das Listagens 3 e 4 pode-se perceber que, utilizando-se sockets no modo UDP, a aplicao no necessita estabelecer uma conexo entre as mquinas, portanto, tambm no possvel garantir a entrega e a sequncia correta de dados, j que nem sempre a mquina destinatria pode estar preparada para receber informaes enviadas pela mquina remetente. O modo sem conexo (ou UDP) muito mais rpido do que o modo baseado em conexes (ou TCP) pelo fato de no fazer verificaes e por no estabelecer sesses entre mquinas. Desenvolvimento de sockets para transmisso e recebimento de arquivos A tecnologia de Sockets em Java tambm permite no s a troca de informaes por canais de comunicao, mas tambm o compartilhamento de arquivos lgicos como textos, imagens, vdeos, entre outros formatos de dados. Para implementar uma arquitetura capaz de transmitir e receber arquivos, necessrio utilizar duas classes j apresentadas: ServerSocket e Socket. Por meio dessas classes, estabelece-se uma conexo e um canal de comunicao, por onde sero transmitidas as informaes. Em resumo, para o servidor transmitir um arquivo, necessita-se passar por um processo de transformao de arquivo lgico para um arranjo de bytes. Para o cliente, receptor do arquivo, o processo ocorre de maneira contrria, transformando-se o arranjo de bytes em arquivo lgico. Implementao de socket de servidor para transmisso de arquivos

Conforme informado anteriormente, a classe ServerSocket tambm pode ser utilizada para transmitir arquivos lgicos como textos e imagens. A diferena se d pelo fato de que o arquivo necessita passar por um processo de decodificao, sendo transformado em um arranjo de bytes, utilizando-se o mtodo read() de uma instncia de BufferedInputStream. Aps essa transformao, a informao pode ser transmitida assim como qualquer outro tipo de dado, por meio do mtodo write() de uma instncia de DataOutputStream. A Figura 6 ilustra o arquivo a ser transmitido pela aplicao servidora. A Listagem 5 apresenta uma implementao de socket de servidor que disponibiliza a transmisso de um arquivo de imagem. O objetivo desta aplicao preparar um arquivo para ser enviado assim que uma conexo for estabelecida.

Figura 6. Logotipo Google Android


package servidor; import import import import import import java.io.BufferedInputStream; java.io.DataOutputStream; java.io.File; java.io.FileInputStream; java.net.ServerSocket; java.net.Socket;

public class SocketServidor { private static final int PORTA = 1234; public static void main(String[] args) { try { ServerSocket server = new ServerSocket(PORTA); Socket socket = server.accept(); DataOutputStream dos = new DataOutputStream (socket.getOutputStream()); File arquivo = new File("C:\\Users\\ Guilherme\\Desktop\\android.gif"); byte[] buffer = new byte[(int) arquivo.length()]; FileInputStream fis = new FileInputStream(arquivo); BufferedInputStream bis = new BufferedInputStream(fis); bis.read(buffer, 0, buffer.length); System.out.println("Enviando arquivo \"" + arquivo.getName() + "\""); dos.write(buffer, 0, buffer.length); dos.flush(); dos.close(); socket.close(); server.close(); } catch (Exception ex) { System.out.println(ex.getMessage());

} } }

Listagem 5. SocketServidor.java: Implementao de socket de servidor para transmisso de arquivos. Tendo desenvolvido a aplicao do lado do servidor, basta implementar a aplicao do lado do cliente, responsvel por conectar-se ao socket e realizar as requisies de recebimento de dados e transformao do arranjo de bytes em um arquivo lgico. Implementao de socket de cliente para recebimento de arquivos Conforme informado anteriormente, a classe Socket tambm pode ser utilizada para receber arquivos transmitidos por um servidor utilizando-se um canal de comunicao. A informao recebida, por meio do mtodo read() de uma instncia de DataInputStream, um arranjo de bytes e para se tornar um arquivo legvel deve passar por um processo de transformao. O processo de transformao ocorre de maneira simples, onde os bytes so lidos no canal de comunicao e, ao final da leitura, utiliza-se o mtodo write() de uma instncia de BufferedOutputStream para escrever as informaes lidas em um arquivo lgico dentro de um diretrio informado. A Listagem 6 apresenta uma implementao de socket de cliente que aguarda o recebimento de um arquivo de imagem. O objetivo desta aplicao , alm de receber informaes no formato de bytes, transformar os dados recebidos e armazenar o arquivo final em um diretrio especificado no cdigo-fonte.
package cliente; import import import import java.io.BufferedOutputStream; java.io.DataInputStream; java.io.FileOutputStream; java.net.Socket;

public class SocketCliente { private static final String HOST = "127.0.0.1"; private static final int PORTA = 1234; private static final int FILE_SIZE = 6022386; public static void main(String[] args) { try { Socket socket = new Socket(HOST, PORTA); DataInputStream dis = new DataInputStream (socket.getInputStream()); byte[] mybytearray = new byte[FILE_SIZE]; FileOutputStream fos = new FileOutputStream ("C:\\Users\\Guilherme\\Desktop\\android_copy.gif"); BufferedOutputStream bos = new BufferedOutputStream(fos); int bytesRead = dis.read(mybytearray, 0, mybytearray.length); int current = bytesRead; do { bytesRead = dis.read(mybytearray, current, (mybytearray.length - current)); if (bytesRead >= 0) { current += bytesRead; } } while (bytesRead > -1); bos.write(mybytearray, 0, current); System.out.println("Arquivo recebido com sucesso!"); bos.flush(); bos.close(); socket.close(); } catch (Exception ex) { System.out.println(ex.getMessage()); } } }

Listagem 6. SocketCliente.java: Implementao de socket de cliente para recebimento de arquivos. Com o desenvolvimento das aplicaes cliente e servidor das Listagens 5 e 6 foi possvel perceber a facilidade e praticidade quando se deseja compartilhar arquivos entre processos executados em mquinas diferentes por meio de sockets TCP. Esta ideia pode ser modificada para aplicativos que gerenciam relatrios, grficos, imagens e outros documentos onde o processamento pode ou deve permanecer isolado apenas em uma mquina responsvel por prover servios solicitados pelos clientes. Concluso O conceito de computao distribuda no recente e nem to pouco utilizada, estando presente em quase todos os locais e situaes, porm o tema, por muitas vezes, no recebe a importncia devida, seja no ambiente acadmico ou corporativo, cabendo aos desenvolvedores e analistas realizar pesquisas em tecnologias antes ignoradas. Graas ao aumento da necessidade e crescente uso da rede de computadores, principalmente pela popularizao da Internet, tornou-se necessrio adaptar o processo de desenvolvimento de software para que as aplicaes trabalhem de maneira distribuda e descentralizada. Este artigo apresentou os conceitos e mecanismos utilizados para a implementao de aplicativos que fazem uso de redes de computadores para a troca de informaes e processamento de dados. A tecnologia Java nos prov classes e interfaces adequadas para a implementao de aplicaes que, por meio de um canal de comunicao, possam enviar e receber dados de diversos tipos, facilitando o desenvolvimento de projetos baseados na arquitetura distribuda. Alm dos conceitos e do embasamento terico, o artigo apresentou, de forma didtica, alguns exemplos de aplicaes que fazem uso de classes relacionadas ao desenvolvimento com sockets, demonstrando que no necessrio possuir conhecimentos sobre detalhes da implementao de algoritmos ou hardware de rede para produzir aplicaes distribudas em Java. O que foi abordado neste artigo apenas uma breve amostra de como a tecnologia de sockets pode auxiliar no desenvolvimento de aplicaes Java, incorporando caractersticas da computao distribuda no desenvolvendo de software. H muito ainda a ser explorado sobre essa tecnologia pouco comentada, porm muito utilizada, criando a possibilidade de novos artigos e trabalhos relacionados. LINKS 1. http://download.oracle.com/javase/tutorial/networking/sockets/ Pgina oficial da Oracle (Sun) sobre sockets em Java. 2. http://java.sun.com/developer/technicalArticles/ALT/sockets/ Pgina oficial da Oracle (Sun) sobre programao avanada de sockets. 3. http://www.oracle.com/technetwork/java/socket-140484.html

Tutorial oficial da Oracle (Sun) sobre desenvolvimento de aplicaes distribudas baseadas em sockets. 4. http://www.javaworld.com/javaworld/jw-12-1996/jw-12-sockets.html Artigo sobre desenvolvimento de sockets em Java da InfoWorld - Java World. 5. http://www.devarticles.com/c/a/Java/Socket-Programming-in-Java/ Artigo sobre desenvolvimento de sockets em Java da DevArticles.

Autor: GUILHERME DE CLEVA FARTO, Revista Easy Java Magazine, Edio 6, 2011.