poll () не может обнаружить событие, когда сокет закрыт локально? - PullRequest
4 голосов
/ 18 февраля 2011

Я работаю над проектом, который будет портировать клиентскую программу TCP / IP на встроенную плату контроллера ARM-Linux. Клиентская программа изначально была написана в epoll (). Тем не менее, целевая платформа довольно старая; единственное доступное ядро ​​- 2.4.x, и epoll () не поддерживается. Поэтому я решил переписать цикл ввода / вывода в poll ().

Но когда я тестировал код, я обнаружил, что poll () работает не так, как я ожидал: он не вернется, когда сокет клиента TCP / IP будет закрыт локально другим потоком. Я написал очень простые коды для проверки:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>

struct pollfd   fdList[1];

void *thread_runner(void *arg)
{
    sleep(10);
    close(fdList[0].fd);
    printf("socket closed\n");
    pthread_exit(NULL);
}

int main(void)
{
    struct  sockaddr_in hostAddr;
    int sockFD;
    char buf[32];
    pthread_t handle;

    sockFD = socket(AF_INET, SOCK_STREAM, 0);
    fcntl(sockFD,F_SETFL,O_NONBLOCK|fcntl(sockFD,F_GETFL,0));

    inet_aton("127.0.0.1",&(hostAddr.sin_addr));
    hostAddr.sin_family = AF_INET;
    hostAddr.sin_port  = htons(12345);
    connect(sockFD,(struct sockaddr *)&hostAddr,sizeof(struct sockaddr));

    fdList[0].fd = sockFD;
    fdList[0].events = POLLOUT;

    pthread_create(&handle,NULL,thread_runner,NULL);

    while(1) {
        if(poll(fdList,1,-1) < 1) {
            continue;
        }
        if(fdList[0].revents & POLLNVAL ) {
            printf("POLLNVAL\n");
            exit(-1);
        }
        if(fdList[0].revents & POLLOUT) {
            printf("connected\n");
            fdList[0].events = POLLIN;
        }
        if(fdList[0].revents & POLLHUP ) {
            printf("closed by peer\n");
            close(fdList[0].fd);
            exit(-1);
        }
        if(fdList[0].revents & POLLIN) {
            if( read(fdList[0].fd, buf, sizeof(buf)) < 0) {
                printf("closed by peer\n");
                close(fdList[0].fd);
                exit(-1);
            }
        }
    }
    return 0;
}

В этом коде я сначала создаю сокет клиента TCP, устанавливаю неблокирующий режим, добавляю к poll () и закрываю () сокет в другом потоке. И результат: «POLLNVAL» никогда не печатается, когда сокет закрыт.

Это ожидаемое поведение опроса ()? Поможет ли мне выбрать select () вместо poll ()?

1 Ответ

9 голосов
/ 18 февраля 2011

Да, это ожидаемое поведение.Вы решаете это с помощью shutdown () на сокете вместо close ().

См., Например, http://www.faqs.org/faqs/unix-faq/socket/ раздел 2.6

РЕДАКТИРОВАТЬ: Причина, по которой это ожидается, заключается в том, что poll () и select () реагируют на события, происходящие на одном из их fd.close () удаляет fd, он больше не существует и поэтому не может иметь никаких событий, связанных с ним.

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