SCE5777

Sistemas Distribuídos
Comunicação em Sistemas Distribuídos
Sockets
4ª aula
26/08/08
Profa. Sarita Mazzini Bruschi
sarita@icmc.usp.br
Slides baseados no material de:
Prof. Edmilson Marmo Moreira (UNIFEI / IESTI)
1

Sockets
Introdução  

Uma rede de computadores é composta por
máquinas interconectadas e canais de
comunicação que permitem a transmissão de
bytes de uma máquina para outra
No TCP/IP, para um programa comunicar
com outro, ele utiliza duas informações:  

Endereço Internet: usado pelo protocolo IP
Número de porta: utilizado pelo protocolo de
transporte (UDP ou TCP)
2

Sockets
Definição 

Um socket é uma abstração através da qual
uma aplicação pode enviar e receber dados,
de uma maneira semelhante à utilizada para
ler e escrever em arquivos
Uma abstração
socket pode ser
referenciada por
diversos
programas
usuários 

3

Sockets
usando Java

4

Sockets Conceitos Básicos    Um cliente deve utilizar o endereço IP do servidor para iniciar uma comunicação Em Java. o endereço pode ser especificado usando uma string que contém o endereço IP ou o nome correspondente O endereço IP é encapsulado na classe InetAddress que provê 3 métodos estáticos:    getByName getAllByName getHostAddress 5 .

