Программирование сокетов на C / C ++

Опубликовано: 15 Июля, 2021

Что такое программирование сокетов?
Программирование сокетов - это способ соединения двух узлов в сети для связи друг с другом. Один сокет (узел) прослушивает определенный порт на IP, в то время как другой сокет обращается к другому, чтобы сформировать соединение. Сервер формирует сокет слушателя, пока клиент обращается к серверу.

Диаграмма состояний для модели сервера и клиента

Этапы для сервера

  • Создание сокета:
     int sockfd = сокет (домен, тип, протокол)

    sockfd: дескриптор сокета, целое число (например, дескриптор файла)
    домен: целое число, домен связи, например, AF_INET (протокол IPv4), AF_INET6 (протокол IPv6)
    type: тип связи
    SOCK_STREAM: TCP (надежный, ориентированный на соединение)
    SOCK_DGRAM: UDP (ненадежный, без установления соединения)
    Протокол: значение протокола для Интернет-протокола (IP), равное 0. Это тот же номер, который отображается в поле протокола в IP-заголовке пакета. (подробности см. в протоколах man).

  • Setsockopt:
     int setsockopt (int sockfd, int level, int optname,  
                       const void * optval, socklen_t optlen);

    Это помогает управлять параметрами сокета, на который ссылается файловый дескриптор sockfd. Это совершенно необязательно, но помогает повторно использовать адрес и порт. Предотвращает ошибку, например: «адрес уже используется».

  • Связывать:
     int bind (int sockfd, const struct sockaddr * addr, 
                              socklen_t addrlen);

    После создания сокета функция bind связывает сокет с адресом и номером порта, указанными в addr (настраиваемая структура данных). В примере кода мы привязываем сервер к локальному хосту, поэтому мы используем INADDR_ANY для указания IP-адреса.

  • Слушать:
     int слушать (int sockfd, int backlog);

    Он переводит сокет сервера в пассивный режим, где он ожидает, пока клиент приблизится к серверу для установления соединения. Бэклог определяет максимальную длину, до которой может вырасти очередь ожидающих соединений для sockfd. Если запрос на соединение поступает при заполнении очереди, клиент может получить сообщение об ошибке с указанием ECONNREFUSED.

  • Принимать:
     int new_socket = accept (int sockfd, struct sockaddr * addr, socklen_t * addrlen);

    Он извлекает первый запрос на соединение из очереди ожидающих соединений для прослушивающего сокета, sockfd, создает новый подключенный сокет и возвращает новый файловый дескриптор, ссылающийся на этот сокет. На этом этапе между клиентом и сервером установлено соединение, и они готовы к передаче данных.

Этапы для клиента

  • Подключение к сокету: точно так же, как и при создании сокета сервера.
  • Соединять:
     int connect (int sockfd, const struct sockaddr * addr,  
                                 socklen_t addrlen);

    Системный вызов connect () соединяет сокет, на который указывает файловый дескриптор sockfd, с адресом, указанным в addr. Адрес и порт сервера указаны в addr.

Выполнение
Здесь мы обмениваемся одним приветственным сообщением между сервером и клиентом, чтобы продемонстрировать модель клиент / сервер.

server.c






// Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main( int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int 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,
(socklen_t*)&addrlen))<0)
{
perror ( "accept" );
exit (EXIT_FAILURE);
}
valread = read( new_socket , buffer, 1024);
printf ( "%s " ,buffer );
send(new_socket , hello , strlen (hello) , 0 );
printf ( "Hello message sent " );
return 0;
}

client.c






// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 8080
int main( int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client" ;
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf ( " Socket creation error " );
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 ( " Invalid address/ Address not supported " );
return -1;
}
if (connect(sock, ( struct sockaddr *)&serv_addr, sizeof (serv_addr)) < 0)
{
printf ( " Connection Failed " );
return -1;
}
send(sock , hello , strlen (hello) , 0 );
printf ( "Hello message sent " );
valread = read( sock , buffer, 1024);
printf ( "%s " ,buffer );
return 0;
}


Компиляция:
gcc client.c -o клиент
gcc server.c -o сервер

Выход:

Клиент: приветственное сообщение отправлено
Привет с сервера
Сервер: Привет от клиента
Привет сообщение отправлено

Далее: Программирование сокетов на C / C ++: обработка нескольких клиентов на сервере без многопоточности
Эта статья предоставлена Акшатом Синхой . Если вам нравится GeeksforGeeks, и вы хотели бы внести свой вклад, вы также можете написать статью с помощью provide.geeksforgeeks.org или отправить ее по электронной почте на deposit@geeksforgeeks.org. Посмотрите, как ваша статья появляется на главной странице GeeksforGeeks, и помогите другим гикам.

Пожалуйста, напишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по теме, обсужденной выше.

C++