epoll一点思考(4)
来源:互联网 发布:js 用 添加数组 编辑:程序博客网 时间:2024/04/29 12:04
epoll EPOLLONESHOT
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里,这样IN事件会被保留。EPOLLONESHOT区别就是,每次IN事件都是串行进行,而不是多个in事件并行。
ET模式与LT模式EPOLLONESHOT处理相同
(1)设置EPOLLONESHOT,创建线程读取,线程中不在将socket放入epoll队列,后续再发数据不触发in事件,无法读取。代码如下:
#include <sys/socket.h>#include <sys/epoll.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <errno.h>#include <sys/types.h>#include <sys/mman.h>#include <iostream>using namespace std;#define MAX_EVENTS 10000int epfd = 0;void* process(void* ptr){ int sockfd = *(int*)ptr; char buf; while(read(sockfd, &buf, 1) > 0) { printf("%c\n",buf); sleep(5); } cout << "thread out " << endl; //event->events = EPOLLIN | EPOLLET; //epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, event);}int main(int argc, char **argv){ short port = 6002; // default port int listenFd = socket(AF_INET, SOCK_STREAM, 0); int reuse = 1; setsockopt(listenFd , SOL_SOCKET , SO_REUSEADDR , &reuse , sizeof(reuse)); fcntl(listenFd, F_SETFL, O_NONBLOCK); // 设置非阻塞方式 sockaddr_in sin; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); bind(listenFd, (const sockaddr*) &sin, sizeof(sin)); listen(listenFd, 5); struct epoll_event ev, events[MAX_EVENTS]; //生成用于处理accept的 epoll专用的文件描述符 epfd = epoll_create(MAX_EVENTS); //设置与要处理的事件相关的文件描述符 ev.data.fd = listenFd; //设置要处理的事件类型 ev.events = EPOLLIN | EPOLLET; //注册epoll事件 if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenFd, &ev) < 0) { printf("worker epoll_ctl error = %s.", strerror(errno)); exit(1); } while (true) { // 等待epoll事件的发生 int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); // 处理所发生的所有事件 for (int i = 0; i < nfds; ++i) // for循环中可以修改为线程池处理epoll事件 { if (events[i].data.fd == listenFd) { socklen_t clilen; struct sockaddr_in clientaddr; int sockfd = accept(listenFd, (sockaddr *) &clientaddr, &clilen); if (sockfd < 0) { continue; } // 设置非阻塞 if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0) | O_NONBLOCK) == -1) { continue; } ev.data.fd = sockfd; //设置用于注测的读操作事件 ev.events = EPOLLIN | EPOLLET |EPOLLONESHOT; //注册ev epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); } else if (events[i].events & EPOLLIN) { cout << "epollin--->" << endl; int sockfd = events[i].data.fd; pthread_t tid; pthread_create(&tid, NULL, process, &sockfd); pthread_detach(tid); usleep(1000); } } } return 0;}
(2)设置EPOLLONESHOT,创建线程读取,线程返回前将socket放入epoll队列,后续再次发送数据会触发in事件。代码如下:
/* * main.cpp * * Created on: 2012-12-27 * Author: root */#include <sys/socket.h>#include <sys/epoll.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <errno.h>#include <sys/types.h>#include <sys/mman.h>#include <iostream>using namespace std;#define MAX_EVENTS 10000int epfd = 0;void* process(void* ptr){ int sockfd = *(int*)ptr; struct epoll_event ev; char buf; while(read(sockfd, &buf, 1) > 0) { printf("%c\n",buf); sleep(5); } cout << "thread out " << endl; ev.data.fd = sockfd; //设置用于注测的读操作事件 ev.events = EPOLLIN | EPOLLET |EPOLLONESHOT; //注册ev epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); }int main(int argc, char **argv){ short port = 6002; // default port int listenFd = socket(AF_INET, SOCK_STREAM, 0); int reuse = 1; setsockopt(listenFd , SOL_SOCKET , SO_REUSEADDR , &reuse , sizeof(reuse)); fcntl(listenFd, F_SETFL, O_NONBLOCK); // 设置非阻塞方式 sockaddr_in sin; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); bind(listenFd, (const sockaddr*) &sin, sizeof(sin)); listen(listenFd, 5); struct epoll_event ev, events[MAX_EVENTS]; //生成用于处理accept的 epoll专用的文件描述符 epfd = epoll_create(MAX_EVENTS); //设置与要处理的事件相关的文件描述符 ev.data.fd = listenFd; //设置要处理的事件类型 ev.events = EPOLLIN | EPOLLET; //注册epoll事件 if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenFd, &ev) < 0) { printf("worker epoll_ctl error = %s.", strerror(errno)); exit(1); } while (true) { // 等待epoll事件的发生 int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); // 处理所发生的所有事件 for (int i = 0; i < nfds; ++i) // for循环中可以修改为线程池处理epoll事件 { if (events[i].data.fd == listenFd) { socklen_t clilen; struct sockaddr_in clientaddr; int sockfd = accept(listenFd, (sockaddr *) &clientaddr, &clilen); if (sockfd < 0) { continue; } // 设置非阻塞 if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0) | O_NONBLOCK) == -1) { continue; } ev.data.fd = sockfd; //设置用于注测的读操作事件 ev.events = EPOLLIN | EPOLLET |EPOLLONESHOT; //注册ev epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); } else if (events[i].events & EPOLLIN) { cout << "epollin--->" << endl; int sockfd = events[i].data.fd; pthread_t tid; pthread_create(&tid, NULL, process, &sockfd); pthread_detach(tid); usleep(1000); } } } return 0;}
(3)设置EPOLLONESHOT,创建线程读取,线程返回前,sleep几秒,在这几秒内,在将socket放入epoll队列前,发送数据,后续再次发送数据会触发in事件。
备忘:
边界触发的效率高,但程序实现上要小心,漏掉没处理的不会得到提醒了。
而电平触发的程序实现上方便,效率要低些,似乎libevent和lighttpd都用的它。
- epoll一点思考(4)
- epoll一点思考(3)
- epoll的一点思考(2)
- epoll的一点思考(5)
- epoll的一点思考(1)
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- 一点思考
- android自定义控件焦点问题
- debian 和windows的共享文件夹
- 国内外物联网公司
- iOS官方Sample大全
- C语言两种for循环写法分析
- epoll一点思考(4)
- 让人反感的mod_pagespeed!(补充2013-1-11)
- Hibernate 注解:一、多对多中set集合按指定字段排序
- Hibernate面试题
- C++ 使用结构类型实例化模板参数
- 设计一个普通的登录界面,都需要了解哪些信息?
- 求数组中出现次数大于数组长度一半元素
- struct tm,time,localtime,mktime,ctime,gmtime,difftime,asctime,strftime
- 职场心理寓言故事