2004-2013 Volnys Bernal 1 2004-2013 Volnys Bernal 2 Resumo das Chamadas TCP Volnys Borges Bernal volnys@lsi.usp.br http://www.lsi.usp.br/~volnys 2004-2013 Volnys Bernal 3 2004-2013 Volnys Bernal 4 Resumo das Chamadas TCP Resumo das Chamadas TCP Lado Cliente Lado Servidor sd1 connect() Detalhamento Lado Servidor sd2 2004-2013 Volnys Bernal 5 2004-2013 Volnys Bernal 6 Chamada Chamada Criar um novo socket (plug de comunicação) Resultado Retorna um descritor de arquivo. int socket (int domain, int type, int protocol) Observação: Quando um socket é criado ele não possui nenhuma informação armazenada (endereços IPs e portas). Endereços IPs e portas são informados nas chamadas (lado servidor) e connect() (lado cliente). 1
2004-2013 Volnys Bernal 7 2004-2013 Volnys Bernal 8 Chamada #include <sys/socket.h> int socket(int domain, int type, int protocol) Socket descriptor Pilha de protocolos PF_INET PF_INET6 PF_X25 Tipo da comunicação SOCK_STREAM (TCP) SOCK_DGRAM (UDP, TCP) SOCK_RAW (IP) Id. do protocolo UDP (17) TCP (6) Chamada Exemplo de criação de socket TCP #include <sys/socket.h> int sd; sd = socket(pf_inet, SOCK_STREAM, 6) if (sd == -1) perror( Erro na chamada socket ); Obs: O valor 6 representa o protocolo TCP, foi obtido consultando /etc/protocols. Pode também ser obtido através de resolução de nomes via getprotobyname(). 2004-2013 Volnys Bernal 9 2004-2013 Volnys Bernal 10 Associar um socket address (IP+porta) ao socket Deve ser utilizado no lado servidor 0: sucesso 1: erro 2004-2013 Volnys Bernal 11 2004-2013 Volnys Bernal 12 Descritor do socket int bind( int sd, Resultado da chamada: sucesso ou erro Endereço IP da interface local. Pode ser o endereço IP de: Uma interface específica Todas interfaces locais(inaddr_any) struct sockaddr *myaddr, socklen_t addrlen) Tamanho da estrutura de endereço (sockaddr) Exemplo de utilização struct sockaddr_in mylocal_addr mylocal_addr.sin_family = AF_INET; mylocal_addr.sin_addr.s_addr = INADDR_ANY; mylocal_addr.sin_port = htons(myport); status = bind(socketdescriptor, (struct sockaddr *) &mylocal_addr, sizeof(struct sockaddr_in)); perror( Erro na chamada bind ); 2
2004-2013 Volnys Bernal 13 2004-2013 Volnys Bernal 14 Abrir a porta na qual o servidor ira aguardar conexões TCP As conexões são aceitas através da ativação de 0: sucesso 2004-2013 Volnys Bernal 15 2004-2013 Volnys Bernal 16 Resultado da função: 0: sucesso -1: erro Descritor do socket int listen(int sd, int queuelenght) Qde máxima de conexões pendentes sem aceite Exemplo: #define QLEN 10... status = listen(sd,qlen); if (status!= 0) { perror("erro na chamada "); exit(1); } 2004-2013 Volnys Bernal 17 2004-2013 Volnys Bernal 18 Chamada Chamada Aceitar uma nova conexão TCP. Accept() extrai a primeira conexão da fila e gera um novo socket descriptor para esta conexão. O socket original não é afetado por esta chamada. Valor não negativo: sucesso, sendo este o valor do novo socket descriptor 3
2004-2013 Volnys Bernal 19 2004-2013 Volnys Bernal 20 Chamada Valor retornado: Positivo: sucesso, correspondendo ao valor do novo socket -1: erro int accept (int sd, struct sockaddr *addr, socklen_t *addrlen) Tamanho da estrutura socketaddr Descritor do socket Ponteiro para uma estrutura sockaddr que conterá o endereço (socket address) do parceiro de comunicação Chamada Exemplo int newsd; int size; struct sockaddr_in clientaddr;... size = sizeof(clientaddr); newsd = accept( sd, (struct sockaddr *) &clientaddr, (socklen_t *) &size); if (newsd < 0) { perror("erro na chamada "); exit(1); }... 2004-2013 Volnys Bernal 21 2004-2013 Volnys Bernal 22 Chamada Chamada Recepção/leitura de dados de um descritor Descritor: descritor sockets, descritor de arquivo,... Pode ser utilizada por cliente ou servidor >0: quantidade de bytes lidos 0: end of file 2004-2013 Volnys Bernal 23 2004-2013 Volnys Bernal 24 Chamada : #include <unistd.h> int read(int sd, void *buf, int buffersize) Socket Descriptor Tamanho do buffer Chamada Exemplo: status = read(sd, bufferp, buffersize) perror( Erro na chamada read ); Ponteiro para o buffer (end. do buffer de recepção) 4
2004-2013 Volnys Bernal 25 2004-2013 Volnys Bernal 26 Chamada Chamada Transmissão/escrita de dados em um descritor Descritor: descritor sockets, descritor de arquivo,... Pode ser utilizada por cliente ou servidor Positivo: quantidade de bytes escritos 2004-2013 Volnys Bernal 27 2004-2013 Volnys Bernal 28 Chamada Chamada Exemplo: #include <unistd.h> int write(int sd, void *buf, int count) Socket Descriptor Tamanho da mensagem status = write(sd,txbuffer, strlen(txbuffer)+1) perror( Erro na chamada write ); Ponteiro para mensagem (end. do buffer da mensagem) 2004-2013 Volnys Bernal 29 2004-2013 Volnys Bernal 30 Chamada Chamada Permite fechar o socket (assim como é feito com arquivo) Existem dois sockets abertos. É importante fechar os dois sockets. Código de exemplo para fechar um socket: int sd; // socketdescriptor status = close(sd); perror( Erro na chamada close ); 5
2004-2013 Volnys Bernal 31 2004-2013 Volnys Bernal 32 1. Implemente um servidor TCP echo que transforma para maiúsculas. O programa deve atender a um cliente TCP e, quando receber a mensagem quit deve encerrar a conexão com o cliente e terminar o programa Dicas: Utilize a rotina de biblioteca toupper() para converter um caractere minúsculo para maiúsculo. Utilize a rotina de biblioteca strcmp() para comparar a string recebida com quit. #include <string.h> If (strcmp(bufferp, quit )==0) /* igual */ 2004-2013 Volnys Bernal 33 2004-2013 Volnys Bernal 34 sd1 Servidor Não Concorrente x Concorrente sd2 2004-2013 Volnys Bernal 35 2004-2013 Volnys Bernal 36 Servidor não concorrente x concorrente Não concorrente Processa uma requisição por vez Concorrente Tem capacidade para r mais que uma requisição simultaneamente Mais complexo Mais difícil de implementar Necessita uma implementação multithreaded concorrente Lado Cliente Lado Servidor connect() 6
2004-2013 Volnys Bernal 37 2004-2013 Volnys Bernal 38 Fazer um servidor TCP echo concorrente. Cliente (1) Pedido de conexão Servidor Main Dica: existem diversas formas de implementar o controle dos threads: sockets (a) Utilizar uma tabela de controle de conexões estabelecidas com cada entrada da tabela contendo os seguintes campos: ocupado, estrutura dos threads (thread_t), semáforo para o thread e socket (new socket). (b) Utilizar a estrutura produtor-consumidor. O produtor é o thread principal: produz novas conexões (socket descriptors). O consumidor são os threads de trabalho: consomem conexões (socket descriptors). Um consumidor, ao receber o socket descriptor fica responsável pela interação com o cliente até que a conexão seja encerrada. 1 2 3 2004-2013 Volnys Bernal 39 2004-2013 Volnys Bernal 40 Cliente Servidor Main sockets Referências Bibliográficas 1 (2) dados 2 3 2004-2013 Volnys Bernal 41 Referências Bibliográficas COMMER, DOUGLAS; STEVENS, DAVID Internetworking with TCP/IP: volume 3: client-server programming and applications Prentice Hall 1993 7