Linux下epoll的一些问题
小弟使用EPOLLIN来触发可读事件,按照网上说的,ET模式下,只有缓冲区从不可读变成可读才会触发EPOLLIN时间,可现在写了一个测试程序,客户端每次发多个字节,服务器每次只收一个字节,但每次都会触发EPOLLIN事件,如果只收一个字节,缓冲区还有数据,下次发送就应该不会再触发EPOLLIN事件(ET模式下),服务端代码如下:#include <iostream>#include <cstring>
#include <sys/epoll.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <fcntl.h>
int main(void)
{
int serfd = socket(AF_INET, SOCK_STREAM, 0);
int clifd;
int ret;
if(serfd < 0)
std::cout << "Create serfd fail!\n";
struct sockaddr_in cliaddr, seraddr;
bzero(&seraddr, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(12439);
seraddr.sin_addr.s_addr = inet_addr("0.0.0.0");
int on = 1;
setsockopt(serfd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
bind(serfd, (struct sockaddr*)&seraddr, sizeof(seraddr));
listen(serfd, 20);
socklen_t len = sizeof(cliaddr);
bzero(&cliaddr, sizeof(seraddr));
clifd = accept(serfd, (struct sockaddr*)&cliaddr, &len);
if(clifd < -1){
std::cout << strerror(errno) << std::endl;
close(serfd);
return 0;
}
fcntl(clifd, F_SETFL, O_NONBLOCK);
//Create epoll
int epfd = epoll_create(1024);
struct epoll_event ev;
struct epoll_event events;
ev.events = EPOLLET | EPOLLIN ;
ev.data.fd = clifd;
epoll_ctl(epfd, EPOLL_CTL_ADD, clifd, &ev);
while(1)
{
int num = epoll_wait(epfd, events, 1024, -1);
char buf = {0};
for(int i = 0; i < num; i++)
{
if(events.events & EPOLLIN){
std::cout << "Ready to read!\n";
std::cout << "size=" << read(events.data.fd, buf, 1)
<< "\tbuf=[" << buf << ']' << std::endl;
}
if(events.events & EPOLLOUT){
std::cout << "Ready to write!\n";
}
}
}
return 0;
}
客户端使用: nc 来连接,并发送数据,第一次发了abcd,触发了EPOLLIN,但服务器只收一个字节,第二次发了ef,依然触发了EPOLLIN。
服务器端的接收情况:
此外:如果我注册的时候是EPOLLET|EPOLLOUT ,为什么这个EPOLLOUT每次都会触发?
谢谢各位! hi,
按照EPOLLET 代码实现,应该是如果你没有读取完毕
并且底层驱动也没有数据发送过来的哈。
这时候你的epoll_wait 是不能等待相关的事件啦。
例如,你在读取一个字节后,你客服端不发送消息过来,那么你在epoll_wait
对应的文件符 是一直没有相应的事件报告的(在EPOLLET模式下)
如果你不使用EPOLLET模式,那么你在读取一个字节后,再次epoll_wait,
即使你的客服端不发送消息,也会有读事件报告的(因为你还有数据没读完)
回复 2# tc1989tc
嗯,是的,比如我客户端传了5个字节,epoll服务器第一次触发EPOLLIN的时候,我只收了1个字节,
这样的话,不是还有4个字节留在内核缓冲区中吗(网上说要触发EPOLLIN,一直要读到返回EAGAIN错误)?
下次客户端再发数据,由于是EPOLLET的,但此时内核缓冲区不为空(还有4个字节),没有从不可读变成可读,那它应该不会再次触发EPOLLIN啊!
可我现在做的测试结果,刚好相反!
看linux的evenepoll.c 里面的实现
和你测试的结果是一致的。
它只保证啦一次报文的边缘触发
也就是驱动有报文来有等待队列 他还是会**的 回复 4# tc1989tc
嗯勒,谢谢你!
页:
[1]