Redes de Computadores Linguagem de Programação Sockets Ms. Marcello Erick Bonfim
[email protected]
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 #include #include #include
<sys/types.h> <sys/sockets.h>
Declarando um socket
Para se declarar um socket não existe segredo. Ele é do tipo int e declara-se normalmente: 1. 2. 3. 4.
main(){ int Meusocket; ... }
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 AF_UNIX AF_ISO AF_NS
(ARPA INTERNET PROTOCOLS) - "A mais usada" (UNIX INTERNET PROTOCOLS) (ISO PROTOCOLS) (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. 2. 3. 4. 5. 6.
main(){ int Meusocket; /* Declarando a variável socket */ .. Meusocket = socket(AF_INET,SOCK_STREAM,0); .. }
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. 2. 3. 4. 6. 7. 8. 9. 11. 12. 13. 14. 16. 17. 18.
/* Headers */ #include <string.h> #include <sys/types.h> #include <sys/socket.h> #define MINHA_PORTA 20000 main(){ int Meusocket; struct sockaddr_in meu_endereco; Meusocket = socket (AF_INET,SOCK_STREAM,0); local.sin_family = AF_INET; local.sin_port = htons(MINHA_PORTA); local.sin_addr.s_addr = inet_addr("200.100.100.1"); bind(Meusocket,(struct sockaddr *)&local,sizeof(struct sockaddr)); ... }
Função listen()
Para colocar um socket em modo escuta (servidor) usamos a chamada de sistema listen():
Parâmetros:
#include <sys/socket.h> int listen( int sockfd, int backlog ); 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.c 1. 2. 3. 4. 5. 6. 8. 9. 10. 11. 12. 13.
#include<sys/types.h> #include<sys/socket.h> #include #include #include<stdlib.h> #include<stdio.h> main() { int cont,create_socket,new_socket,addrlen,tempo; int bufsize = 128; char *buffer = malloc(bufsize); struct sockaddr_in address;
14. 15. 16. 17. 18. 19.
if ((create_socket = socket(AF_INET,SOCK_STREAM,0)) > 0) printf("Socket criado!!!\n"); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(15000);
Continuação: servidor.c 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
if (bind(create_socket,(struct sockaddr *)&address,sizeof(address)) == 0) printf("Escutando...\n"); listen(create_socket,3); addrlen = sizeof(struct sockaddr_in); new_socket = accept(create_socket,(struct sockaddr *)&address,&addrlen); if (new_socket > 0){ printf("O cliente %s esta conectado...\n",inet_ntoa(address.sin_addr)); for(cont=1;cont<5000;cont++) printf("\x7"); } recv(new_socket,buffer,bufsize,0); tempo=atoi(buffer); sleep(tempo); strcpy (buffer,"Acorde ja se passaram os segundos desejados"); send(new_socket,buffer,bufsize,0); close(new_socket); close(create_socket); }
Exemplo cliente: cliente.c 1. 2. 3. 4. 5. 6.
8. 9. 10. 11. 12. 13.
#include<sys/socket.h> #include<sys/types.h> #include #include #include<stdlib.h> #include<stdio.h> main(int argc,char *argv[]) { int create_socket; int bufsize = 128; char *buffer = malloc(bufsize); struct sockaddr_in address;
14. 15. 16. 17. 18. 19.
if (argc<=3) { printf ("use assim: ./%s ip_servidor SET x , onde x e o tempo em segundos!!!\n",argv[0]); exit (0); }
Continuação: cliente.c 1.
else
strcpy(buffer,argv[2]); if (strcmp(buffer,"SET")==0) strcpy(buffer,argv[3]); else { printf ("sua sintaxe contem erro!!!\n"); exit (0); } if ((create_socket = socket(AF_INET,SOCK_STREAM,0)) > 0) printf("Socket criado!!!\n"); address.sin_family = AF_INET; address.sin_port = htons(15000); inet_pton(AF_INET,argv[1],&address.sin_addr);
2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.
}
if (connect(create_socket,(struct sockaddr *)&address,sizeof(address)) == 0) printf("A conexao foi aceita com o servidor %s...\n",inet_ntoa(address.sin_addr)); send(create_socket,buffer,bufsize,0); recv(create_socket,buffer,bufsize,0); printf ("%s\n",buffer); close(create_socket);
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.