• Nenhum resultado encontrado

Cliente/Servidor. Programação com Sockets. Graça Bressan. Graça Bressan/LARC

N/A
N/A
Protected

Academic year: 2021

Share "Cliente/Servidor. Programação com Sockets. Graça Bressan. Graça Bressan/LARC"

Copied!
25
0
0

Texto

(1)

Cliente/Servidor

Programação com Sockets

(2)

Interface através de Sockets

Socket é uma API ( Aplication Program Interface ) para acesso aos serviços do protocolo de transporte do TCP/IP.

As duas principais APIs de comunicação do Unix, para uso em C, são:

• Sockets da versão de Berkeley

• TLI ( Trasport Layer Interface ) da versão ATT.

Camadas de protocolos TCP/IP

Interface através de Sockets

A maioria dos fabricantes, em especial os fabricantes de workstations, como Sun e DEC, adotaram o BSD Unix. Portanto, a interface Sockets tornou-se disponível em muitas máquinas e acabou sendo amplamente aceita.

(3)

Interface de Programação para Arquivos

Operação Significado

open Prepara um dispositivo ou um arquivo para operações de E/S.

close Termina o uso do dispositivo ou arquivo previamente aberto.

read Obtém dados de um dispositivo ou arquivo e coloca na memória.

write Transmite dados da memória para dispositivo ou arquivo.

Interface de Programação para Arquivos

Quando um programa executa a função open para iniciar uma operação de E/S, o sistema retorna um inteiro denominado descritor de arquivos que a aplicação usa nas próximas operações de E/S.

O open recebe três argumentos:

• Nome do arquivo ou do dispositivo a ser aberto.

• modo de acesso

• Um conjunto de bits para caso especiais

Ao terminar de usar o arquivo, a aplicação chama close para liberar o descritor e os recursos a ele associados (como buffers).

(4)

read ( desc, buffer, 128 );

(c) Fechar o arquivo ao término das operações: close ( desc );

Interface de Programação de Sockets

A API de socket foi incluída como uma extensão das operações sobre arquivos:

• Descritores análogos aos de arquivo serão usados para comunicação de dados por sockets.

• As chamadas de sistema, read e write, com descritores de sockets serão usadas para envio e recebimento de dados, de forma análoga às operações convencionais de arquivos.

A aplicação deve especificar:

• As portas dos protocolos local e remoto.

• Os endereços IP local e remoto

• Se elas usarão TCP ou UDP

• Se iniciará a conexão ou irá esperar por uma conexão, isto é, se ela vai se comportar como cliente ou como servidor.

Interface de Sockets

Um socket armazena uma associação entre uma porta TCP e um endereço IP.

Um socket pode ser Passivo ou Ativo:

Socket Passivo: um socket criado para esperar conexões de outras estações. Este tipo de socket é utilizado por aplicações servidoras;

Socket Ativo: um socket utilizado para iniciar uma conexão. Este tipo de socket é utilizado por aplicações clientes.

Abstração de um Socket

Descritores de sockets e descritores de arquivos

No Unix, um aplicativo que precisa efetuar uma E/S chama a função open para criar um descritor de arquivo que será usado para acessar o

(5)

O sistema operacional implementa descritores de arquivos em uma tabela de ponteiros para as estruturas de dados internos de cada dispositivo.

Tabela de Descritores

Interface de Sockets

Cada processo tem uma tabela de descritores de arquivos.

Quando um processo abre um arquivo, o Sistema Operacional coloca na tabela de descritores um ponteiro apontando para a estrutura de dados deste arquivo.

O descritor retornado pelo open, é o índice da entrada nesta tabela.

Como um arquivo, cada socket ativo é identificado por um número inteiro denominado descritor de socket.

O Unix aloca o descritor de socket na mesma tabela de descritores de arquivos.

(6)

Estrutura de dados do sockets

Quando uma aplicação chama socket, o sistema operacional aloca uma estrutura de dados que contém as informações necessárias para a comunicação e coloca um ponteiro para essa estrutura na tabela de descritores.

Estrutura de dados do sockets

Quando um socket é criado o sistema deixa muito dos campos da estrutura vazios e que devem ser preenchidos por outras chamadas de sistema.

Após a criação do socket e preenchimento de seus campos, ele pode ser usado para:

• Esperar por uma conexão (servidor) ou

• Iniciar uma conexão (cliente).

Conexão

Uma conexão é uma associação entre dois sockets.

