A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Programação com sockets API Sockets apareceu no BSD4.1 UNIX em 1981 são explicitamente criados, usados e liberados por aplicações paradigma cliente/servidor.

Apresentações semelhantes


Apresentação em tema: "Programação com sockets API Sockets apareceu no BSD4.1 UNIX em 1981 são explicitamente criados, usados e liberados por aplicações paradigma cliente/servidor."— Transcrição da apresentação:

1 Programação com sockets API Sockets apareceu no BSD4.1 UNIX em 1981 são explicitamente criados, usados e liberados por aplicações paradigma cliente/servidor dois tipos de serviço de transporte via API Sockets: datagrama não confiável fluxo de bytes, confiável Socket é uma interface (uma porta), local ao hospedeiro, criada por e pertencente à aplicação, e controlado pelo SO, através da qual um processo de aplicação pode tanto enviar como receber mensagens para/de outro processo de aplicação (remoto ou local) socket Meta: aprender a construir aplicações cliente/servidor que se comunicam usando sockets

2 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.

3 Rotinas do S.O.SocketsComandos no HardwareRotinas do Driver API Sockets Application Program Interface – Elemento de ligação entre uma aplicação e um sistema operacional de mais baixo nível. AplicaçãoTransporteRedeEnlace de DadosFísica Sistema Operacional (Kernel) Drivers e Hardware Aplicação Final

4 Programação com sockets usando TCP Socket: Uma porta entre o processo de aplicação e um protocolo de transporte fim-a-fim (UDP ou TCP) Serviço TCP: Transferência confiável de bytes de um processo para outro processo TCP com buffers, variáveis socket Controlado pelo programador de aplicação Controlado pelo sistema operacional estação ou servidor processo TCP com buffers, variáveis socket Controlado pelo programador de aplicação Controlado pelo sistema operacional estação ou servidor internet

5 Cliente deve contactar servidor: processo servidor deve antes estar em execução servidor deve antes ter criado socket (porta) que aguarda contato do cliente Cliente contacta servidor para: criar socket TCP local ao cliente especificar endereço IP, número de porta do processo servidor Quando cliente cria socket: TCP cliente cria conexão com TCP do servidor Quando contatado pelo cliente, o TCP do servidor cria socket novo para que o processo servidor possa se comunicar com o cliente permite que o servidor converse com múltiplos clientes Endereço IP e porta origem são usados para distinguir os clientes TCP provê transferência confiável, ordenada de bytes (tubo) entre cliente e servidor ponto de vista da aplicação Programação com sockets usando TCP

6 Comunicação entre sockets

7 TCP: Gerenciamento de Conexões Lembrete: Remetente, receptor TCP estabelecem conexão antes de trocar segmentos de dados inicializam variáveis TCP: nos. de seq. buffers, info s/ controle de fluxo (p.ex. RcvWindow ) cliente: iniciador de conexão servidor: contatado por cliente Inicialização em 3 tempos: Passo 1: sistema cliente envia segmento de controle SYN do TCP ao servidor especifica no. inicial de seq não envia dados Passo 2: sistema servidor recebe SYN, responde com segmento de controle SYNACK aloca buffers especifica no. inicial de seq. servidor-> receptor Passo 3: receptor recebe SYNACK, responde com segmento ACK que pode conter dados.

8 TCP: Gerenciamento de Conexões (cont.) Encerrando uma conexão: cliente fecha soquete: Passo 1: sistema cliente envia segmento de controle FIN ao servidor Passo 2: servidor recebe FIN, responde com ACK. Encerra a conexão, enviando FIN. cliente FIN servidor ACK FIN fechar fechada espera temporizada

9 TCP: Gerenciamento de Conexões (cont.) Passo 3: cliente recebe FIN, responde com ACK. Entre em espera temporizada - responderá com ACK a FINs recebidos Passo 4: servidor, recebe ACK. Conexão encerrada. cliente FIN servidor ACK FIN fechando fechada espera temporizada fechada

10 TCP: Gerenciamento de Conexões (cont.) Ciclo de vida de cliente TCP Ciclo de vida de servidor TCP

11 Conceitos Importantes da Linguagem C e UNIX Argumentos de Valor/Resultado Chamadas de Sistema de E/S Descritores de Arquivo Byte Ordering Portas e Endereços IP Associações & Conexões Serviços de Transporte

12 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) */ }

13 Chamadas de Sistema de E/S UNIX usa para toda E/S o paradigma open-read-write-close. Por exemplo, open prepara um arquivo e retorna um descritor, que será utilizado depois para operações read/write. O close fecha o arquivo. #include 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 );

