Как программа ожидает входящие соединения после того, как они пройдут прослушивание () - PullRequest
2 голосов
/ 03 апреля 2012

Я изучаю программирование сокетов в c и пытаюсь понять, что именно делает listen() в коде.Я понимаю, что это определяет максимальное количество соединений, которое может быть поставлено в очередь для accept(), но кроме этого я не могу понять, что еще он делает.

Согласно тексту, из которого я учусь,

listen () ожидает входящих соединений.Accept () получает ожидающее соединение на порт, который вы слушаете () ing .

Глядя на поток выполнения, я вижу, что listen(), на самом деле,вызывается только один раз, и после этого только accept () обрабатывает любое новое входящее соединение. Затем, как сервер прослушивает будущие запросы, если listen () никогда не вызывается, как только мы попадаем внутрь цикла accept .?

                       +----------+
                       |socket()  |
                       +----------+

                       +----------+
                       |bind()    |
                       +----------+

                       +----------+
                       |listen()  |
                       +----------+
                       +----------+
                       |while(1)  |
                       |----------|
                       |accept()  |
                       |          |
                       |          |
                       +----------+

Вот код, над которым я работаю:

/*Server*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

int main()
{
    int sockfd, newsock;
    char buffer[200];
    memset(buffer, 0, sizeof(buffer));

    /*Creating a new socket*/
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket error");
        exit(1);
    }

    /*Creating socket address structure*/
    struct sockaddr_in server_addr, client_address;

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(7200);
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.2");
    bzero(&(server_addr.sin_zero),8);

    /*Binding*/
    if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("Bind error");
        exit(1);
    }

    /*Listening for new connection; maximum 5*/
    if(listen(sockfd, 5) < 0)
    {
        perror("Listen error");
    }


    while(1)
    {
        socklen_t len = sizeof(client_address);

        if((newsock = accept(sockfd, (struct sockaddr *)&client_address, &len)) < 0)
        {
            perror("Accept error");
            exit(1);
        }

        int i;
        if((i = read(newsock, buffer, sizeof(buffer))) < 0)
        {
            perror("Receive error");
            exit(1);
        }
        if(i == 0)
        {
            printf("Socket closed remotely\n");
        }
        if(i > 0)
        {
            printf("received %d bytes\n",i);
            printf("data: %s",buffer);
        }

        close(newsock);
    }
    close(sockfd);

    return 0;
}

Ответы [ 4 ]

5 голосов
/ 03 апреля 2012

listen () ожидает входящих соединений.

Это просто вводящее в заблуждение упрощение.Этот системный вызов отмечает сокет для прослушивания .Это означает, что она информирует ОС эй, ищите этот сокет, вы будете получать запросы на соединение по нему .

Реальная функция ожидания - accept. Эта функция ожидает входящих соединений.Каждый раз, когда вы вызываете его (в контексте блокировки), происходит одна из двух вещей:

  • Если есть неприемлемые соединения (регулируемые вторым аргументом прослушивания) accept просто выбирает одно и все готово
  • В противном случае он на самом деле ждет, пока соединения станут доступными, прежде чем вернуть
2 голосов
/ 03 апреля 2012

Функция listen() не ожидает подключения; он (а) сообщает ядру, что сокет будет принимать соединения, и (б) устанавливает параметр backlog - сколько соединений ядро ​​поставит в очередь перед отклонением новых соединений. listen() вызывается только один раз, потому что он просто устанавливает вещи.

Функция accept() - это то, что обрабатывает новые соединения. Со страницы руководства:

   The accept() function shall extract the first connection on  the  queue
   of  pending  connections, create a new socket with the same socket type
   protocol and address family as the specified socket, and allocate a new
   file descriptor for that socket.

Итак, listen() устанавливает сокет, ядро ​​обрабатывает установление соединения, а accept() удаляет соединения из очереди и делает их доступными для вашего кода.

1 голос
/ 03 апреля 2012

listen() переводит сокет в режим прослушивания. После этого он всегда слушает, поэтому вам не нужно снова звонить listen(). После этого вы просто набираете accept(), чтобы получать соединения, которые входят во время прослушивания, один раз для каждого соединения.

1 голос
/ 03 апреля 2012

Звонок на listen просто подписывает ваш процесс на возможные соединения, которые будут доставлены позже. Фактическая работа выполняется в пространстве ядра, и вызов accept просто получает дескриптор уже установленного соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...