`
weiyinchao88
  • 浏览: 1234373 次
文章分类
社区版块
存档分类
最新评论

epoll用法说明(源代码)

 
阅读更多

epoll用到的所有函数都是在头文件sys/epoll.h中声明的,下面简要说明所用到的数据结构和函数:
所用到的数据结构
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 */
};
结构体epoll_event 被用于注册所感兴趣的事件和回传所发生待处理的事件,其中epoll_data 联合体用来保存触发事件的某个文件描述符相关的数据,例如一个client连接到服务器,服务器通过调用accept函数可以得到于这个client对应的socket文件描述符,可以把这文件描述符赋给epoll_data的fd字段以便后面的读写操作在这个文件描述符上进行。epoll_event 结构体的events字段是表示感兴趣的事件和被触发的事件可能的取值为:EPOLLIN :表示对应的文件描述符可以读;
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(我不太明白是什么意思,可能是类似client关闭 socket连接这样的事件);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET:表示对应的文件描述符有事件发生;
所用到的函数:
1、epoll_create函数
函数声明:int epoll_create(int size)
该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围(我觉得这个参数和select函数的第一个参数应该是类似的但是该怎么设置才好,我也不太清楚)。
2、epoll_ctl函数
函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
该函数用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
参数:epfd:由 epoll_create 生成的epoll专用的文件描述符;
op:要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD
改、EPOLL_CTL_DEL 删除
fd:关联的文件描述符;
event:指向epoll_event的指针;
如果调用成功返回0,不成功返回-1
3、epoll_wait函数
函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
该函数用于轮询I/O事件的发生;
参数:
epfd:由epoll_create 生成的epoll专用的文件描述符;
epoll_event:用于回传代处理事件的数组;
maxevents:每次能处理的事件数;
timeout:等待I/O事件发生的超时值;
返回发生事件数。
例子:


#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;
}
/************关于本文档********************************************
*filename: epoll-server.c
*purpose: 演示epoll处理海量socket连接的方法
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2007-01-31 21:00
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to:Google
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/
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;

if (argv[1])
myport = atoi(argv[1]);
else
myport = 7838;

if (argv[2])
lisnum = atoi(argv[2]);
else
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);
if (argv[3])
my_addr.sin_addr.s_addr = inet_addr(argv[3]);
else
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;
}

编译此程序用命令:
gcc -Wall epoll-server.c -o server

运行此程序需要具有管理员权限!

sudo ./server 7838 1

通过测试这一个服务器可能同时处理10000 -3 = 9997 个连接!

如果这是一个在线服务系统,那么它可以支持9997人同时在线,比如游戏、聊天等。
分享到:
评论

相关推荐

    epoll scgi server python 源代码

    通过阅读和学习这个源代码,你可以了解如何将 epoll 的高性能与 SCGI 的效率结合,构建出一个能处理大量并发请求的 Python Web 服务器。同时,这也有助于深入理解网络编程、多路复用 I/O 机制以及 Python 在服务器...

    unix环境高级编程源代码

    源代码会展示如何打开、读取、写入和关闭文件,以及如何使用符号链接、硬链接和文件权限等特性。 3. **网络通信**:Unix提供了丰富的网络编程接口,如套接字(socket)。源代码可能包含客户端-服务器模型的实现,...

    epoll实现cs通信.zip

    在IT行业中,网络编程是不可或缺的一部分,特别是在构建高性能服务器...通过阅读和分析源代码,开发者可以深入理解epoll的用法及其在高性能网络编程中的优势。同时,这也为实现其他基于epoll的复杂网络服务提供了基础。

    linux下使用epoll技术制作大并发服务器(比如一个游戏房间能同时进来1千人)的实现 附源代码

    在Linux系统中,为了处理高并发的网络连接,epoll技术被广泛应用于高性能服务器的开发。epoll是一种I/O事件的通知...通过对源代码的深入理解,我们可以学习到如何将epoll与服务器架构相结合,实现高性能的网络服务。

    epoll 精髓

    而且select支持的最大文件描述符数目是有限制的,在早期的Linux系统中,这个限制是1024,尽管可以通过修改源代码中的FD_SETSIZE宏定义并重新编译内核来增加这个数目,但这并不是解决问题的根本方法。 epoll与select...

    UNIX网络编程V1源代码

    《UNIX网络编程V1源代码》是网络编程领域的一份宝贵资源,主要涵盖了UNIX系统上的网络应用程序开发。这本书,由W. Richard Stevens撰写,是学习和理解网络协议、套接字编程以及UNIX环境下网络通信机制的经典之作。源...

    一个端口扫描器源代码

    源代码是程序的基础,通过查看和理解源代码,我们可以学习到编程语言的用法、特定算法的实现以及网络通信的基本原理。以下将详细介绍与"一个端口扫描器源代码"相关的知识点: 1. **端口和协议**:端口是计算机网络...

    IO多路复用之epoll实例

    **IO多路复用之epoll实例** ...在"test"这个文件中,可能包含了示例的源代码,包括了上述步骤的具体实现。为了深入理解这个例子,建议阅读和分析代码,尤其是与epoll相关的函数调用和事件处理逻辑。

    Socket异步编程源代码与资料

    事件驱动模型,如使用回调函数或者基于Epoll(Linux)或IOCP(Windows)的机制,让程序在有事件发生时得到通知,而非一直轮询检查。 3. **点对点通讯(P2P)** P2P通信是一种直接在两个网络节点之间建立连接的方式...

    netty-transport-classes-epoll-4.1.74.Final-API文档-中文版.zip

    赠送源代码:netty-transport-classes-epoll-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-transport-classes-epoll-4.1.74.Final.pom; 包含翻译后的API文档:netty-transport-classes-epoll-4.1.74....

    APUE(Unix环境高级编程源代码)相关源代码

    1. **系统调用**:APUE源代码中包含了大量对系统调用的使用,如`open()`, `read()`, `write()`, `close()`等用于文件操作,`fork()`, `execve()`用于进程创建和执行,以及`wait()`, `waitpid()`用于进程同步和通信。...

    Linux环境下Epoll系统调用实现web服务器并发工作

    在`webserver.c`源代码中,我们可以看到具体的实现细节,包括结构体定义、套接字操作、Epoll接口的使用等。代码会演示如何初始化Epoll,监听套接字的注册,事件循环的运行,以及对就绪事件的处理逻辑。通过对这个...

    HTTPSVR 源代码

    "HTTPSVR 源代码"是一个涉及到网络服务器开发的重要主题,主要关注的是使用HTTP协议构建服务器的源代码实现。这个主题涵盖了多个IT领域的知识点,包括但不限于: 1. **HTTP协议**:HTTP(超文本传输协议)是互联网...

    ACE 使用EPOLL

    - **ACE**:Adaptive Communication Environment(自适应通信环境)是一个支持实时通信应用的开放源代码框架,提供了广泛的通信和操作系统抽象服务。 - **EPOLL**:是Linux内核提供的一个I/O多路复用技术,相比传统...

    netty-transport-classes-epoll-4.1.73.Final-API文档-中英对照版.zip

    赠送源代码:netty-transport-classes-epoll-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-transport-classes-epoll-4.1.73.Final.pom; 包含翻译后的API文档:netty-transport-classes-epoll-4.1.73....

    netty-transport-classes-epoll-4.1.73.Final-API文档-中文版.zip

    赠送源代码:netty-transport-classes-epoll-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-transport-classes-epoll-4.1.73.Final.pom; 包含翻译后的API文档:netty-transport-classes-epoll-4.1.73....

    linux下的epoll服务程序实例

    `EPollCodeSource`很可能是包含服务程序和客户端程序源代码的压缩包。解压后,可以详细研究代码实现,包括如何创建和管理`epoll`实例,如何处理套接字的读写事件,以及如何在多线程环境中使用`epoll`等。 总结,`...

    基于VC开发epoll程序方案和源码.rar

    标题中的"基于VC开发epoll程序方案...通过阅读和理解这些源代码和文档,开发者可以学习到如何在VC环境下利用epoll机制实现高效的网络服务器,同时掌握跨平台编程技巧,这对于开发高性能、可扩展的网络应用非常有价值。

    UNIX网络编程 卷1:源代码

    3. **套接字API函数**:如`socket()`、`bind()`、`listen()`、`accept()`、`connect()`、`send()`、`recv()`等,这些函数在源代码中被广泛使用,帮助读者了解它们的具体作用和用法。 4. **I/O复用(IO Multiplexing...

    UNIX网络编程 卷1:套接字联网API源代码

    《UNIX网络编程 卷1:套接字联网API源代码》是网络编程领域的一本经典著作,主要关注于UNIX系统中的网络通信,特别是基于套接字的编程接口。这本书深入探讨了如何使用套接字API来实现跨网络的通信,为开发者提供了...

Global site tag (gtag.js) - Google Analytics