#c #linux #sockets #network-programming
#c #linux #сокеты #сетевое программирование
Вопрос:
Это рисунок, демонстрирующий типичную модель клиент-сервер из интерфейса программирования Linux
Это пример исходного кода для серверной части от geeksforgeeks
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
// Function designed for a chat between client and server.
void func(int sockfd)
{
// server's job
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...n");
exit(0);
}
else
printf("Socket successfully created..n");
bzero(amp;servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)amp;servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...n");
exit(0);
}
else
printf("Socket successfully binded..n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...n");
exit(0);
}
else
printf("Server listening..n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)amp;cli, amp;len);
if (connfd < 0) {
printf("server acccept failed...n");
exit(0);
}
else
printf("server acccept the client...n");
// Function for chatting between client and server
func(connfd);
// After chatting close the socket
close(sockfd);
}
В книге, о которой я упоминал выше, автор сказал
Ключевым моментом для понимания accept() является то, что он создает новый сокет, и именно этот новый сокет подключен к одноранговому сокету, который выполнил connect() .
В исходном коде сервера есть 2 сокета
sockfd
, выводsocket()
connfd
, выводaccept()
Почему серверная часть не используется sockfd
для «общения» с клиентом, а создает новый сокет connfd
, а затем «разговаривает» с клиентом, пока сокет уже существует?
Ответ №1:
Прослушивающий сокет можно использовать для приема нескольких подключений, каждое с разной парой удаленных IP / портов.
TCP-соединение определяется 4 значениями: IP-адрес источника, порт источника, IP-адрес назначения, порт назначения. Дескриптор сокета, возвращаемый с помощью accept
, связан с таким соединением. В отличие от этого, прослушивающий сокет связан только с локальным IP и портом.
В этом конкретном примере кода он вызывается только accept
один раз. Но это может быть сделано в цикле для обработки соединений с нескольких конечных точек. Обычно такой процесс будет иметь один поток, вызываемый accept
в цикле. Затем, когда возвращается новый сокет accept
, запускается новый поток для обработки этого соединения, в то время как основной поток вызывает accept
снова.
Ответ №2:
К серверу может быть подключено несколько клиентов одновременно. Один дескриптор сокета не может представлять несколько соединений. Каждое соединение состоит из уникальной комбинации пар локальный одноранговый адрес / порт, поэтому серверу требуется отдельный дескриптор сокета для представления каждого из них.