14 Descritores São números inteiros não negativos que são ponteiros para estruturas de dados do sistema que representam os arquivos/dispositivos abertos por um processo x Descritores de Arquivo y z Imagem do ProcessoEstruturas do S.O. z z

15 A comunicação por sockets também usa descritores. Quando um socket é aberto, retorna um descritor, que pode ser utilizado por outras funções, como p-ex read e write.

16 Define como um valor é armazenado na memória. Exemplo: = 0x 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-EndianLittle-Endian n n+1 n+2 n+3 EndereçoMemória n n+1 n+2 n+3 EndereçoMemória

17 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 A40A029C36 Notação Padrão Hexadecimal

18 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 Processos : : : 20 Endereço Associado Sockets Processos : : : : 56 Endereço Associado Sockets

19 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. 602 Processo 20 Endereço Associado Socket : Endereço Conectado : 13003

20 accept( ) close( ) connect( ) socket( ) bind( ) listen( ) close( ) Estabelecimento da Conexão TCP Cliente Servidor writen( ) readn( ) writen( ) readn( ) Sockets em uma aplicação TCP Funções da API de sockets utilizadas para um cliente e um servidor se comunicarem usando TCP: ter telefone associar número ao telefone ligar campainha atender chamada desligar conversar fazer chamada desligar conversar

21 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 int socket( int domain, int type, int protocol );

22 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 para endereçamento IPv4. 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 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 );

23 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 int bind( int sockfd, struct sockaddr *my_addr, socklen_t addrlen );

24 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 ( ) 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 int inet_aton(const char * str, struct in_addr * addrptr); char * inet_ntoa(struct in_addr addr);

25 Sockets – Resolvendo Nomes com DNS Para resolver nomes de hosts (www.land.ufrj.br) para endereços IP ( ) usamos as rotinas de acesso ao serviço DNS: #include 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 */ }

26 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).

27 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 int listen( int sockfd, int backlog );

28 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 int accept( int sockfd, struct sockaddr * cliaddr, socklen_t * addrlen );

29 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 int send( int sockfd, void * buffer, size_t n_bytes, int flags );

30 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 int recv( int sockfd, void * buffer, size_t n_bytes, int flags );

31 #include 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 ).

32 #include 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.

33 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.

34 Servidores concorrentes Esquema 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); }

35 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( ) bind( ) listen( ) close( ) Troca de Dados Estabelecimento da Conexão TCP Cliente Servidor Servidores Concorrentes

36 Programação com sockets usando UDP UDP: não tem conexão entre cliente e servidor não tem handshaking remetente coloca explicitamente endereço IP e porta do destino servidor deve extrair endereço IP, porta do remetente do datagrama recebido UDP: dados transmitidos podem ser recebidos fora de ordem, ou perdidos UDP provê transferência não confiável de grupos de bytes (datagramas) entre cliente e servidor ponto de vista da aplicação

37 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.

38 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 int sendto( int sockfd, void * buffer, size_t n_bytes, int flags, const struct sockaddr * to, socklen_t addrlen );

39 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 int recvfrom( int sockfd, void * buffer, size_t n_bytes, int flags, struct sockaddr * from, socklen_t * addrlen );

40 #include 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 ).

41 #include 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.

42 Conclusões sobre sockets UDP Um par de aplicações que se comunicam por UDP em geral tem a seguinte forma: close( ) socket( ) bind( ) close( ) Troca de Dados Cliente Servidor bind( )

43 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

44 Depurando: Passo 1, A Máquina de Estados Comando chave: netstat -a

45 src]$ netstat -a | grep Proto Local Address Foreign Address State tcp *:32568 *:* LISTEN tcp localhost:47415 localhost:32568 ESTABLISHED tcp localhost:32568 localhost:47415 ESTABLISHED src]$ netstat -a | grep tcp 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

46 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

47 2b: Camada de Aplicação Bibliografia Recomendada Stevens, W. R. – UNIX Network Programming: Volume I – Networking APIs: Sockets and XTI Comer, D.E.; Stevens, D.L. – TCP/IP Client-Server Programming and Aplications, vol.3, Linux POSIX Socket Version Frost J. – BSD Sockets: A quick and dirty primer. ts.html).


Carregar ppt "Programação com sockets API Sockets apareceu no BSD4.1 UNIX em 1981 são explicitamente criados, usados e liberados por aplicações paradigma cliente/servidor."

Apresentações semelhantes


Anúncios Google