43
Introdução à Programação com Sockets Fernando Jorge Silveira Filho [email protected] Daniel Sadoc Menasché [email protected]

Introdução à Programação com Sockets Fernando Jorge Silveira Filho [email protected] Daniel Sadoc Menasché [email protected]

Embed Size (px)

Citation preview

Page 1: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Introdução à Programação com Sockets

Fernando Jorge Silveira [email protected]

Daniel Sadoc Menasché[email protected]

Page 2: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Visão Geral

• Objetivos:– Realizar comunicação entre processos.– Entender como usar as funções da API

sockets.• Histórico da API sockets: desenvolvida na

época da implementação dos protocolos TCP/IP pelo grupo da UC, Berkeley.

• Inicialmente iremos (re)ver alguns conceitos que serão importantes.

Page 3: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Rotinas do S.O.

Sockets

Comandos no Hardware

Rotinas do Driver

API Sockets

• Application Program Interface – elemento de ligação entre a aplicação e um sistema de mais baixo nível.

Aplicação

Transporte

Rede

Enlace de Dados

Física

Sistema Operacional(Kernel)

Drivers e Hardware

Aplicação Final

Page 4: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Conceitos Importantes

• Argumentos de Valor/Resultado• Descritores de Arquivo• Chamadas de Sistema de E/S• Byte Ordering• Portas e Endereços IP• Associações & Conexões• Serviços de Transporte

Page 5: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Argumentos de Valor/Resultado• É possível (e comum) na linguagem C, utilizar o recurso

de passagem de argumentos por referência para passar valores para uma função ao mesmo tempo em que se espera um valor de retorno na mesma variável.

• Exemplo: imagine uma função is_prime() que retorna 1 se um número apontado por um ponteiro n é primo e 0 (zero) se composto. Neste último caso, a função também retorna o número primo mais próximo do valor passado. Este segundo valor de retorno pode ser colocado no próprio endereço de memória referenciado por n.

int is_prime( int * n ){ /* verifica se (*n) é primo e em caso negativo coloca o primo mais próximo em (*n) */}

Page 6: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Descritores de Arquivos

• Números inteiros não negativos que são ponteiros para estruturas de dados do sistema que representam os arquivos abertos por um processo.

7 26 15 50 39 21xDescritores

de Arquivo yz

Imagem do Processo Estruturas do S.O.

zz

Page 7: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Chamadas de Sistema de E/S

• Operações básicas que podem ser realizadas com arquivos.

• open, close, read, write.#include <unistd.h>

int open( const char * filename, int oflag, ... );

int close( int fd );

size_t read( int fd, void * buffer, size_t n_bytes );size_t write( int fd, void * buffer, size_t n_bytes );

Page 8: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

• Como um valor é armazenado na memória?• Exemplo: 16909060 = 0x01020304

• Para evitar conflitos entre hosts de arquiteturas diferentes é convencionado que informações de controle na rede são armazenadas em Big-Endian.

Byte Ordering

Big-Endian Little-Endian

01

02

03

04

n

n+1

n+2

n+3

Endereço Memória

04

03

02

01

n

n+1

n+2

n+3

Endereço Memória

Page 9: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Endereços IP e Portas• Endereços IP identificam hosts na rede TCP/IP

e são formados por 4 bytes, normalmente chamado octetos por razões históricas.

• Portas são identificadores dos processos interessados em usar os recursos de rede em um host. Portas ocupam 2 bytes na memória.

• Ambos tipos de variáveis são armazenadas no byte order da rede (Big-Endian).

146 164 10 2 39990

92 A4 0A 02 9C 36Notação Padrão

Hexadecimal

Page 10: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Associações

• Um processo precisa associar um socket a um endereço para “avisar” ao sistema operacional que deseja receber dados que chegam ao host com o endereço de destino especificado.

602789

1026

102

Processos2023

146.164.41.10 : 80

2541

146.164.41.10 : 21

146.164.41.10 : 20

EndereçoAssociadoS

ocke

ts

602789

1026

102

Processos2023

146.164.41.10 : 80

2541

146.164.41.10 : 21

146.164.41.10 : 20

146.164.41.10 : 56

EndereçoAssociadoS

ocke

ts

Page 11: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Conexões

• Um socket pode ser conectado a um endereço diferente do seu próprio para que pacotes possam ser enviados por ele diretamente ao processo parceiro.

602Processo

20

EndereçoAssociadoS

ocke

t

200.128.40.12 : 10020

EndereçoConectado

146.164.41.10 : 13003