println("Local Host:").out.println("\t" + address.println("\t" + address.out.println("Unable to determine this host's address").out. System.getHostAddress()). System.println ("\t" + addressList[j].println("Unable to find address for" + args[i]).} } } } 6 .println("\t" + addressList[0].length.out. // for InetAddress class InetAddressExample { public static void main (String[] args) { // Get name and IP address of the local host try { InetAddress address = InetAddress.out.} for (int i=0. i++) { // Get name(s)/address(es) of hosts given on command line try { InetAddress[] addressList = InetAddress. System. } catch (UnknownHostException e) {System.length. System.println(args[i] + ":").getHostAddress()).out.Sockets Exemplo import java.getAllByName(args[i]). System. } catch (UnknownHostException e) {System.getHostName()). for (int j=0. j++) System. j < addressList.getHostName()). i < args.net.out.out.getLocalHost().*.

Sockets TCP  Java fornece duas classes para trabalhar com o TCP:    Socket ServerSocket Uma instância de Socket representa uma conexão de TCP fim-a-fim  Um canal cujas pontas são indentificadas por um endereço IP e um número de porta 7 .

Sockets TCP  Período de Setup   Período que se inicia com o cliente enviando uma requisição de conexão para o servidor Uma instância de ServerSocket aguarda conexões TCP e cria uma nova instância de Socket para manipular os pedidos de conexão 8 .

2. Constrói uma instância de Socket: o construtor estabelece uma conexão TCP para um host e uma porta especificada. 3. Comunica-se utilizando o socket’s I/O stream: uma instância de Socket contém objetos InputStream e OutputStream que pode ser utilizado como qualquer outro Java I/O stream Encerra a conexão utilizando o método close() da classe Socket 9 .Sockets TCP Cliente TCP    Os clientes iniciam a comunicação com um servidor que está passivamente aguardando por uma conexão Um cliente típico segue os seguintes passos: 1.

length == 3) ? Integer.getOutputStream().write(byteBuffer). int bytesRcvd.length .length) { if ((bytesRcvd = in.length < 2) || (args.Sockets TCP – Exemplo . servPort). // for Socket import java. totalBytesRcvd += bytesRcvd.getInputStream().getBytes()..println("Received: " + new String(byteBuffer)). while (totalBytesRcvd < byteBuffer. } } 10 . System. sending echo string").length > 3)) throw new IllegalArgumentException ("Parameter(s): <Server> <Word> [<Port>]").io.*. String server = args[0]. socket.out.Cliente import java.*. // Send the encoded string to the server // Receive the same string back from the server int totalBytesRcvd = 0.totalBytesRcvd)) == -1) throw new SocketException("Connection closed prematurely"). // Convert input String to bytes using the default character // encoding byte[] byteBuffer = args[1].parseInt(args[2]) :7. InputStream in = socket. out.. // for IOException and Input/OutputStream public class TCPEchoClient { public static void main (String[] args) throws IOException { if ((args. OutputStream out = socket.net. } System.close(). byteBuffer.read(byteBuffer. int servPort=(args. // Create socket that is connected to server on specified port Socket socket = new Socket(server.println("Connected to server. totalBytesRcvd.out.

uma nova instância da classe Socket é criada e retornada pelo método accept() Comunica-se com o cliente usando os objetos InputStream e OutputStream do objeto Socket Encerra a conexão com o cliente usando o método close() da classe Socket 11 . Quanto um novo cliente se conecta. 2.Sockets TCP Servidor TCP A tarefa do servidor é preparar o canal de chegada dos pedidos e aguardar por conexões dos clientes Um servidor típico segue os seguintes passos:   1. Esse objeto fica ouvindo a porta. Cria uma instância local da classe ServerSocket. aguardando por pedidos de conexão Repetidamente    Chama o método accetp() do ServerSocket para obter a próxima conexão dos clientes. especificando uma porta local.

0.Sockets TCP – Exemplo . // Size of receive message byte[] byteBuffer = new byte[BUFSIZE].length != 1) throw new IllegalArgumentException("Parameter(s): <Port>").accept().write(byteBuffer.*. // indicated by -1 return while ((recvMsgSize = in. clntSock. int recvMsgSize. InputStream in = clntSock.getHostAddress() + " on port " + clntSock.close().getPort()).getInputStream().parseInt(args[0]). // Receive until client closes connection. // We are done with this client } /* NOT REACHED */ } } 12 .out. // Size of receive buffer public static void main (String[] args) throws IOException { if (args. // Receive buffer for (. OutputStream out = clntSock.. // Close de socket. // Create a server socket to accept client connection requests ServerSocket servSock = new ServerSocket(servPort).read(byteBuffer)) != -1) out.io.Servidor import java.) { // Run forever.getInetAddress(). int servPort = Integer. recvMsgSize). // for IOException and Input/OutputStream public class TCPEchoServer { private static final int BUFSIZE = 32.*.net. // for Socket. accpeting and servicing connections Socket clntSock = servSock. // Get client connection System.println("Handling client at " + clntSock.getOutputStream(). ServerSocket import java.

Detecta dados corrompidos que podem ocorrer na transmissão das mensagens 13 .Sockets UDP   O socket UDP provê um serviço diferente de comunicação em relação ao protocolo TCP O UDP executa somente duas funções:   Adiciona outra camada de endereçamento (portas) para o IP.

funciona como uma caixa de correio onde cartas e pacotes de diferentes lugares podem ser colocados Assim que é criado.Sockets UDP  Características       Não precisam ser conectados antes de serem utilizados Cada mensagem carrega as próprias informações de endereçamento. um socket UDP pode ser usado para enviar e receber mensagens para qualquer endereço Não há garantias de quem uma mensagem enviada por um socket UPD chegará ao seu destino As mensagens podem ser entregues fora de ordem 14 . sendo independente das outras mensagens Durante o recebimento.

Sockets UDP  Java fornece duas classes para trabalhar com UDP:    DatagramPacket DatagramSocket Clientes e servidores utilizam DatagramSockets para enviar e receber DatagramPackets 15 .

como o TCP.Sockets UDP  DatagramPacket   Ao invés de enviar streams. denominadas datagramas. que são representadas em Java como instâncias DatagramPacket Para enviar uma mensagem. o UDP envia mensagens autocontidas. um programa Java constrói uma instância de DatagramPacket e passa como argumento para o método Send() da classe DatagramSocket 16 .

Sockets UDP  DatagramPacket  Para receber uma mensagem. um programa Java cria uma instância de DatagramPacket com espaço pré-alocado de memória (objeto byte[]). onde o conteúdo da mensagem recebida pode ser copiado e passa a respectiva instância para o método receive() da classe DatagramPacket 17 .

o endereço identifica o remetente  Quando um DatagramPacket é recebido no servidor.Sockets UDP  DatagramPacket  Cada instância de DatagramPacket também contém informações de endereços e portas  Quando um DatagramPacket é enviado. este pode modificar seu conteúdo e enviar o mesmo DatagramPacket 18 . o endereço e a porta identificam o destinatário  Quanto um DatagramPacket é recebido.

Sockets UDP Cliente UDP    Os clientes iniciam a comunicação enviando um datagrama para um servidor que está passivamente Um cliente UDP típico segue os seguintes passos: 1. opcionalmente indicando o endereço e a porta Comunica-se através do envio e do recebimento de instâncias de DatagramPacket usando os métodos send() e receive() da classe DatagramPacket Quanto finaliza. 3. 2. desaloca o socket usando o método close() da classe DatagramPacket 19 . Constrói uma instância de DatagramPacket.

parseInt(args[2]):7. 20 .setSoTimeout(TIMEOUT).*. boolean receivedResponse = false. InetAddress serverAddress = InetAddress. bytesToSend. // Resend timeout private static final int MAXTRIES = 5. socket.length == 3) ? Integer.DatagramPacket.getBytes().InetAddress import java. DatagramSocket socket = new DatagramSocket(). DatagramPacket receivePacket = new DatagramPacket (new byte[bytesToSend. // for IOException public class UDPEchoClientTimeout { private static final int TIMEOUT = 3000.length < 2) || (args. serverAddress.*.length > 3)) throw new IllegalArgumentException("Parameter(s): <Server> <Word> [<Port>]"). bytesToSend. // for DatagramSocket.length.getByName(args[0]). servPort).length). int tries = 0.length]. // Maximum retransmissions public static void main (String[] args) throws IOException { if ((args. // Maximum receive blocking time DatagramPacket sendPacket = new DatagramPacket(bytesToSend.io.net. // Convert the argument String to bytes using the // default encoding byte[] bytesToSend = args[1].Sockets UDP – Exemplo – Cliente import java. int servPort = (args.

System.receive(receivePacket).getData())).out.println("No response -.").send(sendPacket).Sockets UDP – Exemplo – Cliente (continução) do { socket. " + (MAXTRIES .getAddress(). receivedResponse = true.equals(serverAddress)) throw new IOException("Received packet from an unknown source")..out. System. } } 21 . // Attempt echo reply // reception // Check source if (!receivePacket. if (receivedResponse) { System. } } while ((!receivedResponse) && (tries < MAXTRIES)).out. } else System..println("Timed out. // Send the echo string try { socket. socket.out.").println("Received: " + new String(receivePacket.println("Porta: " + (int)socket. } catch (InterruptedIOException e) { // We didn't get anything tries += 1.getPort()).close().tries) + " more tries .giving up.

Sockets UDP  Servidor UDP   Como um servidor TCP. a comunicação UDP é iniciada assim que chega um datagrama 22 . um servidor UDP é inicializado e aguarda passivamente por um cliente Como não há a necessidade de se estabelecer conexão.

Sockets UDP Servidor UDP  Um servidor UDP típico segue os seguintes passos:  1. opcionalmente. 4. deloca-se o socket usando o método close() da classe DatagramPacket 23 . o servidor reconhece o destinatário da resposta Comunica-se com os clientes pelo envio e recebimento de DatagramPackets usando os métodos send() e receive() da classe DatagramPacket Quando finalizado. 2. Cria uma instância da classe DatagramPacket. 3. Desta forma. O servidor está pronto para receber datagramas de qualquer cliente Recebe uma instância de DatagramPacket usando o método receive() da classe DatagramPacket. especificando uma porta local e. um endereço local. Quando receive() retorna. o datagrama contém o endereço do cliente.

// Receive packet from client System.parseInt(args[0]).out. int servPort = Integer.out. DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX]. for (. // Maximum size of echo // datagram public static void main (String[] args) throws IOException { if (args.getHostAddress() + " on port " + packet. DatagramSocket socket = new DatagramSocket(servPort). // Reset length to avoid // shrinking buffer } /* NOT REACHED */ } } 24 .ECHOMAX).io.getPort()).) { // Run forever.*.getData()))..*. socket.receive(packet).setLength(ECHOMAX). // for IOException public class UDPEchoServer { private static final int ECHOMAX = 255.length != 1) throw new IllegalArgumentException("Parameter(s): <Port>"). // Send de same packet back to client packet.println ("Handling client at " + packet. System.println ("Message received " + new String(packet.Sockets UDP – Exemplo – Servidor import java. // for DatagramSocket and DatagramPacket import java.send(packet).net. accpeting and echoing datagrams socket.getAddress().

o UDP não provê recuperação de erros na rede e. todos os chamadores sabem que os dados foram copiados para um buffer para transmissão.Sockets Envio e recebimento de mensagens com Sockets UDP  Uma diferença entre TCP e UDP é que o UDP preserva as últimas mensagens     A cada chamada do método receive() são retornados dados de pelo menos uma chamada send() Além disso. dessa forma. independente dos dados terem sido transmitidos Entretando. não existem buffers de dados para possíveis retransmissões 25 . diferentes chamadas a receive() nunca irão retornar dados de uma mesma chamada send() Quando uma chamada ao método write() em um stream de saída TCP retorna.

mas ainda não entregues. todos os bytes recebidos. os dados são armazenados em uma fila FIFO Com uma conexão TCP.Sockets Envio e recebimento de mensagens com Sockets UDP   Entre o tempo de uma mensagem chegar pela rede e o tempo de seus dados serem retornados pelos métodos read() e receive(). são tratados como uma seqüência contínua de bytes 26 .

Os bytes restantes são descartados sem nenhuma indicação ao programa receptor de que a informação foi perdida 27 . os dados podem ter sido originados de diferentes emissores. cada uma com a informação associada que identifica sua origem Uma chamada a receive() nunca irá retornar mais do que uma mensagem Entretando. Um dado recebido de um socket UDP é mantido em uma fila de mensagens. somente os primeiros n bytes da mensagem são retornados.Sockets Envio e recebimento de mensagens com Sockets UDP    No protocolo UDP. se receive() é chamada com um DatagramPacket contendo um buffer de tamanho n e o tamanho da primeira mensagem da fila de mensagens recebidas for maior do que n.

entretanto.Sockets Envio e recebimento de mensagens com Sockets UDP   Por essa razão. um receptor deve sempre prover um DatagramPacket com um buffer grande o suficiente para manter a maior mensagem permitida pelo protocolo da aplicação durante uma chamada ao método receive() Essa técnica irá garantir que nenhum dado se perderá. o tamanho máximo de um datagrama UDP é 65.507 bytes 28 .

o qual pode ser alterado toda vez que uma mensagem é recebida. 29 . noção do tamanho das mensagens.devem explicitamente reiniciar o tamanho interno do buffer atual antes de cada chamada ao método.Sockets Envio e recebimento de mensagens com Sockets UDP   É importante lembrar que cada instância da classe DatagramPacket não possui. com a mesma instância de DatagramPacket. internamente. Aplicações que chamam o método receive() mais de uma vez.

Sockets usando C 30 .

Tipos de Sockets  Stream Sockets     Entrega confiável Garantia de ordenação das mensagens Orientado à conexão Bidirecional  Datagram Sockets     Entrega não confiável Sem garantias de ordenação das msgs Não orientado à conexão Pode enviar ou receber 31 .

sa_data[14]. utiliza-se a estrutura sockadd_in struct sockadd_in { short u_short struct in_addr char sin_family sin_port sin_addr sin_zero[8] // AF_INET // número da porta // endereço do host // não usado } 32 . // endereço da família AX_xxx // endereço específico do protocolo Para a domínio Internet (TCP/IP).Estruturas e manipulação de dados  Estrutura sockaddr struct sockaddr { u_short char }  sa_family.

Estruturas e manipulação de dados   Apesar de existirem várias estruturas (sockaddr_in. sockaddr_ns. connect(sockfd. sizeof(serv_addr)). sockaddr_un). tais como connect e bind precisam do endereço da estrutura genética (sockaddr) e do tamanho da estrutura É necessário fazer casting: struct sockaddr_in serv_addr. (struct sockaddr *) &serv_addr. 33 . algumas funções.

precisa-se usar uma função de conversão 34 .Estruturas e manipulação de dados  Existem dois tipos de ordenação do endereço:  Bits mais significantes primeiro    Network Byte Ordering Bits menos significantes primeiro Quanto uma função precisa que o endereço esteja no formato Network Byte Ordering.

Estruturas e manipulação de dados  Funções para conversão do formato “host” para o formato “network”:     htonl (h-to-n-l): host to network. shot integer 35 . long integer ntohs (n-to-h-s): network to host. long integer htons (h-to-n-s): host to network. short integer ntohl (n-to-h-l): network to host.

Estruturas e manipulação de dados  Funções para conversão de endereços:  unsigned long inet_addr (char *ptr)   Converte uma string em formato de endereço Internet (decimal com ponto) char *inet_ntoa (struct in_addr inaddr)  Função inversa 36 .

int type. int protocol):   Cria um descritor family: AF_UNIX AF_INET AF_NS AF_IMPLINK  type: SOCK_STREAM SOCK_DGRAM SOCK_RAW SOCK_SEQPACKET SOCK_RDM  protocol: normalmente 0 37 .Principais funções  int socket (int family.

porta e endereço IP addrlen: tamanho da estrutura sockaddr 38 .Principais funções  int bind (int sockfd. struct sockaddr *my_addr. int addrlen)      Associação de um socket a uma porta local Necessário quando for utilizar a função listen() depois sockfd: descritor do socket my_addr: ponteiro para uma struct sockaddr que contém informação sobre seu endereço. nome.

sin_addr.s_addr = INADDR_ANY     Escolha da porta Preenche automaticamente o endereço IP da máquina que o processo está sendo executado bind() retorna -1 se ocorreu um erro Portas abaixo de 1024 são reservadas Pode-se utilizar qualquer porta até 65535 39 .sin_port = 0   Fazendo my_addr.Principais funções  bind()  O processo de pegar o próprio endereço IP e/ou porta pode ser feito automaticamente:  Fazendo my_addr.

Principais funções  connect(int sockfd. nome. porta e endereço IP do destino addrlen: tamanho da estrutura sockaddr 40 . int addrlen)     Conecta com um servidor sockfd: descritor do socket serv_addr: ponteiro para uma struct sockaddr que contém informação sobre endereço. struct sockaddr *serv_addr.

Sockets em C Principais funções  listen(int sockfd. int backlog)   Espera por conexões Processo que:     Primeiro “escuta” Depois “aceita” sockfd: descritor do socket backlog: número de conexões que são aceitas na fila de entrada 41 .

Principais funções  accept(int sockfd. int *addrlen)       Algum processo irá tentar se conectar a uma porta que o servidor está “ouvindo” A conexão será colocada na fila de entrada esperando que seja “aceita” Quando se faz um accept() está aceitando uma conexão pendente sockfd: descritor do socket addr: ponteiro para uma struct sockaddr_in que contém informação sobre a conexão que está chegando addrlen: tamanho da estrutura sockaddr 42 . void *addr.

int flags) receive(int sockfd. int len.Principais funções   send(int sockfd. unsigned int flags)       Para envio e recebimento sockfd: descritor do socket msg: ponteiro para a mensagem que se quer enviar buf: buffer onde a mensagem será colocada len: tamanho da mensagem em bytes flags = 0 43 . int len. void *buf. const void *msg.

const void *msg. int tolen) int recvfrom(int sockfd. void *buf. unsigned int flags. const struct sockaddr *to. int len. int len. struct sockaddr *from.Principais funções   sento(int sockfd. unsigned int flags. int *fromlen). unsigned int flags. 44 . structlen.

Principais funções  close(sockfd)  Fecha uma conexão 45 .

 Retorna um ponteiro para uma estrutura hostent struct hostent { char *h_name.   Retorna o nome do computador que o processo está sendo executado struct hostent *gethostbyname(const char *name). size_t size). char **h_addr_list. int h_length. #define h_addr h_addr_list[0]  46 . }.Principais funções  int gethostname(char *hostname. char **h_aliases. int h_addrtype.

h_length – tamanho do endereço em bytes.Principais funções       h_name – nome do host h_aliases – lista alternativa de nomes. Os hosts são endereçados em Network Byte Order. 47 . h_addrtype – tipo do endereço utilizado. h_addr – Primeiro endereço de h_addr_list. h_addr_list – Array de endereços de rede para o host. normalmente AF_INET.

Cliente/Servidor TCP 48 .

Cliente/Servidor UDP 49 .