epoll使用实例说明
首先看一下epoll的几个函数的介绍。
1、epoll_create函数
/**
* @brief 该函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。
*
* @param size size就是你在这个epoll fd上能关注的最大socket fd数
*
* @return 生成的文件描述符
*/
int epoll_create(int size);
2、epoll_ctl函数
/**
* @brief 该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。
*
* @param epfd 由 epoll_create 生成的epoll专用的文件描述符
* @param op 要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除
* @param fd 关联的文件描述符
* @param event 指向epoll_event的指针
*
* @return 0 succ
* -1 fail
*/
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *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 */
};
常用的事件类型:
EPOLLIN :表示对应的文件描述符可以读;
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 表示对应的文件描述符有事件发生;
例:
struct epoll_event ev;
//设置与要处理的事件相关的文件描述符
ev.data.fd=listenfd;
//设置要处理的事件类型
ev.events=EPOLLIN|EPOLLET;
//注册epoll事件
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
3、epoll_wait函数
/**
* @brief 该函数用于轮询I/O事件的发生
*
* @param epfd 由epoll_create 生成的epoll专用的文件描述符
* @param events 用于回传代处理事件的数组
* @param maxevents 每次能处理的事件数
* @param timeout 等待I/O事件发生的超时值;-1相当于阻塞,0相当于非阻塞。一般用-1即可
*
* @return >=0 返回发生事件数
* -1 错误
*/
int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);
好了,其实在epoll的使用中无非就用到了上面介绍的几个函数,下面贴一段用epoll实现的服务器代码:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/resource.h>
#define MAXBUF 1024
#define MAXEPOLLSIZE 10000
/*
setnonblocking – 设置句柄为非阻塞方式
*/
int setnonblocking(int sockfd)
{
if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)
{
return -1;
}
return 0;
}
/*
handle_message – 处理每个 socket 上的消息收发
*/
int handle_message(int new_fd)
{
char buf[MAXBUF + 1];
int len;
/* 开始处理每个新连接上的数据收发 */
bzero(buf, MAXBUF + 1);
/* 接收客户端的消息 */
len = recv(new_fd, buf, MAXBUF, 0);
if (len > 0)
{
printf(“%d接收消息成功:’%s’,共%d个字节的数据/n”,
new_fd, buf, len);
}
else
{
if (len < 0)
printf
(“消息接收失败!错误代码是%d,错误信息是’%s’/n”,
errno, strerror(errno));
close(new_fd);
return -1;
}
/* 处理每个新连接上的数据收发结束 */
return len;
}
int main(int argc, char **argv)
{
int listener, new_fd, kdpfd, nfds, n, ret, curfds;
socklen_t len;
struct sockaddr_in my_addr, their_addr;
unsigned int myport, lisnum;
struct epoll_event ev;
struct epoll_event events[MAXEPOLLSIZE];
struct rlimit rt;
myport = 5000;
lisnum = 2;
/* 设置每个进程允许打开的最大文件数 */
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
{
perror(“setrlimit”);
exit(1);
}
else
{
printf(“设置系统资源参数成功!/n”);
}
/* 开启 socket 监听 */
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror(“socket”);
exit(1);
}
else
{
printf(“socket 创建成功!/n”);
}
setnonblocking(listener);
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)
{
perror(“bind”);
exit(1);
}
else
{
printf(“IP 地址和端口绑定成功/n”);
}
if (listen(listener, lisnum) == -1)
{
perror(“listen”);
exit(1);
}
else
{
printf(“开启服务成功!/n”);
}
/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
kdpfd = epoll_create(MAXEPOLLSIZE);
len = sizeof(struct sockaddr_in);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listener;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0)
{
fprintf(stderr, “epoll set insertion error: fd=%d/n”, listener);
return -1;
}
else
{
printf(“监听 socket 加入 epoll 成功!/n”);
}
curfds = 1;
while (1)
{
/* 等待有事件发生 */
nfds = epoll_wait(kdpfd, events, curfds, -1);
if (nfds == -1)
{
perror(“epoll_wait”);
break;
}
/* 处理所有事件 */
for (n = 0; n < nfds; ++n)
{
if (events[n].data.fd == listener)
{
new_fd = accept(listener, (struct sockaddr *) &their_addr,&len);
if (new_fd < 0)
{
perror(“accept”);
continue;
}
else
{
printf(“有连接来自于: %d:%d, 分配的 socket 为:%d/n”,
inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
}
setnonblocking(new_fd);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = new_fd;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, new_fd, &ev) < 0)
{
fprintf(stderr, “把 socket ‘%d’ 加入 epoll 失败!%s/n”,
new_fd, strerror(errno));
return -1;
}
curfds++;
}
else
{
ret = handle_message(events[n].data.fd);
if (ret < 1 && errno != 11)
{
epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);
curfds–-;
}
}
}
}
close(listener);
return 0;
}
OK,基本到这里epoll的使用也就明朗了,希望对大家有用~
epoll使用实例说明的更多相关文章
- select、poll、epoll程序实例
三个函数的基本用法如下: select 创建 fd_set rset , allset; FD_ZERO(&allset); FD_SET(listenfd, &allset); 监听 ...
- 服务器 libevent中epoll使用实例demo
名词解释:man epoll之后,得到如下结果: NAME epoll - I/O event notification facility SYNOPSIS #include ...
- epoll测试实例
C++ Code 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 ...
- 基本I/O模型与Epoll简介
5种基本的I/O模型:1)阻塞I/O ;2)非阻塞I/O; 3)I/O复用(select和poll);4)信号驱动I/O(SIGIO);5)异步I/O(POSIX.1的aio_系列函数). 操作系统中 ...
- Python-select详解(select、epoll)
select函数操作集合的时候有个要求,要么集合本身是描述符,要么他提供一个fileno()接口,返回一个描述符. I/O多路复用是在单线程模式下实现多线程的效果,实现一个多I/O并发的效果.看一个简 ...
- Epoll模型详解
Linux 2.6内核中提高网络I/O性能的新方法-epoll I/O多路复用技术在比较多的TCP网络服务器中有使用,即比较多的用到select函数. 1.为什么select落后 首先,在Lin ...
- linux epoll模型
原文:http://yjtjh.blog.51cto.com/1060831/294119 Linux I/O多路复用技术在比较多的TCP网络服务器中有使用,即比较多的用到select函数.Linux ...
- 深度理解select、poll和epoll
在linux 没有实现epoll事件驱动机制之前,我们一般选择用select或者poll等IO多路复用的方法来实现并发服务程序.在大数据.高并发.集群等一些名词唱得火热之年代,select和poll的 ...
- epoll使用详解
目录 epoll介绍 Epoll的优点: 1.支持一个进程打开大数目的socket描述符(FD) 2.IO效率不随FD数目增加而线性下降 3.支持边缘触发模式 4.使用mmap加速内核与用户空间的消息 ...
随机推荐
- leetcode第七题Reverse Integer (java)
Reverse Integer Reverse digits of an integer. Example1: x = 123, return 321 Example2: x = -123, retu ...
- 避免eclipse下启动run就进入debug模式
分析原因:可能是eclipse的一个bug 解决方法:进入手机开发者模式设置,关闭usb调试和开发者模式,再重新打开即可.
- jQuery响应式幻灯片插件jquery.glide.js(支持触摸&轻量级)
找到一款好的幻灯片插件不容易,找到一款功能全并且使用很简单的幻灯片更不容易,今天为大家分享一款全能的幻灯片插件glide.js,也是我现在在使用的一款插件. jquery.glide.js是响应和触摸 ...
- Tarjan系列算法总结(hdu 1827,4612,4587,4005)
tarjan一直是我看了头大的问题,省选之前还是得好好系统的学习一下.我按照不同的算法在hdu上选题练习了一下,至少还是有了初步的认识.tarjan嘛,就是维护一个dfsnum[]和一个low[],在 ...
- 在安全层面,企业如何获得更好的投资回报率 ROI?
前言 任何企业对投资都有回报的要求,回报可能是直接的「利润」,达到短期.长期的目标,或者通过投资减少损失.因此每个项目的决策者在每笔投资前都要衡量 ROI,证明该投资能达到的效果和收益,以便在项目结束 ...
- VisualStudio替换所有空行
[一篮饭特稀原创,转载请注明出自http://www.cnblogs.com/wanghafan/p/3371620.html] Ctrl+Shift+H 查找内容\r\n\r\n //如果要替换 ...
- 【Xamarin挖墙脚系列:最重要的布局ListView】
原文:[Xamarin挖墙脚系列:最重要的布局ListView] 安卓的几个重要的布局 线性布局 相对布局 Table布局 Tab布局 表格Grid布局 列表布局. 这几种基本的布局的方式,最重要 ...
- Beej网络socket编程指南
bind()函数 一旦你有一个套接字,你可能要将套接字和机器上的一定的端口关联 起来.(如果你想用listen()来侦听一定端口的数据,这是必要一步--MUD 告 诉你说用命令 "telne ...
- C# 验证码识别基础方法及源码
先说说写这个的背景 最近有朋友在搞一个东西,已经做的挺不错了,最后想再完美一点,于是乎就提议把这种验证码给K.O.了,于是乎就K.O.了这个验证码.达到单个图片识别时间小于200ms,500个样本人工 ...
- 【转】c++重载、覆盖、隐藏——理不清的区别
原文网址:http://blog.sina.com.cn/s/blog_492d601f0100jqqm.html 再次把林锐博士的<高质量c++编程指南>翻出来看的时候,再一次的觉得这是 ...