Page 12: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Serviços de Transporte

• A camada de transporte dos protocolos TCP/IP fornece duas opções de tipos de serviço:– Serviço orientado a conexão: utiliza o

protocolo TCP (Transmission Control Protocol) e garante entrega e ordenação.

– Serviço datagrama: utiliza o protocolo UDP (User Datagram Protocol) e não faz nenhuma garantia.

Page 13: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Esquema de umaAplicação TCP

• Um par de aplicações que se comunicam por TCP em geral tem a seguinte forma:

accept( )

close( )

connect( )

socket( )

socket( )

bind( )

listen( )

close( )

Estabelecimentoda Conexão TCP

Cliente

Servidor

writen( )

readn( )

readn( )

writen( )

readn( )

Page 14: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Esquema de umaAplicação TCP

• Um par de aplicações que se comunicam por TCP em geral tem a seguinte forma:

accept( )

close( )

connect( )

socket( )

socket( )

bind( )

listen( )

close( )

Estabelecimentoda Conexão TCP

Cliente

Servidor

writen( )

readn( )

readn( )

writen( )

readn( )

ter telefone associar número

ao telefoneligar alarme

responder chamadafazer chamada

Page 15: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets - Criação• Utiliza-se a chamada de sistema socket():

• Parâmetros:– domain – o tipo de rede do socket. Usamos AF_INET (Address

Family Internet). Outros tipos: AF_LOCAL, AF_INET6.– type – o tipo de serviço de transporte. Para sockets TCP usamos

SOCK_STREAM, para UDP usamos SOCK_DGRAM.– protocol – o protocolo utilizado. Passando 0 (zero) é utilizado o

padrão.• A função retorna um descritor do socket criado ou –1 em

caso de erro.

#include <sys/types.h>#include <sys/socket.h>

int socket( int domain, int type, int protocol );

Page 16: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets - Endereços• Endereços IP e portas são

armazenados em estruturas do tipo struct sockaddr_in.

• sin_family é o tipo do endereço. AF_INET deve ser usado.

• sin_port é a porta associada ao endereço.

• sin_addr é uma estrutura que contém o endereço IP (os 4 octetos).

• O endereço IP e a porta devem ser armazenados no byte order da rede (Big-Endian).

#include <netinet/in.h>

struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; /* ... outros campos */};

struct in_addr { in_addr_t s_addr;};

uint16 htons( uint16 data_in_host_order );uint16 ntohs( uint16 data_in_net_order );

uint32 htonl( uint32 data_in_host_order );uint32 ntohl( uint32 data_in_net_order );

Page 17: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets - Associação• Utiliza-se a chamada de sistema bind():

• Parâmetros:– sockfd – o descritor do socket.– my_addr – a estrutura com o endereço para ser associado.– addrlen – o tamanho da estrutura do endereço.

• A função retorna 0 (zero) em caso de sucesso ou –1 no caso de um erro.

• Erro comum: EADDRINUSE (“Address already in use”)

#include <sys/types.h>#include <sys/socket.h>

int bind( int sockfd, struct sockaddr *my_addr, socklen_t addrlen );

Page 18: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets – Traduzindo Endereços IP

• Para converter um endereço IP entre as formas de string e binária:

• A função inet_aton() converte um endereço na notação do ponto (1.2.3.4) para o formato binário em byte order de rede (como a struct sockaddr_in espera) e retorna 0 (zero) em caso de sucesso.

• A função inet_ntoa() faz a conversão oposta.

#include <arpa/inet.h>

int inet_aton(const char * str, struct in_addr * addrptr);char * inet_ntoa(struct in_addr addr);

Page 19: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets – Resolvendo Nomes com DNS

• Para resolver nomes de hosts (www.land.ufrj.br) para endereços IP (146.164.47.193) usamos as rotinas de acesso ao serviço DNS:

#include <netdb.h>

struct hostent * gethostbyname(const char * str);

struct hostent { int h_length; /* tamanho do endereço */ char **h_addr_list; /* lista de endereços */ char *h_addr; /* primeiro endereço */ /* ... outros campos */}

Page 20: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets TCP• Sockets orientados a conexão com garantias de entrega

e ordenação.• É preciso estabelecer a conexão antes da troca de

dados.• O servidor cria um socket especial para “escutar”

pedidos de conexão do cliente.• Cada vez que o servidor aceita um pedido de conexão

recebido no socket de escuta, um novo socket é criado para realizar a comunicação. Assim é possível para o servidor voltar a aceitar novos pedidos de conexão mais tarde (usando o socket de escuta).