Cada um dos sockets de uma conexão são chamados de "end-points". Um socket usado para esperar por uma conexão é denominado socket passivo.

(7)

Endereço Final

Os pontos extremos da comunicação são os processos de cliente e servidor, cada um rodando em um sistema. Estes processos são identificados pelos seus endereços finais.

Em uma rede Internet, os 2 processos podem estar em rede diferentes, conectados por um ou mais roteadores.

Consiste de 3 níveis de endereços:

• Endereço de rede

• Endereço do host conectado na rede

• Endereço do processo no host.

O TCP/IP usa um inteiro de 32 bits para especificar a rede e o host, e tanto TCP como UDP usam números de porta de 16 bits para especificar o processo do usuário.

A maioria das famílias de protocolos definem um conjunto de endereços " bem conhecidos " que são usados para identificar os serviços fornecidos pelo host.

Exemplo: A implementação do TCP/IP fornece um servidor de

transferência de arquivos denominado FTP que um cliente pode contactar para transferir um arquivo. A porta para FTP é definida como sendo 21.

Conexão e Endereços Finais

• Quando um socket é criado, ele não contém os endereços finais que serão utilizados na conexão.

• Portanto, antes de usar um socket, o endereço final ou os endereços finais devem ser especificados.

(8)

Conexões entre Sockets

Interface de Sockets

(9)

Exemplo de Cliente/servidor usando TCP

Interface através de Sockets com UDP

O cliente não estabelece conexão com o servidor. Em vez disso, manda datagramas através de sendto(), que requer endereço do destino (servidor) como argumento.

O servidor, por sua vez, não espera por uma conexão. Ele apenas chama recvfrom(), que espera indefinidamente até um dado chegar de algum cliente.

A chamada recvfrom() retorna ao chamador, o endereço IP e de porta do processo cliente junto com o datagrama, de forma que o servidor possa enviar uma resposta ao cliente correto.

(10)
(11)

Interface de Sockets

socket (pf, type, protocol)

Cria um novo socket que pode ser usado para comunicação. Retorna um descritor de socket.

Os argumentos para a chamada especificam:

• A família de protocolos que a aplicação vai usar ( por exemplo, PF_INET para TCP/IP).

• Tipo de serviço (por ex. stream ou datagram ).

• Protocolo ( ex. TCP ou UDP ).

connect (socket, destaddr, addrlen)

Depois de criar um socket, um cliente chama connect para estabelecer uma conexão com um servidor remoto.

Os argumentos para a chamada são:

• O descritor de socket obtido com socket.

• Ponteiro para uma estrutura do tipo sockaddr contendo o endereço final remoto.

•O connect deixa o socket ligado permanentemente ao endereço destino, isto é, no estado conectado, desde que use serviço com conexão (TCP). Nos serviços sem conexão ele guarda apenas o endereço remoto. Para serviços sem conexão não é necessário usar connect, mas se usar, não será necessário especificar o endereço remoto toda vez que for fazer

(12)

• Descritor de socket.

• Endereço onde está o dado.

• Tamanho do dado em bytes.

O write copia os dados a serem enviados em buffers do sistema

operacional e permite que a aplicação continue a sua execução enquanto o dado é transmitido pela rede. Se o buffer estiver cheio, o write bloqueia o processo temporariamente até que TCP esvazie o buffer.

A alternativa ao write para o modo não conectado é:

sendto (socket, buffer, length, flags, destaddr, addrlen)

read (socket, buffer, length)

Tanto cliente como servidor usam read para receber dados da conexão TCP, servidores usam read para receber solicitações e os clientes para receber resposta.

Os argumentos para a chamada são:

• Descritor de socket.

• Endereço de um buffer.

• Tamanho do buffer.

O read extrai os bytes que chegam no socket e copia-os no buffer. Se não chegou nenhum dado, a chamada de read bloqueia a execução do

processo.

Se tiver mais dados que o tamanho do buffer, o read extrai apenas o suficiente para encher o buffer.

Se vier menos, extrai todos os bytes e retorna o número de bytes. Read também pode ser usado para receber mensagens em sockets que usam UDP. Nesse caso, cada read extrai um datagrama UDP.

Outra alternativa para socket não conectado é:

(13)

close (socket)

Essa chamada termina a conexão, desalocando um socket.

Se vários processos estiverem compartilhando um mesmo socket, close decrementa um contador e desaloca o socket quando o contador atingir zero.

O argumento para essa chamada é o descritor de socket.

