Você está na página 1de 62

Comunicao entre processos usando Sockets

Disciplina: Linguagem de Programao IV

Reviso da aula anterior

Reviso do programa fork. Quais so os problemas em relao aos processos pesados ?

Comunicao entre processos


send / receive (troca de mensagens)
RPC (Remote Procedure Call)
C. 1984, ex.: rpcinfo/portmapper. Objetos distribudos. Maior nvel de abstrao.

API: Application Programming interface

API: Modelo de Programao

disponvel em muitos sistemas operacionais ex: Windows NT, Unix, etc. Facilita a Programao Torna as aplicaes mais flexveis

Reviso Sockets

O que um Socket?
Socket uma ponta de uma comunicao ponto-a-ponto entre dois programas rodando em uma rede.

Introduzido em 1981 no UNIX BSD(Berkeley


Software Distribution) 4.1

A API SOCKET

A API SOCKET

A API SOCKET - cont.

Cada aplicao conhece apenas o seu prprio Socket;


Os sockets so explicitamente criados, usados e
liberados pela prpria aplicao;

Baseado no paradigma cliente/servidor;

dois tipos de servio de transporte via API socket:


datagramas no confiveis confiveis, orientado a conexo

Sockets: viso conceitual

cada socket possui o seu prprio buffer para envio


e recepo de dado, nmero de porta, parmetro;

As operaes com o socket so construdas como


chamada a funes do sistema operacional.

Endereamento na Internet

Cada mquina na Internet possui um ou mais


endereos IP 32-bit nicos e globais;

A mquina pode ter 1 ou mais endereos

cada endereo est associado a cada placa de rede

Notao de ponto decimal:

4 inteiros decimais , cada grupo representando um byte de endereo IP.

Endereamento na Internet

A funo inet_addr() converte da notao ponto


decimal para o endereo de 32-bit;

A funo gethostbyname() converte o nome


textual para o ponto decimal.

DNS: Sistema de nomes de Domnio na Internet

uma base de dados distribuda usada por


aplicaes TCP/IP para mapear de/para nomes de mquina para/de endereos IP.

servidor de nomes:

as funes de usurio gethostbyname() e gethostbyaddress() contactam o servidor de nome local atravs da porta 53 o servidor de nomes retorna um endereo IP do nome da mquina solicitada

Criando um socket
Mesmo ponto comum (socket) usado para enviar/receber

dados
no existe, a priori, associao do socket com a rede

deve especificar a famlia de protocolo, bem como o nvel

do servio a ser usado com o socket:

Tipo de servio: Datagrama (SOCK_DGRAM) = UDP Confivel (SOCK_STREAM) = TCP

Criando um socket - cont.


int socket (int family, int service, int protocol)
family um nome simblico para a famlia de protocolos service um nome simblico para o tipo de servio Protocol para uso futuro. Esse valor ser 0. Obs.: O cdigo de retorno da funo socket() um descritor, usado em todas as chamadas ao socket criado.

Exemplo:
#include <sys/types.h> #include <sys/socket.h> int sockfd; if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { /* handle error */ }

Cada socket deve ser associado a uma porta local


que deve ser nica.
A porta uma abstrao do protocolo TCP/IP para distinguir entre mltiplos destinos dentro de uma determinada mquina

Atribuindo um endereo de rede ao socket: bind()

Precisa especificar o endereo de rede

O S.O. sabe que as messagens recebidas naquele endereo e porta devem ser entregues para o socket. Endereo de portas. Ver arquivos /etc/services.

Endereamento de Socket: estruturas de endereo pr-definidas


Especificando endereos de socket: algumas estruturas de dados usadas na implementao:
struct sockaddr_in { short sin_family; /* default AF_INET */ u_short sin_port; /* nmero de 16 bit */ struct in_addr sin_addr; /* endereo de 32 da mquina */ char sin_zero[8]; /* no usado */ }; struct in_addr { u_long s_addr; /* end. 32 bit da mquina */ };

bit

A chamada ao bind()
int bind ( int sockfd, struct sockaddr *myaddr, int addresslen)
sockfd: o nmero do socket obtido anteriormente. *myaddr: especifica o end. local associado ao

socket(inclusive a porta). addresslen: o tamanho da estrutura de endereo

Obs.: se a funo retornar um erro ento o nmero da porta j est em uso ou fora do limite.

A chamada ao bind() - cont.


#include <sys/types.h> #include <sys/socket.h> #include <inet.h> int sockfd; struct sockaddr_in myaddr; if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { /* Manipulador de erro */ } myaddr.sin_family = AF_INET; myaddr.sin_port = htons(5100); myaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* INADDR_ANY = SO determina o hostid */ if ( bind(sockfd, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) { /* Manipulador de erro*/ }

