epoll学习
一、epoll_create
#include <sys/epoll.h> int epoll_create(int size);
int epoll_create1(int flags);
返回:成功非负文件描述符,-1出错
size:内核监听数目一共多大
创建一个epoll接口,size参数和select不同,不是fd+1?
需要注意的是:当创建好epoll后,它就会占用一个fd值,在linux /proc/id/fd/能看到这个fd的,所以使用完epoll后,必须close()关闭,否则可能导致耗尽fd。
二、epoll_ctl
#include <sys/epoll.h> int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
返回:0成功,-1失败
epfd:由epoll_create生成的epoll专用的文件描述符
op:要进行的操作,可能取EPOLL_CTL_ADD注册、EPOLL_CTL_MOD修改、EPOLL_CTL_DEL删除
fd:关联的文件描述符
event:指向epoll_event指针
epoll的相关的epoll_event结构:
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t; struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
其中的events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
三、epoll_wait
#include <sys/epoll.h> int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout); int epoll_pwait(int epfd, struct epoll_event *events,
int maxevents, int timeout, const sigset_t *sigmask);
返回:发生事件数
epfd:由epoll_create生成的epoll专用的文件描述符
epoll_event:用于回传代处理事件的数组
maxevents:每次能处理的事件数
timeout:等待I/O事件发生的超时值
在linux中的man手册中有epoll模型:
#define MAX_EVENTS 10
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd; /* Set up listening socket, 'listen_sock' (socket(),
bind(), listen()) */ epollfd = epoll_create();
if (epollfd == -) {
perror("epoll_create");
exit(EXIT_FAILURE);
} ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
} for (;;) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -); //等待IO事件
if (nfds == -) {
perror("epoll_pwait");
exit(EXIT_FAILURE);
} for (n = ; n < nfds; ++n) {
//如果是主socket事件,则表示有新连接进入,需要进行新连接的处理
if (events[n].data.fd == listen_sock) {
conn_sock = accept(listen_sock,
(struct sockaddr *) &local, &addrlen);
if (conn_sock == -) {
perror("accept");
exit(EXIT_FAILURE);
}
//将新连接置于非阻塞模式
setnonblocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
//注意这里的参数EPOLLIN|EPOLLET并没有设置对写socket的监听
//如果有写操作的话,这个时候epoll是不会返回事件的
//如果要对写操作也监听的话,应该是EPOLLIN|EPOLLOUT|EPOLLET
//并且将新连接也加入EPOLL的监听队列
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -) {
//加入到epoll的监听队列里,这里用EPOLL_CTL_ADD
//来加一个新的epoll事件,可以通过EPOLL_CTL_DEL减少
//一个epoll事件,通过EPOLL_CTL_MOD来改变一个i额事件的监听方式
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
//如果不是主socket的事件的话,则代表这是一个用户的socket事件
//则用来处理这个用户的socket的事情是,比如说read(fd, xxx)之类,或者一些其他的处理
do_use_fd(events[n].data.fd);
}
}
}
epoll模型
下面是个epoll的使用例子:
#include <iostream>
#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 <stdlib.h>
#include <strings.h> using namespace std; #define MAXLINE 5
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5000
#define INFTIM 1000 void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock, F_GETFL);
if(opts < ) {
perror("fcntl(sock, GETFL)");
exit();
}
opts = opts | O_NONBLOCK;
if(fcntl(sock, F_SETFL, opts) < ) {
perror("fcntl(sock, SETFL, opts)");
exit();
}
} int main()
{
int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
ssize_t n;
char line[MAXLINE];
socklen_t clilen; struct epoll_event ev, events[];
epfd = epoll_create();
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = socket(AF_INET, SOCK_STREAM, ); setnonblocking(listenfd);
ev.data.fd = listenfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
char *local_addr = "192.168.1.63";
inet_aton(local_addr, &(serveraddr.sin_addr));
serveraddr.sin_port = htons(SERV_PORT);
bind(listenfd, (sockaddr *)&serveraddr, sizeof(serveraddr));
listen(listenfd, LISTENQ); maxi = ;
for( ; ; ) {
nfds = epoll_wait(epfd, events, , );
for(i=;i<nfds;i++) {
if(events[i].data.fd == listenfd) {
connfd = accept(listenfd, (sockaddr *)&clientaddr, &clilen);
if(connfd < ) {
perror("connfd < 0");
exit();
}
setnonblocking(connfd);
char *str = inet_ntoa(clientaddr.sin_addr);
std::cout<<"connect from"<<str<<std::endl;
ev.data.fd = connfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
} else if(events[i].events & EPOLLIN) {
if((sockfd = events[i].data.fd) < ) {
continue;
}
if((n = read(sockfd, line, MAXLINE)) < ) {
if(errno == ECONNRESET) {
close(sockfd);
events[i].data.fd = -;
} else {
std::cout<<"readline error"<<std::endl;
}
} else if(n == ) {
close(sockfd);
events[i].data.fd = -;
}
ev.data.fd = sockfd;
ev.events = EPOLLOUT | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
} else if(events[i].events & EPOLLOUT) {
sockfd = events[i].data.fd;
write(sockfd, line, n);
ev.data.fd = sockfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
}
}
}
epoll例子
epoll学习的更多相关文章
- 【UNIX】select、poll、epoll学习
三者都是UNIX下多路复用的内核接口,select是跨平台的接口,poll是systemV标准,epoll是linux专有的接口,基于poll改造而成. select 函数原型: int select ...
- I/O复用模型之epoll学习
简介: epoll是linux下多路复用I/O接口select/poll的增强版,它能够显著提高程序在大量并发连接中只有少量活跃的情况下的系统cpu利用率,原因是它会复用文件描述符集合来传递结果而不用 ...
- linux epoll 学习
一.epoll介绍 epoll是linux内核为处理大批量句柄而作的改进的poll,是linux下IO多路复用select.poll的增强版,它能显著减少程序在大量并发连接中只有少量活跃的情况下的系统 ...
- linux epoll学习
#include <sys/time.h> /* For portability */ #include <sys/select.h> int select(int nfds, ...
- epoll学习(二)
首先看程序一,这个程序想要实现的功能是当用户从控制台有任何输入操作时,输出”hello world!”. l 程序一 #include <unistd.h> #include <io ...
- epoll相关
1) 能不能给一个使用epoll相关API进行IO监控的示例?在<<epoll学习笔记>>中有一个简单的示例说明epoll相关API的使用, 但是这个示例是非常简单的, 它仅仅 ...
- epoll 系列函数简介、与select、poll 的区别
一.epoll 系列函数简介 #include <sys/epoll.h> int epoll_create(int size); int epoll_create1(int flags) ...
- python开发学习-day10(select/poll/epoll回顾、redis、rabbitmq-pika)
s12-20160319-day10 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...
- 网络编程基础——学习阻塞,非阻塞(select和epoll)
<h3 class="xyn" helvetica="" neue',="" helvetica,="" aria ...
随机推荐
- HTTP请求流程基础知识
HTTP协议解析: HTTP即超文本传输协议,是一种详细规定了浏览器和万维网服务器之间互相通信的规则,它是万维网交换信息的基础,它允许将HTML文档从WEB服务器传输到WEB浏览器. URL(统一资源 ...
- 【HDOJ6599】I Love Palindrome String(PAM,manacher)
题意:给出一个由小写字母组成的长为n的字符串S,定义他的子串[L,R]为周驿东串当且仅当[L,R]为回文串且[L,(L+R)/2]为回文串 求i=[1,n] 所有长度为i的周驿东串的个数 n<= ...
- delphi 解决RichViewEdit乱码问题
⑴ 设置RichViewEdit下面的几个属性: ① RTFReaderProperties → ParaStyleMode → rvrsAddIfNeeded ② RTFReaderProperti ...
- python使用开源图片识别第三方库tesseract
详细安装博客:https://blog.csdn.net/luanyongli/article/details/81385284 第一步tesseract-ocr的安装如果不会请参照:https:// ...
- 集训队8月9日(组合计数+容斥原理+Mobius函数)
刷题数:4 今天看了组合计数+容斥原理+Mobius函数,算法竞赛进阶指南169~179页 组合计数 https://www.cnblogs.com/2462478392Lee/p/11328938. ...
- 转载:eclipse中web项目小地球没了
转载自:{FROM:http://www.cnblogs.com/zhouyalei/archive/2013/01/30/2882651.html} MyEclipse下创建的项目 导入eclips ...
- 听说你懂个J?——前端发展闲聊
刚好周末和朋友聊起"前端从受鄙视到变得重要"这个话题,感慨前端这四年来的发展,遂有本文. 1. 前情提要 毋庸讳言,在我刚工作的时候,前端是还是一个不受重视的岗位.切图狗,写网页的 ...
- mongodbdriver 的C# 驱动findasync变成列表的方法
IAsyncCursorExtensions.ToList(返回的Task<IAsyncCursor<T>>实例). 也有他的异步版本.可以参见 https://mongodb ...
- JS - 模块
# CommonJS - [CommonJS - Wikipedia](https://en.wikipedia.org/wiki/CommonJS) ## 介绍 主要在浏览器之外地方(例如服务器和桌 ...
- java继承方法覆盖
public class TestB { private void f() { System.out.println("TestB"); } public static void ...