bind (socket, localaddr, addrlen)

Uma aplicação chama bind para associar um endereço final local a um socket.

É usado por servidores para especificar uma porta conhecida através da qual vai esperar por uma conexão.

Os argumentos de um bind são:

• Descritor de socket.

• Ponteiro para um endereço final.

Para os protocolos TCP/IP, o endereço final usa a estrutura sockaddr_in, que inclui um endereço IP e um número de porta.

listen (socket, qlength)

Quando um socket é criado, ele não é ativo nem passivo.

Os servidores orientados a conexão, chamam listen para colocar o socket no modo passivo e deixa-lo preparado para receber conexões.

(14)

de conexão e retorna o descritor deste socket. Este novo socket utiliza a mesma porta do socket inicial.

O servidor usa o novo socket apenas para a nova conexão e usa o socket original para aceitar novas solicitações.

Uma vez aceita a nova conexão, o servidor pode transferir dados através do novo socket.

Resumo de Comandos da Interface de Sockets

Nome da

Função Significado

socket Cria um descritor para usar na comunicação connect Conecta a um par remoto

write Envia dados através da conexão read Recebe dados vindos da conexão

close Termina comunicação e desaloca o socket

bind Associa um endereço IP local e uma porta do protocolo aum socket

listen Coloca o socket no modo passivo e estabelece o número deconexõesTCP que devem ser enfileiradas.

accept Aceita a próxima conexão. recv Recebe o próximo datagrama. recvmsg Variação de recv

recvfrom Recebe o próximo datagrama e registra o endereço final doremetente

send Envia um datagrama sendmsg Variação do send

(15)

pré-registrado

shutdown Termina uma conexão TCP em uma ou ambas as direções

getpeername Depois que uma conexão chega, obtem o endereço finalremoto

getsockopt Obtem as opções atuais de um socket setsockopt Muda a opção de um socket

Utilitários para conversão de inteiros.

O TCP/IP utiliza a representação chamada "ordem de bytes da rede"

(network byte order), para inteiros usados nos cabeçalhos dos protocolos. Esta representação representa números inteiros com o byte mais

significativo primeiro, isto é, no endereço menor (representação big endian).

Embora o software de protocolos esconda a maioria dos detalhes, os programadores devem estar cientes deste padrão porque algumas rotinas de sockets exigem que argumentos sejam armazenados na ordem de bytes da rede. Ex.: A estrutura sockaddr_in usa a ordem de bytes da rede.

A interface socket possui várias funções que fazem a conversão entre ordem de bytes da rede e a do host.

Estas funções são usadas mesmo sabendo que a máquina tem a mesma ordem de bytes da rede. Assim, o programa fica portável para diversas arquiteturas.

(16)

Exemplo de Cliente/Servidor

O Exemplo a ser examinado é de um programa servidor que cada vez que é acessado retorna o valor de um contador contendo o número de

acessos ao servidor.

O retorno é na forma da seguinte cadeia ASCII : "Este servidor foi contatado 10 vezes."

O cliente é um programa simples que contata o servidor e obtém o texto acima.

A porta escolhida para o servidor é a 5193. Funções Utilizadas pelo Programa

gethostbyname (domínio)

Parâmetro: nome do computador no domínio ao qual pertence Retorna o endereço IP deste computador.

Ex.: endIP = gethostbyname("merlin.usp.br");

getprotobyname (protocolo) Parâmetro: nome do protocolo

Retorna número que identifica o protocolo no sistema. Ex.: numprot = getprotobyname("tcp");

(17)

Estrutura do Cliente e Servidor

Código do Cliente

/* client.c - código do programa cliente utilizando TCP */ #ifndef unix

#define WIN32

#include <windows.h> #include <winsock.h> #else

#define closesocket close #include <sys/types.h> #include <sys/socket.h>

(18)

extern int errno;

char localhost[] = "localhost"; /* nome default do host */ /*---* Programa: cliente

*

* Objetivo: alocar um socket, conectar ao servidor e imprimir * todas saídas.

* Sintaxe: cliente [ host [porta] ]

* host - nome do computador no qual o servidor * está executando.

* porta - número da porta que o servidor está * utilizando.

* Nota: Os argumentos são opcionais. Se o host não for * informado o cliente utiliza "localhost"; se nenhuma * porta de for especificada, o cliente utiliza a porta * default dada por PROTOPORT.

*---*/ main(argc, argv)

int argc; char *argv[]; {

struct hostent *ptrh; /* ponteiro entrada tabela de host */ struct protoent *ptrp; /* ponteiro entrada tab. protocolo */ struct sockaddr_in sad;/* estrutura para end. do servidor */ int sd; /* descritor de socket */

int port; /* número da porta */

char *host; /* ponteiro para o nome do host */ int n; /* número de caracteres para leitura */

char buf[1000]; /* buffer para os dados do servidor */ #ifdef WIN32

(19)

WSAStartup(0x0101, &wsaData); #endif

memset((char *)&sad,0,sizeof(sad)); /* limpa sockaddr */ sad.sin_family = AF_INET; /* seta familia Internet*/

/* analisa a linha de comando e obtem o nome do host e o número da porta caso tenham sido especificados. */

if (argc > 2) /* Verifica se a porta é especificada */ port = atoi(argv[2]); /* obtem a porta e conv. binário*/ else port = PROTOPORT; /* usa o número da porta default*/ if (port > 0) /* testa se o valor é válido */

sad.sin_port = htons ((u_short) port); else {

fprintf(stderr,"numero de porta incorreta:%s\n",argv[2]); exit(1);

}

if (argc > 1) /* Verifica o parâmetro que define o host */ host = argv[1]; /* se o host foi especificado */

else host = localhost;

/* Converte nome de host no endereço IP equivalente */ ptrh = gethostbyname(host);

if (((char *) ptrh) == NULL ) {

fprintf(stderr,"host invalido: %s\n", host); exit (1);

(20)

sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto); if (sd < 0) {

fprintf(stderr,"falha na criacao do socket\n"); exit(1);

}

/* Conecta o socket ao servidor especificado */

if (connect(sd,(struct sockaddr*)&sad,sizeof(sad)) < 0) { fprintf(stderr,"falha na conexao\n");

exit(1); }

/* Le repetidamente dados do socket e escreve na tela */ n = recv(sd, buf, sizeof(buf), 0);

while (n > 0) { write(1, buf, n);

n = recv(sd, buf, sizeof(buf), 0); }

/* fecha o socket */ closesocket(sd);

/* Termina o programa cliente */ exit(0);

}

Código do Servidor

/* servidor.c - código do programa servidor utilizando TCP */ #ifndef unix

#define WIN32

#include <windows.h> #include <winsock.h> #else

#define closesocket close #include <sys/types.h>

(21)

#include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #endif #include <stdio.h> #include <string.h>

#define PROTOPORT 5193 /* número da port default */ #define QLEN 6 /* tamanho da fila de requisicoes*/ int visitas = 0; /* cont. de conexões de clientes */ /*---* Programa: servidor /*---*

* Objetivo: aloca um socket, e repetidamente executa: * (1) espera a proxima conexão de cliente

(2) envia uma mensagem curta ao cliente (3) fecha a conexão

(d) volta ao passo (1) * Sintaxe: servidor [porta] *

* porta - número da porta que o servidor deverá utilizar * Nota: O número da porta é opcional. Se nenhuma porta for * especificada, o servidor utiliza a porta default dada

* por PROTOPORT.

(22)

struct sockaddr_in cad;/* estrutura para end. do cliente */ int sd, sd2; /* descritores de socket */

int port; /* número da porta */

char *host; /* ponteiro para o nome do host */ int alen; /* comprimento do endereço */

char buf[1000]; /* buffer para os dados do servidor */ #ifdef WIN32

WSADATA wsaData;

WSAStartup(0x0101, &wsaData); #endif

menset((char *)&sad,0,sizeof(sad)); /* limpa sockaddr */ sad.sin_family = AF_INET; /* seta familia Internet*/ sad.sin_addr.s_addr = INADDR_ANY; /* seta IP local */

/* analisa a linha de comando e obtem o nome o número da porta caso tenha sido especificado. */ if (argc > 1) /* se a porta é especificada */

port = atoi(argv[2]); /* obtem a porta e conv. binário*/ else port = PROTOPORT; /* usa o número da porta default*/ if (port > 0) /* testa se o valor é válido */

sad.sin_port = htons ((u_short) port); else {

fprintf(stderr,"numero de porta incorreta:%s\n",argv[2]); exit(1);

}

/* Obtem o número do protocolo de transporte TCP */ if (((int) (ptrp = getprotobyname("tcp"))) == 0){ fprintf(stderr,"Nao pode mapear \"tcp\" \n"); exit (1);

}

(23)

if (sd < 0) {

fprintf(stderr,"falha na criacao do socket\n"); exit(1);

}

/* Faz o Bind do endereço local com o socket */ if (bind(sd,(struct sockaddr*)&sad,sizeof(sad)) < 0) { fprintf(stderr,"falha no bind\n");

exit(1); }

/* Coloca o soket no estado passivo, define fila de espera */ if (listen(sd,QLEN) < 0) {

fprintf(stderr,"falha no listen\n"); exit(1);

}

/* Loop principal do servidor:aceita requisições de conexão*/ while (1) {

alen = sizeof(cad);

if ((sd2=accept(sd,(struct sockaddr*)&cad, &alen)) < 0) { fprintf(stderr,"falha no accept\n");

exit(1); }

visitas++;

sprintf(buf,"Este servidor foi contatado %d vez%e\n", visitas, visitas==1?".":"es."); send(sd2, buf, strlen(buf), 0);

(24)

Utilizando o Cliente com outro Servidor

O cliente do exemplo é um programa genérico que realiza uma conexão TCP para obter uma seqüência de caracteres ASCII. Além de ser utilizado com o servidor do exemplo, também pode ser utilizado com outros

servidores com operem de forma similar.

Este é o caso do servidor DAYTIME disponível nos sistemas e que utiliza a porta 13. As chamadas a seguir retornam a data e hora de diferentes computadores.

$cliente localhost 13

Mon May 12 10:20:14 1997 $cliente xx.lcs.mit.edu 13 Mon May 12 09:23:44 1997

Utilizando outro Cliente com o Servidor

Outro cliente pode ser utilizado para testar o servidor do exemplo, como no caso do telnet que utiliza os mesmos parâmetros: nome do

computador e número da porta do servidor. Exemplo de chamada:

$telnet xx.yy.provedor.com 5193 Trying…

Connected to xx.yy.provedor.com 5193 Escape character is ‘^]’.

Este servidor foi contatado 4 vezes. Connection closed by foreign host.

Serviço Stream

No exemplo, o servidor executa apenas um send e o cliente realiza vários recv para obter o mesmo dado do send. A iteração termina quando o cliente obtém a condição de fim de arquivo, isto é, contador de bytes recebidos igual a zero.

O TCP não garante que os dados sejam enviados em um único segmento por esta razão o cliente deve executar vários recv.

(25)

Bloqueio nos Procedimentos de Sockets

Muitos dos procedimentos de sockets causam o bloqueio do processo que executou o procedimento.

No accept, por exemplo, o programa fica bloqueado até receber um pedido de conexão.

No recv e read, de forma análoga, o programa ficará bloqueado até a chegada de dados.

Existe tratamento assíncrono no TCP, que não bloqueia o programa quando este está a espera de algum dado ou conexão através de um socket. O tratamento assíncrono utiliza o comando select.

Muita chamadas de sockets causam o bloqueio do processo que a executou.

No accept, por exemplo, o programa fica bloqueado até receber um pedido de conexão.

No recv e read, de forma análoga, o programa ficará bloqueado até a chegada de dados.

Fim do módulo

Referências

Documentos relacionados

Não alterne entre o granulado para suspensão oral, o comprimido para mastigar, o comprimido de 600 mg ou o comprimido de 400 mg sem falar primeiro com o médico, farmacêutico

Assim ocorre também num trabalho de Geomancia, ensinamentos e regras na qual num trabalho de Geomancia, ensinamentos e regras na qual certas verdades que são só

Para a ponta de jato plano (leque), a adição dos adjuvantes melhorou a deposição da calda de pulverização sobre as folhas da cebola, em comparação com a aplicação

Se os personagens não intervierem com DuBois, provavelmente irão direto ver Karin, que se encontra em companhia de Alfred: ela acaba de se levantar, e Lucille está preparando seus

Obtém nas fichas de avaliação, fichas de trabalho e no trabalho prático a classificação de Fraco e/ou Não Satisfaz; Apresenta um comportamento irrequieto que afeta

El objetivo del artículo es analizar y describir las estrategias que la Asociación Evangélica de la Misión Israelita del Nuevo Pacto Universal, un movimiento mesiánico milenarista

O jornal Correio Braziliense publicou na coluna Opinião um artigo do cientista político Eliézer Rizzo de Oliveira, analisando a criação do Ministério da Defesa

Assim, este artigo tem como objetivo fazer uma reflexão sobre como tem se dado o discurso desses grupos historicamente excluídos dos processos de desenvolvimento, e que passam