Socket - Aos Primórdios do Java
Módulo 3 - Treinamento baseado no livro Aos Primórdios do Java - Filipe Negrello
Description
Sockets
Objetivos
Após completar você deverá ser capaz de:
Entender o conceito de socket
Conectar-se a computadores remotos utilizando sockets Criar programas Cliente-Servidor
✓ Entender o conceito de Datagrama
Conhecer as classes de Datagramas disponíveis em Java
O que são Sockets
Sockets são abstrações de software utilizadas para representar as duas “pontas” de uma conexão.
Para uma determinada conexão existe um socket em cada uma das máquinas. Entre estes dois sockets trafegam os dados da conexão.
Esta abstração permite que se programe a comunicação entre computadores sem o conhecimento do hardware e cabeamento de uma rede
Um socket é uma ponta lógica de uma conexão entre programas rodando em uma rede. Portanto, para cada conexão existem dois sockets, um em cada ponta da comunicação.
Esta abstração faz com que o conhecimento da parte física que compreende os conectores e os cabos não seja necessário no programa, pois a transferência de dados é tratada da mesma maneira que o acesso a arquivos comuns(streams).
Funcionamento de Sockets
Em Java, um socket é criado apenas para iniciar a conexão entre computadores. Em uma das máquinas, um programa “servidor” (classe ServerSocket ou outro tipo de servidor que aceite conexões TCP) é executado e fica aguardando uma conexão em uma determinada porta (método accept()).
Outra máquina age como “cliente” (classe Socket) e faz uma requisição usando o endereço e a porta de um possível “servidor”.
Caso a conexão ocorra com sucesso, o método accept( ) do programa “servidor” retorna um Socket e a transferência de dados pode ser iniciada. Repare que a partir deste instante não existe mais uma máquina “cliente” e outra “servidor”, pois ambas podem enviar e receber dados. A distinção é feita apenas para identificar quem está ouvindo e quem solicita a comunicação. É a aplicação que irá determinar quem será o “servidor” e quem será o “cliente”.
Após o estabelecimento da conexão deve-se abrir um canal para a transferência dos dados, através do uso de streams. Cada ponto conectado possui duas streams: InputStream, para recebimento e OutputStream, para o envio de dados.
Com este formato fica muito fácil enviar e receber dados, bastando para isso o uso das funções de streams como read() e write().
Deve-se destacar que tanto a conexão quanto a transferência são realizadas sem nenhum conhecimento sobre qual placa de rede está sendo usada, bem como plataforma, funcionamento do protocolo etc. A seguir são apresentadas as classes e funções necessárias para realizar o processo aqui descrito.
A Classe Socket
Classe que representa um socket em Java. Possui diversos construtores para facilitar o uso, mas basicamente os parâmetros solicitados são: identificação do “servidor" e porta do serviço requisitado. O próprio construtor é o responsável pela solicitação da conexão e continua tentando até que ocorra: sucesso, erro de E/S ou endereço não encontrado.
void setSoTimeout()
Indica o tempo máximo (em milissegundos) que uma operação de leitura deve aguardar. Se for definido um timeout de 0 (zero) o tempo máximo é infinito.
InetAddress getLocalAddress() int getLocalPort()
Retornam o endereço e a porta do computador no qual o socket está sendo executado.
InetAddress getInetAddress() int getPort()
Retornam o endereço e a porta do computador no qual o socket está conectado.
InputStream getInputStream() OutputStream getOutputStream()
Retornam os streams padrões para entrada e saída de dados. Através de filtros apropriados podem ser convertidos para outros tipos de streams.
void close() Fecha a conexão.
Lendo Dados com Sockets
Para abrir uma conexão, deve-se criar um objeto da classe Socket, passando como parâmetro uma localização e uma porta.
O construtor do socket tenta conectar-se até que ocorra sucesso, erro de I/O ou endereço não encontrado.
Após a conexão efetivada abre-se uma stream de entrada para recuperação dos dados com getlnputStream().
O protocolo de comunicação utilizado pela classe Socket é o TCP.
Para abrir uma conexão, deve-se criar um objeto da classe Socket, passando como parâmetro uma localização e uma porta.
O construtor do socket tenta conectar-se com a URL indicada até que ocorra sucesso, erro de E/S ou endereço não seja encontrado.
Após a conexão efetivada abre-se uma stream de entrada para recuperação dos dados com o método getInputStream( ).
Geralmente se transforma esse stream em uma outra classe de E/S que tenha o nível desejado de funcionalidade para o usuário.
Para isso usam-se as classes de E/S do Java considerando que o stream de entrada retornado pelo método getInputStream() é uma instância da família da classe InputStream.
O protocolo de comunicação utilizado pela classe Socket é o TCP.
Definindo um Timeout de E/S
Uma operação de E/S ou mesmo a abertura da conexão podem durar indefinidamente.
Para evitar este problema pode ser definido um tempo máximo (timeout) para a conclusão da tarefa.
O método setSoTimeOut é utilizado para a definição do tempo máximo de todas as operações subsequentes.
Timeout de Conexão
A partir da versão 1.4 do Java, é possível se indicar um tempo de timeout na conexão do programa com um servidor.
Para que se tenha essa característica deve-se mudar a maneira de se criar e manipular o Socket.
Primeiramente deve-se criar uma instância de InetSocketAddress, onde se passa o nome do host (ou endereço IP) e a porta de conexão desejada. Essa classe é filha da classe abstrata SocketAddress que representa uma conexão socket sem a parte do protocolo.
Depois se deve criar uma instância de Socket sem os parâmetros de host e porta. Usando essa instância criada, chama-se o método connect() que recebe a instância InetSocketAddress e como segundo parâmetro um valor indicando o tempo de timeout em milisegundos que será usado para a conexão.
Classe ServerSocket
Classe que representa o socket servidor. Todos os seus construtores têm como parâmetro comum a porta de comunicação a ser usada. Caso seja usado o valor 0 (zero) uma porta livre é escolhida pelo programa.
void setSoTimeout()
Indica o tempo máximo (em milissegundos) que o servidor deve aguardar uma conexão (accept). Se for definido um timeout de 0 (zero) o tempo máximo é infinito.
int getSoTimeout()
Retorna o timeout atual. Socket accept()
Bloqueia o programa e aguarda uma conexão. Finaliza apenas quando uma conexão é feita ou quando for atingido o timeout. Quando a conexão é estabelecida o método irá retornar uma instância da classe Socket que deve ser usada para a comunicação com o cliente que se conectou.
InetAddress getlnetAddress() int getLocalPort()
Retornam o endereço e a porta do computador no qual o ServerSocket está sendo executado.
void close() Fecha a“escuta”.
Servidor de Socket
Um servidor de socket deve ficar em espera, aguardando uma conexão em uma porta específica.
A classe para criação de servidores chama-se ServerSocket.
Após a conexão, um objeto Socket é retornado com uma nova porta para que a original fique livre e possa aguardar por novas requisições
Ambos os lados da conexão podem enviar e receber dados.
Quase sempre um servidor que irá receber conexões via socket possui uma estrutura padrão.
A comunicação pode ocorrer de modo serial ou de modo múltiplo. No modo serial somente é permitido que um cliente se comunique com o servidor de cada vez.
O modo múltiplo irá permitir que vários clientes realizem a comunicação com o servidor ao mesmo tempo.
A estrutura de um tipo de servidor difere da outra.
O servidor de socket serial deve ficar em estado de espera, aguardando uma requisição em uma porta específica, realizada através do método accept( ).
Após a conexão, um objeto Socket é retornado com uma nova porta para que a original fique livre e possa aguardar por novas requisições.
Ambos os lados da conexão podem enviar e receber dados, ou seja, após o estabelecimento da conexão, não existe mais a figura de cliente e servidor. Essa comunicação deve sempre seguir um protocolo.
Após a comunicação ter sido terminada, pode-se voltar a chamar o método accept() que irá deixar o servidor em estado de espera novamente. Com essa estrutura de implementação a comunicação cliente/servidor será realizada de modo serial, sendo que somente um cliente terá comunicação com o servidor
Múltiplos Clientes
Em geral, um servidor é capaz de atender múltiplas requisições e criar múltiplos sockets, um para cada cliente.
Esta tarefa é facilmente realizada com a utilização de múltiplas threads.
Para tanto, basta pegar o Socket resultante do método accept() e usá-lo para criar uma nova thread.
Em seguida deve-se chamar o método accept() novamente e aguardar novas requisições.
Data gramas
A classe Socket utiliza o protocolo TCP para realizar sua comunicação. Este protocolo garante a entrega dos pacotes e por isso tem um alto overhead devido ao controle de sequência e entrega dos pacotes.
Existe outro protocolo que não garante nem a entrega e nem a ordem dos pacotes. Ele é chamado de User Datagram Protocol (UDP).
Quando usado em aplicações que não necessitam de precisão na entrega dos pacotes, o protocolo UDP garante maior rapidez de transmissão. Também não existe a figura do servidor múltiplo, sendo que sempre se deve pensar em comunicação UDP sendo feito entre duas máquinas somente, pois o protocolo UDP é um protocolo sem conexão.
Geralmente esse protocolo é usado em servidores de informações.
Como periodicamente o cliente vem buscar informações para consulta no servidor, caso se perca alguma informação no caminho não trará problemas pois logo em seguida o cliente irá pedir novamente a informação.
Classes para Datagramas
A classe DatagramSocket é usada para representar um socket que se comunica com o protocolo UDP.
A classe DatagramPacket representa um pacote que é enviado ou recebido pelo DatagramSocket.
DatagramPackets podem ser enviados para múltiplos recipientes que estejam escutando um MultiCastSocket.
A classe DatagramSocket é usada para representar um socket que se comunica com o protocolo UDP para enviar e receber pacotes datagram.
O socket tipo datagram é um ponto de envio e recebimento de serviços de pacotes. Cada pacote enviado ou recebido através do socket tipo datagram deve ser individualmente endereçado e direcionado.
A informação da origem e destino acompanha o pacote que trafega na rede.
A classe DatagramPacket representa um pacote que é enviado ou recebido pelo DatagramSocket.
É essa classe que implementa o serviço de envio de pacotes sem conexão. Nessa instância é que é colocada a rota de envio do pacote, informando o destino do pacote.
Comunicação Multicast
A comunicação multicast representa a comunicação de um servidor com vários clientes, formando grupos de máquinas.
A comunicação é feita em UDP e, portanto, deve- se usar a classe DatagramPacket para o envio e recebimentos de informações.
Para se criar um grupo de comunicação usa-se a classe MulticastSocket.
Um grupo de multicast é caracterizado por um endereço IP de classe D, de 224.0.0.0 a 239.255.255.255.
A comunicação multicast caracteriza-se pelo envio de um pacote não somente para um cliente e sim para todos os clientes que fazem parte de um grupo de multicast. O protocolo de rede tentará enviar o pacote para todos os clientes participantes do grupo.
Um grupo multicast é caracterizado por um endereço IP classe D entre 224.0.0.0 a 239.255.255.255) sendo que o endereço 224.0.0.0 é reservado e não pode ser usado.
Clientes que querem participar de um grupo, indicam isso através da criação de uma instância de MulticastSocket indicando ou não uma porta. Após criada a instância, o programa que quer receber uma comunicação multicast deve se juntar ao grupo através do método joinGroup( ). Caso se queira deixar o grupo deve-se chamar o método leaveGroup(). É nesses dois métodos que se indica o endereço IP do grupo multicast que está se agrupando ou deixando.
O envio e recebimento de informações via grupo multicast é sempre feito através da classe DatagramPacket.
Para se enviar um pacote para o grupo usa- se o método send() e para receber usa-se o método receive().
What You Will Learn!
- Entender o conceito de socket
- Conectar-se a computadores remotos utilizando sockets
- Criar programas Cliente-Servidor
- Entender o conceito de Datagramas
Who Should Attend!
- A todos desenvolvedores que estão começando na linguagem java e desejam aprender como funciona a comunicação entre dispositivos usando socket puro no java.