C / C ++: создание сокета () завершается неудачно в l oop, слишком много открытых файлов - PullRequest
0 голосов
/ 31 января 2020

Я использую клиент-серверное приложение TCP-сокета. Client на маршрутизаторе OpenWRT Linux (на основе C) и несколько раз записывает данные в сокет и в al oop с некоторой частотой. Server находится на машине Linux Ubuntu (на основе C / C ++) и считывает данные в al oop в соответствии со скоростью поступления данных.

Проблема : Запуск Server а затем Client, сервер продолжает читать новые данные. Обе стороны работают хорошо, пока количество доставленных данных (число соединений) не достигнет 1013. После этого Client застрял на socket(AF_INET,SOCK_STREAM,0) с socket creation failed...: Too many open files. По-видимому, число открытых fd приближается к ulimit -n = 1024 на клиенте.

Я поместил фрагменты кода, который показывает структуры l oop для Server.cpp и Client.c:

Сервер. c:

//    TCP Socket creation stuff over here (work as they should):
//    int sock_ = socket() / bind() / listen()

while (1)
{
        socklen_t sizeOfserv_addr = sizeof(serv_addr_);
        fd_set set;
        struct timeval timeout;
        int connfd_;
        FD_ZERO(&set);
        FD_SET(sock_, &set);
        timeout.tv_sec = 10;
        timeout.tv_usec = 0;
        int rv_ = select(sock_ + 1, &set, NULL, NULL, &timeout);
        if(rv_ == -1){
            perror("select");
            return 1;
        }
        else if(rv_ == 0){
            printf("Client disconnected.."); /* a timeout occured */
            close (connfd_);
            close (sock_);
        }
        else{
            connfd_ = accept (sock_,(struct sockaddr*)&serv_addr_,(socklen_t*)&sizeOfserv_addr);
            if (connfd_ >= 0) {
                int ret = read (connfd_, &payload, sizeof(payload));    /* some payload */
                if (ret > 0)
                     printf("Received %d bytes !\n", ret);
                close (connfd_);  /* Keep parent socket open (sock_) */
            }else{
                printf("Server acccept failed..\n");
                close (connfd_);
                close (stcp.sock_);
                return 0;
            }
        }
}

Клиент. cpp:

while (payload_exist)               /* assuming payload_exist is true */
{
        struct sockaddr_in servaddr;
        int sock;
        if (sock = socket(AF_INET, SOCK_STREAM, 0) == -1)
            perror("socket creation failed...\n");

        int one = 1;
        int idletime = 2;
        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idletime, sizeof(idletime));
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));

        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = inet_addr("192.168.100.12");
        servaddr.sin_port = htons(PORT);  /* some PORT */
        if (connect (sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0){
            perror("connect failed...");
            return 1;
        }
        write(sock, (struct sockaddr*)&payload, sizeof(payload));  /* some new payload */
        shutdown(sock,SHUT_WR);

        bool serverOff = false;
        while (!serverOff){
             if(read(sock, &res, sizeof(res)) < 0){
                 serverOff = true;
                 close(sock); 
             }
        }
}

ПРИМЕЧАНИЕ : payload равен 800 bytes и всегда получает полностью передается за одно write действие. Имея оба кода, определенные в int main(), клиент продолжает создавать сокеты и отправлять данные, с другой стороны, сервер получает все и автоматически close() и уходит, если клиент завершает работу из-за использования select(). Однако если я не завершу работу Client, проверив некоторые журналы печати, очевидно, что Server успешно получит 1013 полезных данных, прежде чем произойдет сбой клиента с socket creation failed...: Too many open files.

Обновление :

Следуя пункту, упомянутому Штеффеном Ульрихом, выяснилось, что у клиентского сокета fd нет утечки, и существует второй fd в исходном l oop (который был оставил открытым) заставлял ulimit превышать лимит.

1 Ответ

4 голосов
/ 31 января 2020
        if(read(sock, &res, sizeof(res)) < 0){
             serverOff = true;
             close(sock);   /********* Not actually closing sock *********/
        }

Ваш чек на завершение соединения неверен. read возвращает 0, если другая сторона отключила соединение, и <0 только при ошибке.

    if (sock = socket(AF_INET, SOCK_STREAM, 0) == -1)
        perror("socket creation failed...\n");

Учитывая приоритет операторов в C, это в основном говорит:

    sock = ( socket(AF_INET, SOCK_STREAM, 0) == -1) )
    if (sock) ...

Предполагая, что socket(...) не вернет ошибку, но дескриптор файла (то есть >=0), сравнение будет ложным, и, таким образом, это по существу говорит sock = 0 при утечке дескриптора файла, если fd socket было >0.

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