我正在开发一个项目,将TCP / IP客户端程序移植到嵌入式ARM-Linux控制器板上.客户端程序最初是用epoll()编写的.但是,目标平台已经很老了;唯一可用的内核是2.4.x,不支持epoll().所以我决定在poll()中重写I / O循环.
但是当我测试代码时,我发现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”.
这是poll()的预期行为吗?如果我选择select()而不是poll()会有帮助吗?
解决方法:
是的,这是预期的行为.您可以通过在套接字上使用shutdown()而不是close()来解决此问题.
参见例如http://www.faqs.org/faqs/unix-faq/socket/第2.6节
编辑:这是预期的原因是poll()和select()对其中一个fd上发生的事件作出反应. close()删除fd,它根本不存在,因此它不能有任何与之关联的事件.
标签:linux,sockets 来源: https://codeday.me/bug/20190726/1544039.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。