Professional Documents
Culture Documents
Viso Geral
Objetivos:
Realizar comunicao entre processos. Entender como usar as funes da API sockets.
Histrico da API sockets: desenvolvida na poca da implementao dos protocolos TCP/IP pelo grupo da UC, Berkeley. Inicialmente iremos (re)ver alguns conceitos que sero importantes.
API Sockets
Application Program Interface elemento de ligao entre a aplicao e um sistema de mais baixo nvel.
Aplicao Final Aplicao Sockets Transporte Sistema Operacional (Kernel) Rotinas do S.O. Rede Rotinas do Driver Enlace de Dados Drivers e Hardware Fsica Comandos no Hardware
Conceitos Importantes
Argumentos de Valor/Resultado Descritores de Arquivo Chamadas de Sistema de E/S Byte Ordering Portas e Endereos IP Associaes & Conexes Servios de Transporte
Argumentos de Valor/Resultado
possvel (e comum) na linguagem C, utilizar o recurso de passagem de argumentos por referncia para passar valores para uma funo ao mesmo tempo em que se espera um valor de retorno na mesma varivel. Exemplo: imagine uma funo is_prime() que retorna 1 se um nmero apontado por um ponteiro n primo e 0 (zero) se composto. Neste ltimo caso, a funo tambm retorna o nmero primo mais prximo do valor passado. Este segundo valor de retorno pode ser colocado no prprio endereo de memria referenciado por n.
int is_prime( int * n ) { /* verifica se (*n) primo e em caso negativo coloca o primo mais prximo em (*n) */ }
Descritores de Arquivos
Nmeros inteiros no negativos que so ponteiros para estruturas de dados do sistema que representam os arquivos abertos por um processo.
Imagem do Processo Descritores de Arquivo Estruturas do S.O. x
7 26 15 50 39 21
z
z z
Byte Ordering
Como um valor armazenado na memria? Exemplo: 16909060 = 0x01020304
Big-Endian
Endereo Memria Endereo
Little-Endian
Memria
n
n+1 n+2 n+3
01
02 03 04
n
n+1 n+2 n+3
04
03 02 01
Para evitar conflitos entre hosts de arquiteturas diferentes convencionado que informaes de controle na rede so armazenadas em Big-Endian.
Endereos IP e Portas
Endereos IP identificam hosts na rede TCP/IP e so formados por 4 bytes, normalmente chamado octetos por razes histricas. Portas so identificadores dos processos interessados em usar os recursos de rede em um host. Portas ocupam 2 bytes na memria. Ambos tipos de variveis so armazenadas no byte order da rede (Big-Endian).
Notao Padro Hexadecimal 146 92 164 A4 10 0A 2 02 39990 9C 36
Associaes
Um processo precisa associar um socket a um endereo para avisar ao sistema operacional que deseja receber dados que chegam ao host com o endereo de destino especificado.
Sockets
Endereo Associado
Sockets
Endereo Associado
Conexes
Um socket pode ser conectado a um endereo diferente do seu prprio para que pacotes possam ser enviados por ele diretamente ao processo parceiro.
Socket Processo 602
Endereo Associado Endereo Conectado 200.128.40.12 : 10020
20 146.164.41.10 : 13003
Servios de Transporte
A camada de transporte dos protocolos TCP/IP fornece duas opes de tipos de servio:
Servio orientado a conexo: utiliza o protocolo TCP (Transmission Control Protocol) e garante entrega e ordenao. Servio datagrama: utiliza o protocolo UDP (User Datagram Protocol) e no faz nenhuma garantia.
bind( )
listen( )
accept( ) readn( )
writen( )
writen( )
bind( )
listen( )
Estabelecimento da Conexo TCP
fazer chamada
connect( )
accept( ) readn( )
writen( )
writen( )
Sockets - Criao
Utiliza-se a chamada de sistema socket():
#include <sys/types.h> #include <sys/socket.h>
int socket( int domain, int type, int protocol );
Parmetros:
domain o tipo de rede do socket. Usamos AF_INET (Address Family Internet). Outros tipos: AF_LOCAL, AF_INET6. type o tipo de servio de transporte. Para sockets TCP usamos SOCK_STREAM, para UDP usamos SOCK_DGRAM. protocol o protocolo utilizado. Passando 0 (zero) utilizado o padro.
Sockets - Endereos
Endereos IP e portas so armazenados em estruturas do tipo struct sockaddr_in. sin_family o tipo do endereo. AF_INET deve ser usado. sin_port a porta associada ao endereo. sin_addr uma estrutura que contm o endereo IP (os 4 octetos). O endereo IP e a porta devem ser armazenados no byte order da rede (BigEndian).
#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 );
Sockets - Associao
Utiliza-se a chamada de sistema bind():
#include <sys/types.h> #include <sys/socket.h> int bind( int sockfd, struct sockaddr *my_addr, socklen_t addrlen );
Parmetros:
sockfd o descritor do socket. my_addr a estrutura com o endereo para ser associado. addrlen o tamanho da estrutura do endereo.
A funo retorna 0 (zero) em caso de sucesso ou 1 no caso de um erro. Erro comum: EADDRINUSE (Address already in use)
A funo inet_aton() converte um endereo na notao do ponto (1.2.3.4) para o formato binrio em byte order de rede (como a struct sockaddr_in espera) e retorna 0 (zero) em caso de sucesso. A funo inet_ntoa() faz a converso oposta.
struct hostent { int h_length; char **h_addr_list; char *h_addr; /* ... outros campos }
Sockets TCP
Sockets orientados a conexo com garantias de entrega e ordenao. preciso estabelecer a conexo antes da troca de dados. O servidor cria um socket especial para escutar pedidos de conexo do cliente. Cada vez que o servidor aceita um pedido de conexo recebido no socket de escuta, um novo socket criado para realizar a comunicao. Assim possvel para o servidor voltar a aceitar novos pedidos de conexo mais tarde (usando o socket de escuta).
Parmetros:
sockfd o descritor do socket. backlog a soma das filas de conexes completas e incompletas. Este parmetro extremamente dependente da implementao do Sistema Operacional.
Parmetros:
sockfd o descritor do socket. cliaddr a estrutura onde ser guardado o endereo do cliente. addrlen argumento valor/resultado com o tamanho da estrutura do endereo.
O valor de retorno da funo um novo descritor (no negativo) em caso de sucesso ou 1 caso contrrio. Cada novo descritor retornado por accept() est associado mesma porta do socket de escuta.
Parmetros:
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 opes para essa operao.
O valor de retorno da funo a quantidade de bytes enviados em caso de sucesso ou 1 caso contrrio.
Parmetros:
sockfd o descritor do socket. buffer um ponteiro para a rea de memria onde devem ser armazenados os dados recebidos. n_bytes quantidade mxima de bytes a serem recebidos. flags opes para essa operao.
O valor de retorno da funo a quantidade de bytes recebidos em caso de sucesso ou 1 caso contrrio.
podem retornar menos bytes do que a quantidade requisitada, e nenhuma mensagem de erro retornada neste caso! Soluo: ao usar as funes recv, recvfrom, send e sendto pode-se (devese!) passar como parmetro a flag MSG_WAITALL.
com o endereo do servidor int Inicializar a estrutura servaddr main( int argc, char ** argv ) (servaddr { com zeros. ). Isto ir int sockfd; a conexo osdo campos da Preencher L estabelecer 30 bytes socket. Esta char recvline[30]; TCP entre o cliente e o estrutura servaddr : funo pode ler menos bytes struct sockaddr_in servaddr; servidor. o sin_family com o tipo de se outro lado (o servidor)
endereo fechar a2 conexo. if( argc != ) (AF_INET) return sin_port com a porta (12345) 1; Imprime os dados recebidos
orientado a conexo connect( sockfd, (SOCK_STREAM ), (struct sockaddr *)&servaddr, usando TCP (o protocolo); sizeof(servaddr) padro dado por 0).
readn( sockfd, recvline, 30 ); fputs( recvline, stdout ); close( sockfd ); return 0;
na sada padro. sin_addr com o endereo sockfd = socket( AF_INET, Fecha o socket. passado como argumento SOCK_STREAM,
para o programa. 0 );
de o 10 S.O. bytes de que pelo osocket. modo de escuta. Isto listenfd = socket( AF_INET, Fecha processo o socket deseja da cria uma fila de SOCK_STREAM, 0 ); conexo. receber pacotes para pedidos de conexo Volta este a endereo. aceitar novos memset( &myaddr, 0, sizeof(myaddr) ); para o socket. myaddr.sin_family pedidos. = AF_INET;
myaddr.sin_port = htons(12345); myaddr.sin_addr.s_addr = INADDR_ANY;
}
memset( &cliaddr, 0,pelo qual o endereo IP sizeof(cliaddr) ); processo deseja size = sizeof( cliaddr ); pacotes. connfdreceber = accept( listenfd,Como uma sockaddr mquina*)&cliaddr, pode ter (struct vrios &size ); IPs, mais writen( connfd, Alo Mundo, 10 ); prtico especificar que close( connfd ); receber se deseja
sin_addr contm o
pacotes para qualquer return 0;um deles. Para isso usamos a constante } INADDR_ANY.
Servidores Concorrentes
Muitas vezes necessrio para um servidor lidar com vrios clientes de uma nica vez. Para conseguir isto preciso, de alguma maneira, voltar a aceitar conexes, sem esperar que um cliente seja completamente servido. Isto normalmente feito atravs da criao de novas threads ou novos processos. Um servidor, aps o retorno da funo accept(), se divide em dois, e enquanto uma linha de execuo se dedica a atender o cliente, outra volta a esperar por novos pedidos de conexo.
close (connfd); }
listen( )
Estabelecimento da Conexo TCP
connect( )
accept( )
Servidores Concorrentes
Troca de Dados
close( ) close( )
Sockets UDP
Sockets sem conexo e sem garantias de entrega ou ordenao. S preciso saber o endereo de destino antes de enviar dados. possvel receber dados a qualquer momento e de qualquer um. Usamos as funes sendto() e recvfrom(). Pode-se ainda usar a funo connect() com sockets UDP, mas o seu significado aqui diferente, uma vez que NO faz sentido falar em uma conexo UDP. Para sockets UDP, a funo connect() apenas fixa o endereo conectado. Assim possvel usar as funes send() e recv() como para sockets TCP.
Parmetros:
sockfd o descritor do socket. buffer um ponteiro para os dados a serem enviados. n_bytes quantidade de bytes a serem enviados. flags opes para essa operao. to endereo de destino dos dados. addrlen tamanho em bytes do endereo de destino.
O valor de retorno da funo a quantidade de bytes enviados em caso de sucesso ou 1 caso contrrio.
Parmetros:
sockfd o descritor do socket. buffer um ponteiro para a rea de memria onde devem ser armazenados os dados recebidos. n_bytes quantidade mxima de bytes a serem recebidos. flags opes para essa operao. from ponteiro para a estrutura onde ser escrito o endereo de origem. addrlen argumento valor/resultado com o tamanho do endereo de origem.
O valor de retorno da funo a quantidade de bytes recebidos em caso de sucesso ou 1 caso contrrio.
Envia 13 bytes de zeros. { com sockfd; para dados servidor. int Preencher os o campos da struct sockaddr_in servaddr; estrutura servaddr :
if( argc != 2 ) endereo (AF_INET) return 1;
memset( &servaddr, 0, sizeof(servaddr) ); servaddr.sin_family = AF_INET; htons(12345); Criar servaddr.sin_port um socket para = rede inet_aton( argv[1], TCP/IP (AF_INET ), &servaddr.sin_addr );
orientado a datagramas (SOCK_DGRAM ), Alo usando sendto( sockfd, Servidor, 13, UDP (o protocolo padro MSG_WAITALL, (struct sockaddr *)&servaddr, dado por 0 ).
sizeof(servaddr) ); close( sockfd ); } return 0;
sin_port com a porta (12345) no byte order da rede. sockfd = socket( AF_INET, sin_addr SOCK_DGRAM, com o endereo passado como 0 ); argumento para o programa.
bytes. possvel para esta int Associar o ** endereo int main( argc, char argv ) funo retornar antes { preenchido com o se int sockfd, size, n; enviar um o socket, outro lado para informar struct sockaddr_in myaddr; datagrama o S.O. de menor. que o Imprime os dados sockfd processo = socket( AF_INET, deseja recebidos na sada receber SOCK_DGRAM, pacotes para0 ); padro. este endereo.
Servidor
socket( )
bind( )
Troca de Dados
close( ) close( )
[sadoc@copa src]$ netstat -a | grep 32568 tcp localhost:47415 localhost:32568 CLOSE_WAIT tcp localhost:32568 localhost:47415 FIN_WAIT2
Lies Aprendidas
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).