Servio Orientado a Conexo

SERVIDOR
Cria o descritor: socket() para receber pedidos Atribui um endereo ao descritor:bind() Avisa que est aceitando conexes: listen() bloquea/espera novas conexes.: accept()(novos sockets criados na volta)
Troca de msg

CLIENTE
cria o descritor: socket() Atribui ao descritor um endereo (opcional) :bind()

Determina o end. servidor


Conectar o servidor via socket: connect() envia msg: send()
resposta

espera pelo pkt:recv() envia resposta:send() Libera o descritor: close() espera a resp:recv() Libera o descritor: close()

Servio Orientado a Conexo

aperto de mo cliente/servidor:

cliente deve se conectar ao servidor antes de enviar ou receber dados cliente no passar do connect() at o servidor aceit-lo servidor deve aceitar o cliente antes de enviar ou receber dados servidor no passar do accept() at o cliente usar connect()

servio orientado a conexo: servio confivel


oferecido pela camada de transporte.

conexo cliente-para-servidor : connect()

cliente usa connect() para requisitar conexo junto ao servidor protocolo da camada de transporte (ex: TCP) inicia

procedimento para conexo atravs do aperto de mo cliente/servidor connect() retorna quando o servidor aceita a conexo ou time-out (no h resposta) usado com protocolos confiveis, mas tambm com datagramas

Conexo cliente-para-servidor : connect() - cont.


int connect ( int sockfd, struct sockaddr *toaddrptr, int addresslen)

sockfd: nmero do socket atribudo anteriormente. Os processos o usam para enviar conexes aceitas.
*toaddrptr: especifica o end. Remoto (inclusive a porta). Addresslen : o tamanho da estrutura de endereo.

A chamada listen()
Usado por servidores orientados a conexo. avisa a rede/S.O. que o servidor aceitar requisies para conexo. No bloqueia e no espera por requisies!
int listen ( int sockfd, int maxwaiting)

sockfd: nmero do socket atribudo anteriormente. maxwaiting: nmero mximo de conexes que podem ser enfileiradas, enquanto aguardam o servidor executar um accept(). O valor tpico 5.

Executado pelo servidor aps listen().

Conexo servidor-para-cliente : accept()

servidor ir aceitar as novas conexes via socket


novo, isto , retornar um novo nmero de socket para usar na comunicao de volta ao cliente.

Accept() -cont.
int accept ( int sockfd, struct sockaddr *fromaddrptr, int *addresslen)

sockfd nmero do socket atribudo anteriormente.

*fromaddrptr estrutura que contm o endereo do cliente onde enviar as respostas.


Addresslen o tamanho da estrutura de endereo.

Accept() -cont
struct sockaddr_in other_app_addr; int sockid, newsockid, addrsize; addrsize = sizeof(other_app_addr)); newsockid = accept(sockid, (struct sockaddr *) &other_app_addr, &addrsize); /* newsockid to communicate with client, sockid to accept more connections */

Enviando e recebendo dados


Os dados so enviados/recebidos usando chamadas E/S do Unix ou chamadas de rede

send/recv para sockets write/read para qualquer operao de I/O

send()
int send (int sockfd, char *buff, int bufflen, int flags)
sockfd nmero do socket . *buff o endereo do dado a ser enviado. O contedo abriga a

mensagem. bufflen nmero de bytes a enviar. flags controla a transmisso. Para ns ser sempre 0 (zero) . Obs.: retorna o nmero de bytes efetivamente enviado.

Exemplo: usando send()


char buffer[50]; struct sockaddr_in other_app_addr; int retcode /* suppose we have done socket() and bind() calls, filled in other_app_addr,and put 23 bytes of data into buffer */ retcode = send(sockfd, buffer, 23, 0)

recv()
int recv (int sockfd, char *buff, int bufflen, int flags)

sockfd o nmero do socket obtido anteriormente. *buff o endereo onde o dado ser armazenado. bufflen nmero mximo esperado flags controla a recepo. Esse valor ser sempre 0.

Obs.: recv() retorna o nmero de bytes efetivamente recebidos

Exemplo: usando recv()


char buffer[50]; struct sockaddr_in other_app_addr; int nread, addrlen;

/* suppose we have done socket(), bind() */ nread = recv(sockfd, buffer, 23, 0)

Sockets - outras funes

Sockets - estruturas Sockets - funes Ordenao de bytes e converses

Servio no orientado a conexo

Sockets - estruturas
struct sockaddr { // estrutura parmetro de connect()

unsigned short sa_family; // AF_xxx char sa_data[14]; // IP + porta

};

Estrutura paralela para a Internet: struct sockaddr_in {


short int sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; // pad

};

