EPOLL下的accept(转载)
来源:互联网 发布:淘宝上衣服尺码表 编辑:程序博客网 时间:2024/06/05 16:56
转载自:http://www.cppblog.com/ifeng/archive/2011/09/29/157141.html
转载者注:看完这个,再回头看看nginx源码,发现它在accept时用的是LT模式,read,write时是ET模式)
不知道是谁第一个犯了错,在网上贴出所谓epoll通用框架的代码。注意看accpet的处理:
1
epfd = epoll_create(10);
2
3
struct
sockaddr_in clientaddr;
4
struct
sockaddr_in serveraddr;
5
listenfd = socket(AF_INET, SOCK_STREAM, 0);
6
7
bool
bReuseaddr = 1;
8
//setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(bool));
9
setnonblocking(listenfd);
10
ev.data.fd = listenfd;
11
ev.events = EPOLLIN | EPOLLET;
12
// ev.events=EPOLLIN;
13
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
14
bzero(&serveraddr,
sizeof
(serveraddr));
15
serveraddr.sin_family = AF_INET;
16
// char *local_addr=INADDR_ANY;
17
// inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);
18
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
19
serveraddr.sin_port = htons(SERV_PORT);
20
bind(listenfd, (sockaddr *) &serveraddr,
sizeof
(serveraddr));
21
listen(listenfd, LISTENQ);
22
maxi = 0;
23
int
nfds_count = 0, recvcount = 0, recvlen = 0;
24
for
(;;) {
25
cout <<
"before epoll_wait! nfds_count="
<< nfds_count << endl;
26
nfds = epoll_wait(epfd, events, 20, 10000000);
27
28
// if(nfds>1) cout<<"nfds="<<nfds<<endl;
29
cout <<
"nfds="
<< nfds << endl;
30
31
for
(i = 0; i < nfds; ++i) {
32
if
(events[i].data.fd == listenfd) {
33
connfd = accept(listenfd, (sockaddr *) &clientaddr, &clilen);
34
nfds_count += 1;
35
if
(connfd < 0) {
36
perror
(
"connfd<0"
);
37
exit
(1);
38
}
39
setnonblocking(connfd);
40
char
*str = inet_ntoa(clientaddr.sin_addr);
41
cout <<
"connect from "
<< str <<
"connfd="
<< connfd << endl;
42
ev.data.fd = connfd;
43
ev.events = EPOLLIN | EPOLLET;
44
//ev.events=EPOLLIN;
45
//ev.events=EPOLLIN|EPOLLOUT|EPOLLET;
46
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
47
48
}
49
}
50
}
代码是从某处(很多地方都是这段,连注释都一样)拷过来的。熟悉epoll的人看了应该很熟系,其实就是将linsten的fd也加入到epoll中,当有新连接加入时可以epoll_wait到,随后再用accpet处理。
事实上这段代码是有问题的——高并发的情况下,accept到的fd的数量跟client端的发起请求的数量并不相等。我测了一下,100个并发(其实也不算高了)往往少几个到几十个不等。
相信很多人被这段代码误导了,因为我在遇到问题的时候搜到不少帖子,用的都是这样的代码。只是奇怪的是没见几个人说遇到我提到的这个问题。不过有人说这段代码效率不高,提出用阻塞式IO把accpet提到一个单独的线程里做。撇开这样做性能上的优劣不说,倒是能解决我遇到的问题,但这治标不治本——我要用epoll+nonblockio
下面说说这段误人子弟的代码,其实 man epoll 就能找到这段代码的出处。相信它是某位同志从里面帖出来然后玩弄了许久后好心放到网上的,不然不会有这么多的//注释。而问题就是出在注释上,注意到 man-page 里的代码是这样的:
1
ev.events = EPOLLIN;
2
ev.data.fd = listen_sock;
3
if
(epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
4
perror
(
"epoll_ctl: listen_sock"
);
5
exit
(EXIT_FAILURE);
6
}
没错,man里并没有将listenfd以ET的方式加入epoll(不指定EPOLLET默认就是Level Triggered),事实也证明不设ET就没有问题了。
难道说ET模式下就不能以非阻塞模式来accpet?答案是否定的。其实只要把accpet方式改一下就可以了,简单说就是if改while:
1
while
((confd = accept(listenfd, (
struct
sockaddr*) sa, &clientlen)) > 0) {
2
3
//add connection to epoll
4
peer = (
struct
sockaddr*) sa;
5
printf
(
"%s:%d connect at %d.\n"
, inet_ntoa(peer->sin_addr),
6
peer->sin_port, confd);
7
setnonblocking(confd);
8
9
ev.data.fd = confd;
10
ev.events = EPOLLIN | EPOLLET ;
11
12
epoll_ctl(myfd, EPOLL_CTL_ADD, confd, &ev);
13
14
}
Feedback
# re: EPOLL下的accept(转载) 回复 更多评论
2011-09-29 18:58 by dong- EPOLL下的accept(转载)
- EPOLL下的accept(转载)
- Linux下服务器端使用EPOLL ACCEPT产生的问题
- epoll 的accept , read, write
- linux下epoll模型accept并发问题
- linux下epoll模型accept并发问题
- epoll 的accept , read, write(重要)
- epoll 的accept , read, write(重要)
- epoll 的accept , read, write(重要)
- epoll 的accept , read, write(重要)
- epoll 的accept , read, write(重要)
- epoll 的accept , read, write(重要)
- epoll 的accept , read, write(重要)
- epoll中accept的使用细节
- epoll的ET和LT模式下,accept,recv,send写法
- linux epoll accept 问题
- epoll accept 惊群
- accept与epoll惊群
- 利用KindEditor的uploadbutton实现异步上传图片 .
- Java学习笔记之static关键字。
- BZOJ3675【斜率优化】
- Android17_异步任务+JSON解析+ListView分页
- CXF3.0.4与spring整合开发Webservice功能的web项目
- EPOLL下的accept(转载)
- 移动应用开发中后台mysql数据库的编码问题
- JSP中Request对象解决中文乱码
- 插入排序与Shell排序
- 指针变量作为函数参数
- 【CF】C. Glass Carving(二分 + 树状数组 + 优先队列 + 数组计数)
- HDU3068(最长回文子串manacher算法)
- FKJAVA读书笔记--第五章--面向对象(上)
- mongodb c++驱动 登录验证的问题