请问为什么我采用epoll的EPOLLET模式同时监听fd读写的时候,会随机触发 "写" 事件?
1:我采用epoll
的EPOLLET
模式同时监听fd
读写,客户端连接服务器之后只发送数据
,按正常情况应该只会触发服务器端的EPOLLIN
,但是实际情况却随机
触发服务器端的EPOLLOUT
。
2:我目前测试如果将recv
函数的recv_buf
大小设置小点(我设置的为4
),就不会出现这个问题。而且即使按照我下面代码的1024
大小,我要是一条一条发送也不会出现问题。
3:服务端代码如下:
while(1) {
nfds = epoll_wait(epollfd,events,1024,0);
sleep(1);
for(i = 0;i < nfds;i++) {
if(events[i].data.fd == listen_fd) { //连接请求
conn_fd = accept(listen_fd,(struct sockaddr *)&conn_addr,&conn_len);
printf("accept a new collection : %s\n",inet_ntoa(conn_addr.sin_addr));
ev.data.fd = conn_fd;
ev.events = EPOLLOUT | EPOLLIN | EPOLLET;
epoll_ctl(epollfd,EPOLL_CTL_ADD,conn_fd,&ev);
}
else if(events[i].events & EPOLLIN) { //读事件
if((sock_fd = events[i].data.fd) < 0 ) {
continue;
}
bzero(recv_buf,1024);
if((i = recv(sock_fd,recv_buf,1024,0) )== 0) { //这个recv的大小会影响结果
close(sock_fd);
events[i].data.fd = -1;
} else {
printf("%s\n",recv_buf);
}
}
else if(events[i].events & EPOLLOUT) { //写事件
bzero(recv_buf,1024);
strcpy(recv_buf,"我是服务器,收到了你的消息");
send(events[i].data.fd,recv_buf,1024,0);
}
}
4:客户端用nc 127.0.0.1 8888
连接,结果会出现
5:
(备注:上面的汉字是服务器返回的,但是我客户端只是发送yang
数据啊,为什么会触发服务端的写事件呢?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为边沿触发不是这么用的。实际上水平触发也不该这么用。建议先把水平触发弄清楚了再玩边沿触发。
监听写事件,意味着你有东西要写出去。如果你写好了,就不要再监听这个事件。只要写不会阻塞,那么文件描述符就是可写的。
send 和 recv 也不是这么用的,因为对于网络,有可能发生 short write 和 short read 的情况:数据只收发了一部分。你需要根据返回值来看是不是还有数据没发完。不要犯 Oracle 的 MySQL Connector/Python 那样的错误。
另外 nc 连上去之后是会自动读数据的。
ev.events = EPOLLOUT | EPOLLIN | EPOLLET;
我觉得是这一行的问题,不能够在一开始拿到conn_fd 就同时注册可读事件和可写事件,而是应该在你确定已经读取完整了客户端数据之后再注册可写事件。
因为对一个conn_fd只要不阻塞它就是可写的,而你在一开始就注册了可写事件,所以当然会触发写事件。