aula 12 - sockets
DESCRIPTION
Material sobre sockets da API BerkeleyTRANSCRIPT
O que são e para que servem os sockets? Os sockets são os programas responsáveis pela
comunicação ou interligação de outros programas na internet.
Quando você se conecta a um serviço qualquer você está usando um socket, no caso chama-se a rotina socket() como cliente de um lado, e do lado do host com serviço, uma rotina de socket servidor.
Existem alguns tipos de sockets. Trabalharemos com os "Stream Sockets“, também conhecido como "SOCK_STREAM".
Stream Sockets usam TCP, e são usados em diversas aplicações como telnet, www, etc. Os pacotes são seqüenciais, seguem em 2 vias, sendo possível ler e gravar.
API Socket API = Application Program Interface:
API é o elemento de ligação entre a aplicação e um sistema de mais baixo nível.
Consiste de algumas funções bem definidas que podem ser usadas pelo usuário na sua aplicação.
Socket: como funciona?
Bibliotecas (headers)
Existem alguns headers usados em conjunto para facilitar ao máximo a programação de sockets. #include <sys/types.h> #include <sys/sockets.h> #include <netinet/in.h> #include <netdb.h>
Declarando um socket
Para se declarar um socket não existe segredo. Ele é do tipo int e declara-se normalmente:
1. main(){2. int Meusocket;3. ...4. }
Definindo uma estrutura Os dados necessários do host a que se quer comunicar, são definidos
através de uma struct. A struct usada para conexões na internet é a sockaddr_in, e possui a seguinte declaração:
struct sockaddr_in { short int sin_family; /* Familia do endereco */ unsigned short int sin_port; /* Numero da porta */ struct in_addr sin_addr; /* IP do Host */ unsigned char sin_zero[8]; /* Zera a estrutura, algum espaco como struct sockaddr */ }
sin_family usa a seguinte sintaxe: + AF_INET (ARPA INTERNET PROTOCOLS) - "A mais usada" + AF_UNIX (UNIX INTERNET PROTOCOLS) + AF_ISO (ISO PROTOCOLS) + AF_NS (XEROX NETWORK SYSTEM PROTOCOLS)
main(){ int Meusocket; struct sockaddr_in endereco; .. }
Construindo um socket A construção de um socket segue o modelo:
Meusocket = socket(sin_family, tipo_do_socket_desejado,Numero_protocolo);
Onde: sin_family são essas já explicadas; tipo_do_socket_desejado, no caso SOCK_STREAM ou
SOCK_DGRAM; Numero_protocolo é o número correspondente do protocolo
que se vai trabalhar,ex: 0 - IP - INTERNET PROTOCOL 1 - ICMP - INTERNET CONTROL MESSAGE PROTOCOL 2 - IGMP - INTERNET GROUP MULTICAST PROTOCOL 3 - GGP - GATEWAY-GATEWAY PROTOCOL 6 - TCP - TRANSMISSION CONTROL PROTOCOL 17 - UDP - USER DATAGRAMA PROTOCOL
Um exemplo prático seria:1. main(){2. int Meusocket; /* Declarando a variável socket */3. ..4. Meusocket = socket(AF_INET,SOCK_STREAM,0);5. ..6. }
Serviço com conexão (TCP)
Função Bind (Associação) Um processo servidor precisa associar um socket a um endereço IP e
uma porta, para avisar o sistema operacional que deseja receber dados que chegam ao host.
bind(Meusocket,(struct sockaddr *)&local,sizeof(struct sockaddr))
Sintaxe: int bind(int Meusocket, struct sockaddr *local, int addrlen);
1. /* Headers */2. #include <string.h>3. #include <sys/types.h>4. #include <sys/socket.h>
5. #define MINHA_PORTA 200006. main(){7. int Meusocket;8. struct sockaddr_in meu_endereco;
9. Meusocket = socket (AF_INET,SOCK_STREAM,0);10. local.sin_family = AF_INET;11. local.sin_port = htons(MINHA_PORTA);12. local.sin_addr.s_addr = inet_addr("200.100.100.1");
13. bind(Meusocket,(struct sockaddr *)&local,sizeof(struct sockaddr));14. ...15. }
Função listen() Para colocar um socket em modo escuta
(servidor) usamos a chamada de sistema listen(): #include <sys/socket.h> int listen( int sockfd, int backlog );
Parâmetros: sockfd: descritor do socket. backlog: Número máximo de conexões
pendentes (fila de conexões para serem atendidas em seqüência).
Retorna 0 em caso de sucesso.
Função accept() Função responsável por aceitar uma
conexão num socket. Um socket cliente pede permissão para um socket servidor para ambos se comunicarem,essa função será a que decidirá o futuro da conexão, se aceita ou rejeita. #include <sys/socket.h> int accept( int sockfd, struct sockaddr *
claddr, socklen_t * len );
Parâmetros Accept() sockfd – o descritor do socket. claddr – a estrutura onde será guardado o
endereço do cliente. len – argumento valor/resultado com o
tamanho da estrutura do endereço. Retorno:
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.
Função connect()
Essa função,como o próprio nome diz, é a função responsável pela conexão do socket cliente com um serviço servidor qualquer. int connect(Meusocket,(struct sockaddr
*) &client, sizeof(endereço));
As Funções send() e recv() A função send() é usada para enviar uma mensagem para um socket. A função recv() é usada para receber dados em um socket. Similares as funções read() e write() do Unix.
int send(int Meusocket, const void *msg, size_t len, int flags);
onde: Meusocket -> é o bom e velho arquivo socket, nosso velho
conhecido. *msg -> é um ponteiro p/ a mensagem que queremos enviar. len -> é o tamanho da mensagem.Se a mensagem é muito grande
para passar atomicamente sobre o protocolo escolhido, a mensagem de erro EMSGSIZE é retornada, e a mensagem não é transmitida.
flags -> São parâmetros adicionais,podem ser: #define MSG_OOB 0x1 /* processa dados out-of-band */ #define MSG_DONTROUTE 0x4 /* debuga */
send(Novosocket, "Seja bem vindo!\n", 16, 0)
int recv(int Meusocket, void *buf, int len, unsigned int flags);
onde: Meusocket -> é o socket para ler de outro,no caso, um
socket local. buf -> Aqui é o endereço da área do buffer. len -> é o tamanho do buffer. + flags -> são formados por MSG_OOB e MSG_PEEK
permitindo receber dados out-of-band e permitindo espiar dados que entram. Esta chamada deve ser usada somente com sockets do tipoSOCK_STREAM.
recv(Meusocket, buf, MAXDATASIZE, 0)
Exemplo servidor: servidor.c1. #include<sys/types.h>2. #include<sys/socket.h>3. #include<netinet/in.h>4. #include<unistd.h>5. #include<stdlib.h>6. #include<stdio.h>
7. main()8. {9. int cont,create_socket,new_socket,addrlen,tempo;10. int bufsize = 128;11. char *buffer = malloc(bufsize);12. struct sockaddr_in address;13. 14. if ((create_socket = socket(AF_INET,SOCK_STREAM,0)) > 0)15. printf("Socket criado!!!\n");16. address.sin_family = AF_INET;17. address.sin_addr.s_addr = INADDR_ANY;18. address.sin_port = htons(15000);
Continuação: servidor.c1. if (bind(create_socket,(struct sockaddr *)&address,sizeof(address)) == 0)2. printf("Escutando...\n");3. listen(create_socket,3);4. addrlen = sizeof(struct sockaddr_in);5. new_socket = accept(create_socket,(struct sockaddr
*)&address,&addrlen);6. if (new_socket > 0){7. printf("O cliente %s esta conectado...\n",inet_ntoa(address.sin_addr));8. for(cont=1;cont<5000;cont++)9. printf("\x7");10. } 11. recv(new_socket,buffer,bufsize,0);12. tempo=atoi(buffer);13. sleep(tempo);14. strcpy (buffer,"Acorde ja se passaram os segundos desejados");15. send(new_socket,buffer,bufsize,0);16. close(new_socket);17. close(create_socket);18. }
Exemplo cliente: cliente.c1. #include<sys/socket.h>2. #include<sys/types.h>3. #include<netinet/in.h>4. #include<unistd.h>5. #include<stdlib.h>6. #include<stdio.h>
7. main(int argc,char *argv[])8. {9. int create_socket;10. int bufsize = 128;11. char *buffer = malloc(bufsize);12. struct sockaddr_in address;13. 14. if (argc<=3)15. {16. printf ("use assim: ./%s ip_servidor SET x , onde x e o tempo em segundos!!!\
n",argv[0]);17. exit (0);18. }
Continuação: cliente.c1. else2. strcpy(buffer,argv[2]);3. if (strcmp(buffer,"SET")==0)4. strcpy(buffer,argv[3]);5. else6. {7. printf ("sua sintaxe contem erro!!!\n");8. exit (0);9. }10. if ((create_socket = socket(AF_INET,SOCK_STREAM,0)) > 0)11. printf("Socket criado!!!\n");12. address.sin_family = AF_INET;13. address.sin_port = htons(15000);14. inet_pton(AF_INET,argv[1],&address.sin_addr);15. 16. if (connect(create_socket,(struct sockaddr *)&address,sizeof(address)) == 0)17. printf("A conexao foi aceita com o servidor %s...\n",inet_ntoa(address.sin_addr));18. send(create_socket,buffer,bufsize,0);19. recv(create_socket,buffer,bufsize,0);20. printf ("%s\n",buffer);21. close(create_socket);22. }
Resumindo: No servidor:
bind(create_socket,(struct sockaddr *)&address, sizeof(address));
listen(create_socket,3); accept(create_socket,(struct sockaddr *)
&address,&addrlen); send(new_socket,buffer,bufsize,0); recv(new_socket,buffer,bufsize,0).
No cliente: connect(create_socket,(struct sockaddr
*)&address,sizeof(address); send(new_socket,buffer,bufsize,0) e
recv(new_socket,buffer,bufsize,0).
Serviço com conexão (TCP)
Referências
Comer, D. E. Redes de Computadores e Internet, Quarta Edição, 2007.
Mariz, D. A Camada de Transporte Socket, 2004.