Usando Sockets

em 19/08/2003 , por Leandro de Camargo Araujo Lima
Sockets. O que são, pra que servem e como funcionam
A estrutura Socket foi uma inovação apresentada pelo sistema Berkeley Unix. Através desta estrutura, o programador por ler e gravar bytes como uma stream qualquer de dados. Além disto, ?esconde? os detalhes de baixo nível das redes tais como tipo de transmissão, tamanho de pacote, retransmissão e etc. Através de um socket podemos realizar várias operações, como exemplo:
  • Estabelecer conexões entre máquinas
  • Enviar e receber dados
  • Encerrar conexões
  • Esperar por conexões em determinada porta O socket é na verdade um elemento de software que provê uma interface de rede para a aplicação. Vamos tratar dos sockets TCP, porém Java permite a utilização de sockets UDP e fornece meios para que você possa utilizar outros tipos não definidos através da classe SocketImpl e da interface SocketImplFactory.
    Onde estão? Quem são?
    Os sockets estão localizados no pacote java.net. Basicamente precisamos das classes Socket e ServerSocket para conseguir implementar uma aplicação básica. A classe Socket implementa o socket cliente. Para construir um socket precisamos saber qual é o IP que desejamos conectar e a porta de conexão (que varia de 0 a 65535). A classe ServerSocket fornece a interface de rede necessária para que a aplicação possa funcionar como um servidor TCP. Para criar um ServerSocket precisamos saber qual é a porta que será utilizada. Comumente utiliza-se portas acima de 1000 pois as inferiores são utilizadas pelo sistema operacional.
    Mãos à obra
    Para ilustrar o uso dos sockets, iremos construir uma aplicação bastante simples para comunicação de dois computadores. Um computador ficará aguardando alguma conexão e irá exibir em tela o que foi recebido. Veremos então a classe Servidor e a classe Cliente.

    Vamos explicar os pontos importantes da classe acima. No techo

    apenas declaramos as variáveis que iremos utilizar. Na trecho

    , criamos o server socket na porta 7000.
    No trecho

    utilizamos o método accept() que espera por uma conexão e continua somente quando recebe uma. Então retorna um socket para comunicar com o cliente que acaba de se conectar. O método accept() do ServerSocket, quando invocado, faz com que a Thread atual seja "paralisada" até que uma conexão seja recebida. É comum, em ambientes reais, lançarmos uma Thread a cada conexão recebida pelo ServerSocket. Isto é feito para que possamos tratar vários clientes conectados simultaneamente. Veremos como fazer isto em um outro tutorial. No trecho

    criamos um leitor dos dados de entrada baseado no canal de entrada de dados do socket. O BufferedReader lê texto de uma text-input stream e os deixa em buffer para leitura eficiente das informações. O InputStreamReader lê os bytes que estão chegando e os transforma em caracteres para que o BufferedReader possa entender. No trecho

    chamamos o método readline() da classe BufferedReader. Através deste método, o programa aguarda a chegada de algum dado no canal de entrada e lê uma linha. Após linha ser recebida ela é impressa na saída padrão do sistema com o popular System.out.println(). Nas linhas

    , fechamos os sockets. Note que fizemos isto dentro de um bloco do tipo finally pois isto garante que os recursos serão liberados. É muito importante liberar este tipo de recurso sempre que não forem mais necessários, pois são finitos e representam um custo considerável de manutenção.
    Mãos à Obra - Continuando...
    Agora vejamos a classe Cliente.

    Nas linhas

    apenas declaramos as variáveis que iremos utilizar. Na linha

    criamos o socket. De acordo com o construtor que utilizamos, criamos um socket para comunicação com o IP 127.0.0.1 (IP LoopBack*) na porta 7000 (que a porta que nosso servidor irá ?escutar?. Na linha

    criamos um objeto do tipo PrintStream para poder imprimir dados para o canal de saída do socket. Na linha

    utilizamos o método println() da classe PrintStream para imprimir uma String que será enviada através do socket para o Servidor. O método println() da classe PrintStream converte os caracteres digitados para o formato adequado de envio através do socket. Verifique a especificação da API para verificar todos os tipos de dados que podem ser impressos por este método. Na linha

    fechamos o socket dentro do bloco finally. Agora, que entendemos o código podemos executá-los Copie os arquivos do tutorial para uma pasta e compile-os da forma comum. javac Servidor.java javac Cliente.java Agora, abra 2 janelas de prompt. Vamos executar cada classe em um prompt diferente (para testar em um mesmo equipamento). Em uma das janelas digite java Servidor e na outra digite java Cliente. Você deverá perceber que ao executar a classe Cliente, o texto ?Estou enviando dados para o servidor? será exibido na janela da classe Servidor. Pronto, esta é a nossa aplicação funcionando em rede de forma simples. Faça testes, verifique o que acontece quando o servidor não está rodando, altere os Ips caso esteja em rede, ou se estiver conectado a internet teste com seus amigos, leia a especificação das APIs e, quem sabe, adicionar recursos... Demos o passo inicial, agora é com você! *IP LoopBack ? Termo utilizado para representar uma forma de comunicação com o próprio equipamento (geralmente utilizado para efetuar testes). Para acessá-lo, utilizamos 127.0.0.1 ou simplesmente localhost.