Page 21: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets TCP – listen()• Para por um socket em modo de escuta usamos a

chamada de sistema listen():

• Parâmetros:– sockfd – o descritor do socket.– backlog – a soma das filas de conexões completas e

incompletas. Este parâmetro é extremamente dependente da implementação do Sistema Operacional.

• O valor de retorno da função é 0 (zero) em caso de sucesso ou –1 caso contrário.

#include <sys/socket.h>

int listen( int sockfd, int backlog );

Page 22: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets TCP – accept()• Esta função aceita pedidos de conexão pendentes ou fica

bloqueada até a chegada de um.

• Parâmetros:– sockfd – o descritor do socket.– cliaddr – a estrutura onde será guardado o endereço do cliente.– addrlen – argumento valor/resultado com o tamanho da

estrutura do endereço.• O valor de retorno da função é um novo descritor (não

negativo) em caso de sucesso ou –1 caso contrário.• Cada novo descritor retornado por accept() está

associado à mesma porta do socket de escuta.

#include <sys/socket.h>

int accept( int sockfd, struct sockaddr * cliaddr, socklen_t * addrlen );

Page 23: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets TCP – send()• Usada para enviar dados por um socket conectado.

• Parâmetros:– sockfd – o descritor do socket.– buffer – um ponteiro para os dados a serem enviados.– n_bytes – quantidade de bytes a serem enviados a partir do

ponteiro buffer.– flags – opções para essa operação.

• O valor de retorno da função é a quantidade de bytes enviados em caso de sucesso ou –1 caso contrário.

#include <sys/socket.h>

int send( int sockfd, void * buffer, size_t n_bytes, int flags );

Page 24: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets TCP – recv()• Recebe dados por um descritor conectado, ou bloqueia

a execução até que algum dado chegue ao socket:

• Parâmetros:– sockfd – o descritor do socket.– buffer – um ponteiro para a área de memória onde devem ser

armazenados os dados recebidos.– n_bytes – quantidade máxima de bytes a serem recebidos.– flags – opções para essa operação.

• O valor de retorno da função é a quantidade de bytes recebidos em caso de sucesso ou –1 caso contrário.

#include <sys/socket.h>

int recv( int sockfd, void * buffer, size_t n_bytes, int flags );

Page 25: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Atenção para uma Armadilha!•As funções

read, recv, recvfrom, write, send e sendtopodem retornar menos bytes do que a quantidade requisitada, e nenhuma mensagem de erro é retornada neste caso!•Solução: ao usar as funções recv, recvfrom, send e sendto pode-se (deve-se!) passar como parâmetro a flag MSG_WAITALL.

Page 26: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Atenção para uma Armadilha!•As funções read e write não devem ser utilizadas! Ao invés disto, deve-se usar as funções de “embrulho” (“wrap functions”) readn e writen.

ssize_t readn(int fd, const void *vptr, size_t n){ size_t nleft; ssize_t nread; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( ( nread = read ( fd, ptr, nleft ) ) <=0 ) { if (errno == EINTR) nread = 0; else return (-1); } else if ( nread == 0) break; /* EOF */ nleft -= nread; ptr += nread; } return (n - nleft);}

Page 27: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>

int main( int argc, char ** argv ){ int sockfd; char recvline[30]; struct sockaddr_in servaddr;

if( argc != 2 ) return –1;

sockfd = socket( AF_INET, SOCK_STREAM, 0 );

memset( &servaddr, 0, sizeof(servaddr) ); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(12345); inet_aton( argv[1], &servaddr.sin_addr );

connect( sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr) );

readn( sockfd, recvline, 30 ); fputs( recvline, stdout ); close( sockfd );

return 0;}

Exemplo – Um Cliente TCP

Inicializar a estrutura servaddr com zeros.

Preencher os campos da estrutura servaddr:

sin_family com o tipo de endereço (AF_INET)

sin_port com a porta (12345) no byte order da rede.

sin_addr com o endereço passado como argumento para o programa.

Conecta o socket com o endereço do servidor (servaddr). Isto irá estabelecer a conexão TCP entre o cliente e o servidor.

Lê 30 bytes do socket. Esta função pode ler menos bytes se o outro lado (o servidor) fechar a conexão.

Imprime os dados recebidos na saída padrão.

Fecha o socket.

Criar um socket para rede TCP/IP (AF_INET), orientado a conexão (SOCK_STREAM), usando TCP (o protocolo padrão dado por 0).

