原文:http://blog.csdn.net/huangdh79/article/details/5739037
网上已有很多关于这两个函数的效率问题的文章,在这里不再累述。
本文主要对两个函数的编程细节问题,进行分析。
epoll使用et模式。select使用非阻塞模式
共用代码
1。设置句柄为非阻塞方式
- int setnonblocking(int sockfd)
- {
- if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)
- return -1;
- return 0;
- }
2。创建监听句柄并打开监听
- int create_listen_fd(void)
- {
- #define SERV_PORT 9999
- int listenfd;
- struct sockaddr_in servaddr;
-
- listenfd = socket(AF_INET, SOCK_STREAM, 0);
- if(listenfd == -1)
- return -1;
- memset(&servaddr, 0x00, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(SERV_PORT);
-
- if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
- return -1;
- if(listen(listenfd, 5) == -1)
- return -1;
-
- return listenfd;
- }
测试场景
1。客户端发送数据后等待,服务器端不对到达数据进行读取。
目的:测试如果有事件到达,但处理结束后管道内仍然有数据存留,各种i/o复用模式是否仍对此事件作出相应。
结果:
1)epoll在数据到达后被唤醒,处理完业务流程后(不对socket管道内数据进行读取),又被阻塞到epoll_wait上。
- int main(int argc, char** argv)
- {
- int epfd, nfds;
-
- struct epoll_event ev,events[20];
- int listenfd, connfd;
- char buf[100];
-
- if((listenfd = create_listen_fd()) == -1)
- {
- printf("create_listen_fd error/n");
- return -1;
- }
-
- if(setnonblocking(listenfd) == -1)
- {
- printf("set non block error/n");
- return -1;
- }
-
-
- epfd = epoll_create(256);
-
- ev.data.fd = listenfd;
-
- ev.events = EPOLLIN | EPOLLET;
-
- epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
-
- for(;;)
- {
-
- nfds = epoll_wait(epfd, events, 20, -1);
- printf("up/n");
- for(int i = 0; i < nfds; i++)
- {
- if(events[i].data.fd==listenfd)
- {
- connfd = accept(listenfd, NULL, NULL);
- setnonblocking(connfd);
-
- ev.data.fd = connfd;
-
- ev.events = EPOLLIN | EPOLLET;
-
- epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
- }
- else if(events[i].events & EPOLLIN)
- {
- if ( (connfd = events[i].data.fd) < 0) continue;
-
- while(false)
- {
- memset(buf, 0x00, 100);
- int rn;
- if((rn = read(connfd, buf, 10)) < 0)
- {
- if(errno == EAGAIN)
- {
- printf("read finish break/n");
- break;
- }
- }
- else if(rn == 0)
- {
- close(connfd);
- epoll_ctl(epfd, EPOLL_CTL_DEL, connfd, NULL);
- printf("close /n");
- break;
- }
- printf("read buf %s/n", buf);
- }
- }
- }
- }
-
- return 0;
- }
2)select在数据到达后被唤醒,处理完业务流程后(不对socket管道内数据进行读取),select会再次被唤醒。
- int main(int argc, char** argv)
- {
- #define HANDLE_CONNFD_COUNT 100
- int connfdSet[HANDLE_CONNFD_COUNT];
- fd_set rset,allset;
- int listenfd, connfd;
- int nfds;
- int iMax;
- char buf[100];
-
- for(int i = 0; i < HANDLE_CONNFD_COUNT; i++)
- {
- connfdSet[i] = -1;
- }
-
- if((listenfd = create_listen_fd()) == -1)
- {
- printf("create_listen_fd error/n");
- return -1;
- }
-
- setnonblocking(listenfd);
- FD_ZERO(&rset);
- FD_SET(listenfd, &rset);
- FD_ZERO(&allset);
- allset = rset;
- iMax = listenfd;
-
- for(;;)
- {
- rset = allset;
- nfds = select(iMax + 1, &rset, NULL, NULL, NULL);
- printf("up/n");
- if(FD_ISSET(listenfd, &rset))
- {
- connfd = accept(listenfd, NULL, NULL);
- setnonblocking(connfd);
- FD_SET(connfd, &allset);
- if(connfd > iMax)
- iMax = connfd;
- for(int i = 0; i < HANDLE_CONNFD_COUNT; i++)
- {
- if(connfdSet[i] < 0)
- connfdSet[i] = connfd;
- break;
- }
- if(--nfds == 0)
- continue;
- }
- else
- {
- for(int i = 0; i < HANDLE_CONNFD_COUNT; i++)
- {
- if(connfdSet[i] < 0)
- continue;
- if(FD_ISSET(connfdSet[i], &rset))
- {
- memset(buf, 0x00, sizeof(buf));
-
- printf("read buf:%s/n", buf);
- if(--nfds == 0)
- break;
- }
- }
- }
- }
- return 0;
- }
阅读(804) | 评论(0) | 转发(0) |