Sockets - estruturas
struct in_addr {
unsigned long s_addr;

sin_port e sin_addr devem estar em Network byte

order. (htonx()), isto , colocar os bytes em ordem de rede antes de mand-los pela rede.
Motivo: so os campos enviados pela rede.

Ordenao de bytes e converses

Ordenao de Bytes
Byte mais significante
chamado de Network byte order (NBO) BigEndian

Byte menos significante


chamado de Host byte order (HBO) LittleEndian

Rotinas de Ordenao de Byte


Rotinas de ordenao de bytes: converte bytes de inteiros

para/de 16 e 32-bits de/para Network Byte Order''


nmeros inteiros devem ser convertido explicitamente para/de Network Byte Order. computadores diferentes podem armazenar os bytes de inteiros em uma ordem diferente na memria. Network Byte Order dita big-endian

Big Endian/Little Endian

Sockets funes
Se tivermos: struct sockaddr_in ina; ina.sin_addr.s_addr = inet_addr(132.241.5.10);
inet_addr() retorna o endereo em NBO.

printf(%s, inet_ntoa(ina.sin_addr));
Seqncia de cdigo para aceitar conexes:
socket(); bind(); listen(); accept();

Procedures do UNIX

htonl converte formato de host de 32 bit para nbo;


ntohl converte nbo para o formato host de 32 bit; htons converte formato de host de 16 bit para nbo; ntohs converte nbo para o formato host de 16 bit.

Servio no Orientado a Conexo

Servio no orientado a conexo


Servio de datagrama: o protocolo da camada de

transporte no garante a entrega do pacote; No h identificao explcita de quem o servidor e quem o cliente; Ao iniciar o contato com o outro lado precisamos saber:
o endereo IP; nmero da porta onde contactar o outro lado.

Ao esperar ser contactado pelo outro lado, precisa

declarar
nmero da porta que est esperando o outro lado

SERVIDOR 1.cria o descritor: socket() 2. atribui ao descritor um endereo: bind() 3. Aguarda pkt chegar: recvfrom() 4. Envia resposta(se houver): sendto()

CLIENTE 1. cria o descritor: socket() 2. Atribui ao descritor um endereo: (opcional) bind()


3. determina endereo do servidor 4. envia msg: sendto() 5. Aguarda chegada do pkt : recvfrom() 6. Libera o descritor: close()

5. Libera o descritor: close()

Exemplo: Servidor no orientado


#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #define MY_PORT_ID 6090 /* numero > 5000 */
main() { int sockid, nread, addrlen; struct sockaddr_in my_addr, client_addr; char msg[50];

Exemplo: Servidor no orientado - cont.


printf("Servidor: criando o socket\n"); if ( (sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ printf("Servidor: erro no socket: %d\n",errno); exit(0); } printf("Servidor: Bindando socket local\n"); bzero((char *) &my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_addr.s_addr = htons(INADDR_ANY); my_addr.sin_port = htons(MY_PORT_ID);

Exemplo: Servidor no orientado - cont.


if ( (bind(sockid, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) ){ printf("Servidor: falha no binding: %d\n",errno); exit(0); } printf("Servidor: iniciando bloqueio de mensagem lida\n"); nread = recvfrom(sockid,msg,11,0, (struct sockaddr *) &client_addr, &addrlen); printf("Servidor: cod retorno lido

%d\n",nread);
if (nread >0) printf("Servidor: mensagem : %.11s\n",msg); close(sockid); }

Exemplo: Cliente no orientado


#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #define MY_PORT_ID 6089 #define SERVER_PORT_ID 6090 #define SERV_HOST_ADDR "128.119.40.186" main() { int sockid, retcode; struct sockaddr_in my_addr, server_addr; char msg[12];

Exemplo: Cliente no orientado - cont.


printf("Cliente: criando socket\n"); if ((sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ printf("Cliente: falha no socket: %d\n",errno); exit(0); } printf("Cliente: amarrando socket local\n"); bzero((char *) &my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_addr.s_addr = htonl(INADDR_ANY); my_addr.sin_port = htons(MY_PORT_ID); if ( ( bind(sockid, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) ){ printf("Cliente: falha no bind: %d\n",errno); exit(0); }

Printf("Cliente: criando estrutura addr para o servidor\n"); bzero((char *) &server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR); server_addr.sin_port = htons(SERVER_PORT_ID);
printf("Cliente: iniciando mensagem e enviando\n"); sprintf(msg, Ola para todos"); retcode = sendto(sockid,msg,12,0,(struct sockaddr *)&server_addr, sizeof(server_addr)); if (retcode <= -1){ printf("cliente: falha no sendto: %d\n",errno); exit(0); } /* close socket */ close(sockid); }

Resumo do Fluxograma TCP / UDP

Uma aplicao de tempo simples:


Cliente: conecta ao servidor envia ao servidor a sua hora local l de volta a hora do servidor

Servidor:

recebe conexes dos clientes imprime a hora local do cliente envia ao cliente a sua hora local

Uma aplicao de tempo simples: cdigo cliente


1 2 3 4 5 6 7 #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <time.h> #include <errno.h> #define SERV_HOST_ADDR "128.119.40.186" /* Don's host machine */ 8 main() 9 { 10 int sockid; 11 struct sockaddr_in ssock_addr; 12 struct timeval tp; 13 struct timezone tzp;

15 16

/* create a socket */

if ((sockid = socket(AF_INET,SOCK_STREAM, 0)) < 0){ 17 printf("erro criacao=%d",errno); 18 exit(0); 19 } 20 21 printf("Criando struct addr p/ server"); 22 bzero((char *) &server_addr, sizeof(server_addr)); 23 server_addr.sin_family = AF_INET; 24 server_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR); 25 server_addr.sin_port = htons(SERVER_PORT_ID); 26 if (connect(sockid, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0){ 27 printf("error connecting to server, error: %d \n",errno); 28 exit(0);

30 /* send time of day */ 31 gettimeofday(&tp,&tzp); 32 /* convert from host byte order to network byte order */ 33 printf("client: local time is %ld \n",tp.tv_sec); 34 tp.tv_sec = htonl(tp.tv_sec); 35 tp.tv_usec = htonl(tp.tv_usec); 38 /* send time of day to other side */ 39 write(sockid, &tp, sizeof(tp)); 40 /* get time of day back fro other side and display */ 41 if ( (read(sockid, &tp, sizeof(tp))) < 0){ 42 printf("error reading new socket \n"); 43 exit(0); 44 } 45

46 /* convert from network byte order to host byte order */ 47 tp.tv_sec = ntohl(tp.tv_sec); 48 tp.tv_usec = ntohl(tp.tv_usec); 49 printf("client: remote time is %ld \n",tp.tv_sec); 50 close(sockid); 51 }

Aplicao de tempo: cdigo servidor


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <time.h> #include <errno.h> #define MY_PORT_ID 6090 main() { int sockid, newsockid, i,j; struct sockaddr_in ssock_addr; struct timeval tp; struct timezone tzp;

17 18 19 20 21 22

23 24 25 26
29 30 31

if ( (sockid = socket (AF_INET, SOCK_STREAM, 0)) < 0) { printf("erro criacao= %d \n",errno); exit(0);} /* man errno */ /* name the socket using wildcards */ bzero((char *) &ssock_addr, sizeof(ssock_addr)); ssock_addr.sin_family = AF_INET; ssock_addr.sin_addr.s_addr = htonl(INADDR_ANY); ssock_addr.sin_port = htons(MY_PORT_ID); /* bind the socket to port address */ if ( ( bind(sockid, (struct sockaddr *) &ssock_addr,sizeof(ssock_addr))< 0)) { printf("error binding socket, error: %d \n",errno); exit(0); } /* start accepting connections */ if ( listen (sockid, 5) < 0) { printf("erro listening: %d \n",errno); exit(0); }

33 34 35 36 37 38 39 40

41
42 43 44

for (i=1; i<=50000 ;i++) { /* accept a connection */ newsockid = accept(sockid, (struct sockaddr *)0, (int *)0); if (newsockid < 0) { printf("error accepting socket, error: %d \n",errno); exit(0); } /* le tempo remoto */ if ( (read(newsockid, &tp, sizeof(tp))) < 0) { printf("error reading new socket \n"); exit(0); } /* convert from network byte order to host byte order */ tp.tv_sec = ntohl(tp.tv_sec); tp.tv_usec = ntohl(tp.tv_usec); printf("server: remote time is %ld \n",tp.tv_sec);

46 /* get local time of day and send to client*/ 47 for (j=0; j<1000000; j++); 48 /* delay */ 49 gettimeofday(&tp,&tzp); 50 /* convert from host byte order to network byte order */ 51 printf("server: local time is %ld \n",tp.tv_sec); 52 tp.tv_sec = htonl(tp.tv_sec); 53 tp.tv_usec = htonl(tp.tv_usec); 54 write(newsockid, &tp, sizeof(tp)); 55 close(newsockid); 56 } 57 close(sockid); 58 }

Bibliografia
COMER, Douglas E. InternetWorking with TCP/IP -VOL

1.

Tutorial sobre sockets: http://beej.us/guide/bgnet/ http://www.newdevices.com/tutoriales/index.html

Sockets em Java:
http://www.javasoft.com/docs/books/tutorial/networking/sockets/d efinition.html

Você também pode gostar