Я работаю над проектом, который будет портировать клиентскую программу 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 ()?