Introdução à Sockets em java





Já conhecemos uma série de questões importantes relativas à redes e em especial, à Internet. Já trabalhamos com alguns métodos e classes do pacote java.net. Agora, chegou o momento de avançarmos um pouco em nossas aplicações de rede com Java.
Vimos que o endereço IP de uma máquina conectada à Internet é único, e identifica esta máquina na rede. Vimos também que os números de porta (para um determinado computador) também são únicos. Portanto, a combinação entre endereço IP e número de porta diferencia totalmente um aplicativo em execução na Internet. É justamente esta combinação entre IP e número de porta que chamaremos de socket.
A conexão por sockets tem origem em 1980, quando a ARPA (Advanced Research Projects Agency, Agência de Projetos de Pesquisa Avançados), órgão do governo norte-americano, forneceu recursos financeiros para que a Universidade da Califórnia em Berkeley oferecesse uma implementação UNIX do pacote de protocolos TCP/IP. O que foi desenvolvido ficou conhecido então como interface de sockets de Berkeley ou simplesmente sockets de Berkeley.
Os sockets nada mais são do que pontos de conexões para uma rede TCP/IP. São análogos aos soquetes em eletricidade, que funcionam como um ponto de contato elétrico entre aparelhos. Quando dois computadores querem manter um “diálogo” entre eles, cada um utilizará um socket. Um deles é chamado de servidor (ele abra um socket e espera por conexões) e o outro é chamado de cliente (ele chama o socket servidor para iniciar a conexão). Para estabelecer uma conexão, é necessário somente um endereço de destino e um número de porta.
Existem dois modos de transmissão de sockets: o modo baseado em conexões e o modo sem conexão. Os sockets baseados em conexões operam como um telefone: eles estabelecem uma conexão e depois suspendem a ligação. Os sockets sem conexão funcionam de maneira análoga ao correio: a entrega não é garantida, e os diferentes itens da correspondência podem chegar em uma ordem diferente daquela que foram enviados.
A escolha do modo de transmissão de sockets vai depender das necessidades da sua aplicação. Se confiabilidade é fundamental, você deverá utilizar o modo baseado em conexões. Um servidor de arquivos, por exemplo, necessita que todos os seus dados cheguem aos usuários e em uma seqüência correta. Uma operação sem conexão seria mais rápida e eficiente, mas não teria garantia alguma.
O modo com conexões utilizar o protocolo TCP. Um socket nesse modo de operação precisa conectar-se a um destino antes de transmitir os dados. Quando conectados, os sockets utilizam uma interface de fluxos: abertura-leitura-escrita-fechamento. Tudo aquilo que foi enviado por um socket é recebido pelo outro exatamente na mesma ordem em que foi transmitido. Já o modo sem conexões utiliza o UDP (User Datagram Protocol). Um datagrama é uma unidade autônoma que possui todas as informações necessárias para a comunicação entre dois sockets. Imagine um datagrama como sendo cada um dos “pedaços” das informações transmitidas durante uma conexão. Um socket nesse modo de operação não precisa se conectar a um socket de destino. Ele precisa simplesmente enviar o datagrama. Na verdade, o protocolo UDP “faz um esforço” para entregar um datagrama, mas não garante que este “esforço” trará resultados positivos.
Como já foi dito no início deste capítulo, as classes Java voltadas para o desenvolvimento de aplicações para redes vieram para facilitar de maneira surpreendente o trabalho dos programadores. Cada modo de transmissão é implementado em um conjunto separado de classes, deixando a vida do desenvolvedor menos confusa.
As classes baseadas em conexões em Java são sempre dividas em versão cliente e versão servidora. A versão cliente tende a ser um pouco mais simples do que a servidora. Por isso, ela será focalizada em primeiro lugar.O aplicativo seguinte, por exemplo, solicita um documento HTML no servidor e retorna uma resposta utilizando Sytem.out.println:
import java.io.*;
import java.net.*;
// Essa pequena aplicação abra uma conexão e chama um arquivo HTML em um servidor
public class SimpleWebClient
{
public static void main(String args[])
{
try
{
// Abre uma conexão de socket cliente
Socket clientSocket1 = new Socket(“cristiano”, 80);
System.out.println(“Client1: “ + clientSocket1);
// Recebe um documento HTML
getPage(clientSocket1);
}
catch (UnknownHostException uhe)
{
System.out.println(“UnknownHostException: “ + uhe);
}
catch (IOException ioe)
{
System.err.println(“IOException: “ + ioe);
}
}
/**
* Solicita uma página de Web usando o socket cliente aberto.
* Exibe um resposta e fecha o socket cliente.
*/
public static void getPage(Socket clientSocket)
{
try
{
// Obtém fluxos de entrada e saída
DataOutputStream outbound = new DataOutputStream(
clientSocket.getOutputStream() );
DataInputStream inbound = new DataInputStream(
clientSocket.getInputStream() );
// Escreve no servidor o pedido HTTP
outbound.writeBytes(“GET / HTTP/1.0 ”);
// Lê a resposta
String responseLine;
while ((responseLine = inbound.readLine()) != null)
{
// Exibe cada linha de resposta
System.out.println(responseLine);
// Checa os erros. Existe um bug no código de fechamento de sockets
// no Windows 95. readline() não retornará null quando o socket cliente for
// fechado pelo servidor
if ( responseLine.indexOf(“</HTML>”) != -1 )
break;
}
// Limpeza
outbound.close();
inbound.close();
clientSocket.close();
}
catch (IOException ioe)
{
System.out.println(“IOException: “ + ioe);
}
}
}
import java.io.*;
import java.net.*;
/**
* espera por conexões e serve um
* documento HTML
*/
class SimpleWebServer
{
public static void main(String args[])
{
ServerSocket serverSocket = null;
Socket clientSocket = null;
int connects = 0;
try
{
// cria o socket servidor
serverSocket = new ServerSocket(80, 5);
while (connects < 5)
{
// espera por conexões
clientSocket = serverSocket.accept();
ServiceClient(clientSocket);
connects++;
}
serverSocket.close();
}
catch (IOException ioe)
{
System.out.println(“Erro: “ + ioe);
}
}
public static void ServiceClient(Socket client)
throws IOException
{
DataInputStream inbound = null;
DataOutputStream outbound = null;
try
{
inbound = new DataInputStream( client.getInputStream());
outbound = new DataOutputStream( client.getOutputStream());
StringBuffer buffer = PrepareOutput();
String inputLine;
while ((inputLine = inbound.readLine()) != null)
{
if ( inputLine.equals(“”) )
{
outbound.writeBytes(buffer.toString());
break;
}
}
}
finally
{
System.out.println(“Limpando conexão: “ + client);
outbound.close();
inbound.close();
client.close();
client.close();
}
}
public static StringBuffer PrepareOutput()
{
StringBuffer outputBuffer = new StringBuffer();
outputBuffer.append(“<HTML> <HEAD> <TITLE>HTML teste</TITLE> ”);
outputBuffer.append(“</HEAD> ”);
outputBuffer.append(“<BODY> Este é um <STRONG>test</STRONG>documento HTML! ”);
outputBuffer.append(“</BODY> ”);
outputBuffer.append(“</HTML> ”);
StringBuffer headerBuffer = new StringBuffer();
headerBuffer.append(“HTTP/1.0 200 OK ”);
headerBuffer.append(“Content-type: text/html ”);
headerBuffer.append(“Content-length: “ + outputBuffer.length() );
headerBuffer.append(“ ”);
headerBuffer.append(outputBuffer.toString());
return headerBuffer;
}
}
Bem, por hoje, ficamos por aqui. Na semana que vem, começaremos a estudar o gerenciamento de memória em Java. Até lá!

Comentários

Postagens mais visitadas deste blog

E Esse Tal de Nano Service?

Executar Audio em Java Swing

Validando Email em Java Com e Sem expressão Regular