Page 28: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <netinet/in.h>

int main( int argc, char ** argv ){ int listenfd, connfd, size; struct sockaddr_in myaddr, cliaddr;

listenfd = socket( AF_INET, SOCK_STREAM, 0 );

memset( &myaddr, 0, sizeof(myaddr) ); myaddr.sin_family = AF_INET; myaddr.sin_port = htons(12345); myaddr.sin_addr.s_addr = INADDR_ANY;

bind( listenfd, (struct sockaddr *)&myaddr, sizeof(myaddr) );

listen( listenfd, 5 );

for( ; ; ) { memset( &cliaddr, 0, sizeof(cliaddr) ); size = sizeof( cliaddr ); connfd = accept( listenfd, (struct sockaddr *)&cliaddr, &size ); writen( connfd, “Alo Mundo”, 10 ); close( connfd ); }

return 0;}

Preencher a estrutura do endereço local (myaddr) para associação com o socket:

sin_addr contém o endereço IP pelo qual o processo deseja receber pacotes. Como uma máquina pode ter vários IPs, é mais prático especificar que se deseja receber pacotes para qualquer um deles. Para isso usamos a constante INADDR_ANY.

Exemplo – Um Servidor TCP

Associar o endereço preenchido com o socket, para informar o S.O. de que o processo deseja receber pacotes para este endereço.

Aguarda um pedido de conexão.

Envia uma mensagem de 10 bytes pelo socket.

Fecha o socket da conexão.

Volta a aceitar novos pedidos.

Colocar o socket em modo de escuta. Isto cria uma fila de pedidos de conexão para o socket.

Page 29: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Servidores Concorrentes• Muitas vezes é necessário para um servidor lidar

com vários clientes de uma única vez. Para conseguir isto é preciso, de alguma maneira, voltar a aceitar conexões, sem esperar que um cliente seja completamente servido.

• Isto normalmente é feito através da criação de novas threads ou novos processos.

• Um servidor, após o retorno da função accept(), se divide em dois, e enquanto uma linha de execução se dedica a atender o cliente, outra volta a esperar por novos pedidos de conexão.

Page 30: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Servidores concorrentesEsquema de um Servidor Típico

pid_t pid;int listenfd, confd;

listenfd = socket(...);bind(listenfd, ...);listen(listenfd, LISTENQ);

for( ; ; ) {connfd = accept(listenfd, ...);

if ( ( pid = fork() ) == 0 ){

close(listenfd);doit(connfd);close(connfd);exit(0)

}close (connfd);

}

Page 31: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Conclusões sobre sockets TCP• Um par de aplicações que se comunicam por TCP em

geral tem a seguinte forma:

accept( )

close( )

connect( )

socket( )

socket( )

bind( )

listen( )

close( )

Troca de Dados

Estabelecimentoda Conexão TCP

Cliente

Servidor

ServidoresConcorrentes

Page 32: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets UDP• Sockets sem conexão e sem garantias de entrega ou

ordenação.• Só é preciso saber o endereço de destino antes de

enviar dados. É possível receber dados a qualquer momento e de qualquer um. Usamos as funções sendto() e recvfrom().

• Pode-se ainda usar a função connect() com sockets UDP, mas o seu significado aqui é diferente, uma vez que NÃO faz sentido falar em uma conexão UDP. Para sockets UDP, a função connect() apenas “fixa” o endereço conectado. Assim é possível usar as funções send() e recv() como para sockets TCP.

Page 33: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets UDP – sendto()• Envia dados por um socket NÃO conectado.

• Parâmetros:– sockfd – o descritor do socket.– buffer – um ponteiro para os dados a serem enviados.– n_bytes – quantidade de bytes a serem enviados.– flags – opções para essa operação.– to – endereço de destino dos dados.– addrlen – tamanho em bytes do endereço de destino.

• O valor de retorno da função é a quantidade de bytes enviados em caso de sucesso ou –1 caso contrário.

#include <sys/socket.h>

int sendto( int sockfd, void * buffer, size_t n_bytes, int flags, const struct sockaddr * to, socklen_t addrlen );

Page 34: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Sockets UDP – recvfrom()• Recebe dados por um descritor NÃO conectado, ou bloqueia a execução

até que algum dado chegue:

• Parâmetros:– sockfd – o descritor do socket.– buffer – um ponteiro para a área de memória onde devem ser armazenados os

dados recebidos.– n_bytes – quantidade máxima de bytes a serem recebidos.– flags – opções para essa operação.– from – ponteiro para a estrutura onde será escrito o endereço de origem.– addrlen – argumento valor/resultado com o tamanho do endereço de origem.

