O socket é uma abstração que representa um ponto de comunicação em uma rede de computadores [Harold 1997]. Para dois computadores trocarem informações, cada um utiliza um socket. Tipicamente, um computador atua como servidor, abrindo o socket e ficando na escuta, a espera de mensagens ou pedidos de conexões. O outro computador assume o papel de cliente, enviando mensagens para o socket do servidor.
Existem dois modos de operação: orientado a conexão, baseado no protocolo TCP (Transport Control Protocol) e sem conexão, empregando o protocolo UDP (User Datagram Protocol). Para usar sockets orientados a conexão, antes do envio dos dados é necessário o estabelecimento de uma conexão entre o cliente e o servidor. A conexão deve ser terminada ao final da comunicação e os dados chegam na mesma ordem que foram enviados. Quando sockets sem conexão são empregados, a entrega não é garantida. Dados podem chegar em ordem diferente da que foram enviados. O modo usado depende das necessidades da aplicação. Via de regra, o uso de conexão implica em maior confiabilidade, porém com maior overhead.
Cada computador em uma rede TCP/IP possui endereço IP único. Portas representam conexões individuais com esse endereço. Quando o socket é criado, ele deve ser associado com uma porta específica, isto é, efetuar o seu binding. Para estabelecer uma conexão o cliente precisa conhecer o endereço IP da máquina onde o servidor executa e o número da porta que o servidor está escutando. Existe a tentativa de padronização de alguns números de portas com relação aos serviços oferecidos pelo servidor, tais como: 7-echo, 13-daytime, 21-ftp, 23-telnet, 25-smtp, 79-finger, 80-http, 110-pop3. Estes números de portas são definidos pela IANA (Internet Assigned Numbers Authority).
A figura a baixo, mostra o algoritmo básico para clientes e servidores quando TCP é usado. Em Java, clientes e servidores adotam procedimentos diferentes. Um socket cliente é criado e conectado pelo construtor da classe Socket. Por exemplo:
clientSocket = new Socket(“merlin.das.ufsc.br”, 80);
A comunicação em si é feita com o auxílio de classes tipo streams, que são classes do pacote java.io. Os clientes seguem sempre a mesma receita básica: cria um socket com conexão cliente e utiliza classes que implementam streams para efetuar a comunicação. Existem diversas opções para sockets clientes, tais como definir o timeout usado no protocolo de desconexão, timeout utilizado em operações de leitura, etc.
Servidores não criam conexões, eles esperam pelo pedido de conexão de um cliente. O construtor de ServerSocket é usado, como em:
ServerSocket serverSocket = new ServerSocket(80, 5);
Um servidor pode receber várias requisições de conexão ao mesmo tempo e as requisições são processadas uma a uma. A fila de requisições ainda não atendidas é denominada pilha de escuta. O tamanho da fila de escuta indica quantas requisições de conexão simultâneas são mantidas. Assim, na construção acima, o primeiro parâmetro é o número da porta a ser escutada e o segundo parâmetro é o tamanho da pilha de escuta. O valor default é 50. O método accept() é chamado para retirar requisições da fila. Ele bloqueia o processo até a chegada uma requisição, e após isso, retorna um socket conectado com o cliente. O objeto socket do servidor não é usado, um novo é criado para a transferência dos dados. O socket do servidor continua enfileirando pedidos de conexão. Finalmente, streams são usados para a troca de dados. Um servidor simples processa uma conexão de cada vez. Entretanto, utilizando múltiplas threads, um servidor concorrente vai criar uma nova thread para cada conexão aberta e assim consegue processar várias conexões simultaneamente. Por exemplo, servidores web comerciais são todos concorrentes.
No caso de comunicação baseada em datagramas, a classe DatagramSocket é usada tanto por clientes como por servidores. O servidor deve especificar sua porta, e a omissão do parâmetro significa “use a próxima porta livre”. O cliente sempre utiliza a próxima. O algoritmo básico é mostrado na figura a baixo:
A classe DatagramPacket é usada para enviar e receber dados. Ela contém informações para conexão e os próprios dados. Para receber dados de um socket datagrama, o método receive() bloqueia até a recepção dos dados. Para enviar dados para um socket datagrama é necessário um endereço, a classe InetAddress representa endereços na Internet. Por exemplo:
InetAddress addr = InetAddress.getByName(“das.ufsc.br”).
O envio de um string para um socket destinatário é feito através da montagem de um objeto DatagramPacket, o qual conterá a mensagem e o endereço destino. Seu envio através do método send() de objeto da classe DatagramSocket criado anteriormente pelo cliente.
Nenhum comentário:
Postar um comentário
Gostou do post? Deixe a sua opnião.