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
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....
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
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.}
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.
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> 6. #define MINHA_PORTA 20000 7. main(){ 8. int Meusocket;
9. struct sockaddr_in meu_endereco;
11. Meusocket = socket (AF_INET,SOCK_STREAM,0); 12. local.sin_family = AF_INET;
13. local.sin_port = htons(MINHA_PORTA);
14. local.sin_addr.s_addr = inet_addr("200.100.100.1");
16. bind(Meusocket,(struct sockaddr *)&local,sizeof(struct sockaddr)); 17. ...
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).
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 *
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á
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
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 */
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.
Exemplo servidor: servidor.c
1. #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> 8. main() 9. { 10. int cont,create_socket,new_socket,addrlen,tempo; 11. int bufsize = 128;12. char *buffer = malloc(bufsize); 13. struct sockaddr_in address; 14.
15. if ((create_socket = socket(AF_INET,SOCK_STREAM,0)) > 0) 16. printf("Socket criado!!!\n");
17. address.sin_family = AF_INET;
Continuação: servidor.c
1. 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.c
1. #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>8. main(int argc,char *argv[]) 9. {
10. int create_socket; 11. int bufsize = 128;
12. char *buffer = malloc(bufsize); 13. struct sockaddr_in address; 14.
15. if (argc<=3) 16. {
17. printf ("use assim: ./%s ip_servidor SET x , onde x e o tempo em
segundos!!!\n",argv[0]);
18. exit (0); 19. }
Continuação: cliente.c
1. else 2. strcpy(buffer,argv[2]); 3. if (strcmp(buffer,"SET")==0) 4. strcpy(buffer,argv[3]); 5. else 6. {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);
Resumindo:
No servidor: