logo

Programação de soquete em C

Programação de soquete é uma forma de conectar dois nós em uma rede para se comunicarem entre si. Um soquete (nó) escuta em uma porta específica em um IP enquanto o outro soquete alcança o outro para formar uma conexão. O servidor forma o soquete do ouvinte enquanto o cliente acessa o servidor.
A programação de soquete é amplamente utilizada em aplicativos de mensagens instantâneas, streaming binário e colaborações de documentos, plataformas de streaming on-line, etc.

Exemplo

Neste programa C estamos trocando uma mensagem de alô entre servidor e cliente para demonstrar o modelo cliente/servidor.

servidor.c

C
#include  #include  #include  #include  #include  #include  #define PORT 8080 int main(int argc char const* argv[]) {  int server_fd new_socket;  ssize_t valread;  struct sockaddr_in address;  int opt = 1;  socklen_t addrlen = sizeof(address);  char buffer[1024] = { 0 };  char* hello = 'Hello from server';  // Creating socket file descriptor  if ((server_fd = socket(AF_INET SOCK_STREAM 0)) < 0) {  perror('socket failed');  exit(EXIT_FAILURE);  }  // Forcefully attaching socket to the port 8080  if (setsockopt(server_fd SOL_SOCKET  SO_REUSEADDR | SO_REUSEPORT &opt  sizeof(opt))) {  perror('setsockopt');  exit(EXIT_FAILURE);  }  address.sin_family = AF_INET;  address.sin_addr.s_addr = INADDR_ANY;  address.sin_port = htons(PORT);  // Forcefully attaching socket to the port 8080  if (bind(server_fd (struct sockaddr*)&address  sizeof(address))  < 0) {  perror('bind failed');  exit(EXIT_FAILURE);  }  if (listen(server_fd 3) < 0) {  perror('listen');  exit(EXIT_FAILURE);  }  if ((new_socket  = accept(server_fd (struct sockaddr*)&address  &addrlen))  < 0) {  perror('accept');  exit(EXIT_FAILURE);  }    // subtract 1 for the null  // terminator at the end  valread = read(new_socket buffer  1024 - 1);   printf('%sn' buffer);  send(new_socket hello strlen(hello) 0);  printf('Hello message sentn');  // closing the connected socket  close(new_socket);    // closing the listening socket  close(server_fd);  return 0; } 

cliente.c

C
#include    #include  #include  #include  #include  #define PORT 8080 int main(int argc char const* argv[]) {  int status valread client_fd;  struct sockaddr_in serv_addr;  char* hello = 'Hello from client';  char buffer[1024] = { 0 };  if ((client_fd = socket(AF_INET SOCK_STREAM 0)) < 0) {  printf('n Socket creation error n');  return -1;  }  serv_addr.sin_family = AF_INET;  serv_addr.sin_port = htons(PORT);  // Convert IPv4 and IPv6 addresses from text to binary  // form  if (inet_pton(AF_INET '127.0.0.1' &serv_addr.sin_addr)  <= 0) {  printf(  'nInvalid address/ Address not supported n');  return -1;  }  if ((status  = connect(client_fd (struct sockaddr*)&serv_addr  sizeof(serv_addr)))  < 0) {  printf('nConnection Failed n');  return -1;  }    // subtract 1 for the null  // terminator at the end  send(client_fd hello strlen(hello) 0);  printf('Hello message sentn');  valread = read(client_fd buffer  1024 - 1);   printf('%sn' buffer);  // closing the connected socket  close(client_fd);  return 0; } 


Compilando



gcc client.c -o clientgcc server.c -o server


Saída

Client:Hello message sentHello from serverServer:Hello from clientHello message sent

Componentes da programação de soquete

1. Soquetes

Soquetes são um dos principais componentes usados ​​pelo programa para acessar a rede e se comunicar com outros processos/nós na rede. É simplesmente uma combinação de um endereço IP e um número de porta que atua como um ponto final para comunicação.
Exemplo: 192.168.1.1:8080 onde as duas partes separadas por dois pontos representam o Endereço IP (192.168.1.1) e o número da porta (8080).

Tipos de soquete:

  • Soquete TCP (soquete de fluxo): Fornece comunicação confiável baseada em conexão (ou seja, Protocolo TCP ).
  • Soquete UDP (soquete de datagrama): Fornece comunicação sem conexão mais rápida, mas não confiável (ou seja, Protocolo UDP ).

2. Modelo Cliente-Servidor

O modelo cliente-servidor refere-se à arquitetura usada na programação de soquete onde um cliente e um servidor interagem entre si para trocar informações ou serviços. Esta arquitetura permite que o cliente envie solicitações de serviço e o servidor processe e envie respostas a essas solicitações de serviço.

Diagrama de estado para modelo de servidor e cliente

Programação de soquete em CDiagrama de estado para modelo de servidor e cliente do Socket

A programação de soquete em C é uma maneira poderosa de lidar com a comunicação em rede.

Criando um processo do lado do servidor

O servidor é criado usando as seguintes etapas:

instanciando java

1. Criação de soquete

Esta etapa envolve a criação do soquete usando a função socket().

Parâmetros:

  • meia: descritor de soquete um número inteiro (como um identificador de arquivo)
  • domínio: inteiro especifica o domínio de comunicação. Usamos AF_LOCAL conforme definido no padrão POSIX para comunicação entre processos no mesmo host. Para comunicação entre processos em diferentes hosts conectados por IPV4 usamos AF_INET e AF_I NET 6 para processos conectados por IPV6.
  • tipo: tipo de comunicação
    SOCK_STREAM: TCP (orientado a conexão confiável)
    SOCK_DGRAM: UDP (sem conexão não confiável)
  • protocolo: Valor do protocolo para Internet Protocol (IP) que é 0. Este é o mesmo número que aparece no campo de protocolo no cabeçalho IP de um pacote. (man protocols para mais detalhes)
C
sockfd = socket(domain type protocol) 

2. Definir opção de soquete

Isso ajuda na manipulação de opções para o soquete referido pelo descritor de arquivo sockfd. Isso é totalmente opcional, mas ajuda na reutilização de endereço e porta. Evita erros como: endereço já em uso.

C
setsockopt(sockfd level optname optval socklen_t optlen); 

3. Vincular

Após a criação do soquete, a função bind() vincula o soquete ao endereço e número da porta especificados em addr (estrutura de dados personalizada). No código de exemplo, vinculamos o servidor ao host local, portanto, usamos INADDR_ANY para especificar o endereço IP.

C++
bind(sockfd sockaddr *addr socklen_t addrlen); 

Parâmetros:

  • meia : descritor de arquivo de soquete criado usando a função socket().
  • endereço : ponteiro para uma estrutura sockaddr que contém o endereço IP e o número da porta para vincular o soquete.
  • addrlen : comprimento da estrutura addr.

4. Ouça

Nesta etapa o servidor utiliza a função listen() que coloca o soquete do servidor em modo passivo onde espera o cliente se aproximar do servidor para fazer uma conexão. O backlog define o comprimento máximo que a fila de conexões pendentes para sockfd pode crescer. Se uma solicitação de conexão chegar quando a fila estiver cheia o cliente poderá receber um erro com a indicação ECONNREFUSED.

C
listen(sockfd backlog); 

Parâmetros :

  • meia : descritor de arquivo de soquete criado usando a função socket().
  • pendências : número que representa o tamanho da fila que contém as conexões pendentes enquanto o servidor aguarda para aceitar uma conexão.

5. Aceite

Nesta etapa o servidor extrai a primeira solicitação de conexão da fila de conexões pendentes para o soquete de escuta sockfd cria um novo soquete conectado usando o comando aceitar() função e retorna um novo descritor de arquivo referente a esse soquete. Neste ponto a conexão é estabelecida entre cliente e servidor e eles estão prontos para transferir dados.

C
new_socket= accept(sockfd sockaddr *addr socklen_t *addrlen); 

Parâmetros:

  • meia : descritor de arquivo de soquete retornado por socket() e bind().
  • endereço : ponteiro para uma estrutura sockaddr que conterá o endereço IP e o número da porta do cliente.
  • addrlen : ponteiro para uma variável que especifica o comprimento da estrutura de endereço.

6. Enviar/Receber

Nesta etapa o servidor pode enviar ou receber dados do cliente.

Enviar(): enviar dados ao cliente

C
send(sockfd *buf len flags); 

Parâmetros:

  • meia : descritor de arquivo de soquete retornado pela função socket().
  • bufante : ponteiro para o buffer que contém os dados a serem enviados.
  • apenas : número de bytes de dados a serem enviados.
  • bandeiras : inteiro especificando várias opções de como os dados são enviados normalmente 0 é usado para comportamento padrão.

Receber() : para receber os dados do cliente.

C
recv( sockfd *buf len flags); 

Parâmetros:

  • meia : descritor de arquivo de soquete retornado pela função socket().
  • bufante : ponteiro para o buffer que contém os dados a serem armazenados.
  • apenas : número de bytes de dados a serem enviados.
  • bandeiras : inteiro especificando várias opções de como os dados são enviados normalmente 0 é usado para comportamento padrão.

6. Fechar

Após a conclusão da troca de informações, o servidor fecha o soquete usando a função close() e libera os recursos do sistema.

C
close(fd); 

Parâmetros:

  • fd: descritor de arquivo do soquete.

Criando Processo do Lado do Cliente

Siga as etapas abaixo para criar um processo do lado do cliente:

1. Conexão de soquete

Esta etapa envolve a criação do soquete que é feita da mesma forma que a criação do soquete do servidor

2. Conecte-se

A chamada de sistema connect() conecta o soquete referido pelo descritor de arquivo sockfd ao endereço especificado por addr. O endereço e a porta do servidor são especificados em addr.

C++
connect(sockfd sockaddr *addr socklen_t addrlen); 

Parâmetros

  • meia : descritor de arquivo de soquete retornado pela função socket().
  • endereço : ponteiro para struct sockaddr contendo o endereço IP e o número da porta do servidor.
  • addrlen : tamanho do endereço.

3. Enviar/Receber

Nesta etapa, o cliente pode enviar ou receber dados do servidor, o que é feito usando as funções send() e recieve() semelhantes à forma como o servidor envia/recebe dados do cliente.

4. Fechar

Assim que a troca de informações for concluída, o cliente também precisa fechar o soquete criado e liberar os recursos do sistema usando a função close() da mesma forma que o servidor.

Problemas comuns e suas correções na programação de soquete

  • Falhas de conexão: Para evitar falhas de conexão devemos garantir que o cliente está tentando se conectar ao correto Endereço IP e porta .
  • Erros de ligação de porta: Esses erros ocorrem quando uma porta já está em uso por outro aplicativo. Nesse cenário, a ligação a essa porta falhará. Tente usar uma porta diferente ou feche o aplicativo anterior usando a porta.
  • Bloqueio de soquetes: Por padrão, os soquetes estão bloqueando. Isso significa que chamadas como accept() ou recv() aguardarão indefinidamente se não houver conexão ou dados do cliente. Você pode definir o soquete para o modo sem bloqueio, se necessário.
Criar questionário