• O valor de retorno da função é a quantidade de bytes recebidos em caso de sucesso ou –1 caso contrário.

#include <sys/socket.h>

int recvfrom( int sockfd, void * buffer, size_t n_bytes, int flags, struct sockaddr * from, socklen_t * addrlen );

Page 35: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>

int main( int argc, char ** argv ){ int sockfd; struct sockaddr_in servaddr;

if( argc != 2 ) return –1;

sockfd = socket( AF_INET, SOCK_DGRAM, 0 );

memset( &servaddr, 0, sizeof(servaddr) ); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(12345); inet_aton( argv[1], &servaddr.sin_addr );

sendto( sockfd, “Alo Servidor”, 13, MSG_WAITALL,

(struct sockaddr *)&servaddr, sizeof(servaddr) );

close( sockfd );

return 0;}

Exemplo – Um Cliente UDP

Inicializar a estrutura servaddr com zeros.

Preencher os campos da estrutura servaddr:

sin_family com o tipo de endereço (AF_INET)

sin_port com a porta (12345) no byte order da rede.

sin_addr com o endereço passado como argumento para o programa.

Envia 13 bytes de dados para o servidor.

Criar um socket para rede TCP/IP (AF_INET), orientado a datagramas (SOCK_DGRAM), usando UDP (o protocolo padrão dado por 0).

Page 36: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <netinet/in.h>

int main( int argc, char ** argv ){ int sockfd, size, n; struct sockaddr_in myaddr;

sockfd = socket( AF_INET, SOCK_DGRAM, 0 );

memset( &myaddr, 0, sizeof(myaddr) ); myaddr.sin_family = AF_INET; myaddr.sin_port = htons(12345); myaddr.sin_addr.s_addr = INADDR_ANY;

bind( sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr) );

for( ; ; ) { recvfrom( sockfd, recvline, 30,

MSG_WAITALL, NULL, NULL ); fputs( recvline, stdout ); }

return 0;}

Exemplo – Um Servidor UDP

Associar o endereço preenchido com o socket, para informar o S.O. de que o processo deseja receber pacotes para este endereço.

Aguarda até 30 bytes. É possível para esta função retornar antes se o outro lado enviar um datagrama menor.

Imprime os dados recebidos na saída padrão.

Page 37: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Conclusões sobre sockets UDP• Um par de aplicações que se comunicam por UDP em

geral tem a seguinte forma:

close( )

socket( ) socket( )

bind( )

close( )

Troca de Dados

Cliente Servidor

bind( )

Page 38: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

• Esta é a forma mais simples de depurar aplicações que envolvem sockets, threads e mais de um processo.

• Atenção! Deve-se gerar as mensagens de aviso em ‘stderr’ (que não possui buffer) e não ‘stdout’!

• Inconveniente desta técnica de depuração: pode afetar o funcionamento do programa.

Depurando: Passo 0,Exibindo mensagens de aviso

Page 39: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Depurando: Passo 1,A Máquina de Estados

Comando chave: netstat -a

Page 40: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

[sadoc@copa src]$ netstat -a | grep 32568Proto Local Address Foreign Address State tcp *:32568 *:* LISTEN tcp localhost:47415 localhost:32568 ESTABLISHED tcp localhost:32568 localhost:47415 ESTABLISHED

[sadoc@copa src]$ netstat -a | grep 32568tcp localhost:47415 localhost:32568 CLOSE_WAIT tcp localhost:32568 localhost:47415 FIN_WAIT2

Depurando: Passo 1, A Máquina de Estados do TCP

Comando chave: netstat -a

wildcard

Page 41: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

• tcpdump -x src host_name > log_file

• Programa equivalente, com interface gráfica: ethereal

Depurando: Passo 2,O comando tcpdump

Imprime o conteúdo de cada pacote,em hexadecimal

Fonte dos pacotes

Page 42: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Lições Aprendidas

Page 43: Introdução à Programação com Sockets Fernando Jorge Silveira Filho fernando@land.ufrj.br Daniel Sadoc Menasché sadoc@land.ufrj.br

Bibliografia Recomendada

• Stevens, W. R. – UNIX Network Programming: Volume I – Networking APIs: Sockets and XTI

• Stevens, W.R. – TCP/IP Illustrated vol.1• Besaw, L. – BSD Sockets Reference

(formato PostScript (.ps) em www.land.ufrj.br/~classes/tp/index-103.html).