一、epoll服务端实现中需要的3个函数:

  • epoll_create:创建保存epoll文件描述符的空间。
  • epoll_ctl:向空间注册并注销文件描述符。
  • epoll_wait:与select函数类似,等待文件描述符发生变化。

二、示例

回声服务端:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h> #define BUF_SIZE 1024
#define EPOLL_SIZE 50
void error_handling(char * messages); int main(int argc, char *argv[])
{
if(argc != )
{
printf("Usage : %s <port>\n", argv[]);
exit();
}
int serverSock, clientSock;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientAddrSize; char buf[BUF_SIZE];
int strLen; struct epoll_event *ep_events;
struct epoll_event event;
int epfd, event_cnt; serverSock =socket(PF_INET, SOCK_STREAM, );
if(serverSock == -)
error_handling("socket() error"); memset(&serverAddr, , sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(atoi(argv[])); if(bind(serverSock, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -)
error_handling("bind() error");
if(listen(serverSock, ) == -)
error_handling("listen() error"); epfd = epoll_create(EPOLL_SIZE);
ep_events = (struct epoll_event*)malloc(sizeof(struct epoll_event) * EPOLL_SIZE); event.events = EPOLLIN;
event.data.fd = serverSock;
epoll_ctl(epfd, EPOLL_CTL_ADD, serverSock, &event); puts("Server start...");
while(){
event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -);
if(event_cnt == -){
puts("epoll_wait() error");
break;
}
for(int i = ; i < event_cnt; i++){
if(ep_events[i].data.fd == serverSock){
clientAddrSize = sizeof(clientAddr);
clientSock = accept(serverSock, (struct sockaddr*)&clientAddr, &clientAddrSize);
event.events = EPOLLIN;
event.data.fd = clientSock;
epoll_ctl(epfd, EPOLL_CTL_ADD, clientSock, &event);
printf("connected client: %d\n", clientSock);
}
else{
strLen = read(ep_events[i].data.fd, buf, BUF_SIZE);
if(strLen == ){
epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
close(ep_events[i].data.fd);
printf("closed client: %d\n", ep_events[i].data.fd);
}
else{
write(ep_events[i].data.fd, buf, strLen);
puts("echo");
}
}
}
}
close(serverSock);
puts("Server close...");
return ;
} void error_handling(char * messages)
{
puts(messages);
exit();
}

三、条件触发和边缘触发

  条件触发方式中,只要输入缓冲有数据就会一直通知该事件。

  边缘触发方式中输入缓冲收到数据时仅注册一次该事件。即使输入缓冲中还留有数据,也不会再进行注册。

  select模型是以条件触发的方式工作的。

  epoll默认是以条件触发方式工作的。

  若将文件(套接字)改为非阻塞模式。调用read&write函数时,无论是否存在数据,都会形成非阻塞文件(套接字)。

  边缘触发方式下,以阻塞方式工作的read&write函数又可能引起服务器端的长事件停顿。因此,边缘触发方式中一定要采用非阻塞read&write函数。

边缘触发的回声服务端:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h> #define BUF_SIZE 4
#define EPOLL_SIZE 50
void setnonblockingmode(int fd);
void error_handling(char * messages); int main(int argc, char *argv[])
{
if(argc != )
{
printf("Usage : %s <port>\n", argv[]);
exit();
}
int serverSock, clientSock;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientAddrSize; char buf[BUF_SIZE];
int strLen; struct epoll_event *ep_events;
struct epoll_event event;
int epfd, event_cnt; serverSock =socket(PF_INET, SOCK_STREAM, );
if(serverSock == -)
error_handling("socket() error"); memset(&serverAddr, , sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(atoi(argv[])); if(bind(serverSock, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -)
error_handling("bind() error");
if(listen(serverSock, ) == -)
error_handling("listen() error"); epfd = epoll_create(EPOLL_SIZE);
ep_events = (struct epoll_event*)malloc(sizeof(struct epoll_event) * EPOLL_SIZE); setnonblockingmode(serverSock);
event.events = EPOLLIN;
event.data.fd = serverSock;
epoll_ctl(epfd, EPOLL_CTL_ADD, serverSock, &event); puts("Server start...");
while(){
event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -);
if(event_cnt == -){
puts("epoll_wait() error");
break;
}
puts("return epoll_wait");
for(int i = ; i < event_cnt; i++){
if(ep_events[i].data.fd == serverSock){
clientAddrSize = sizeof(clientAddr);
clientSock = accept(serverSock, (struct sockaddr*)&clientAddr, &clientAddrSize);
setnonblockingmode(clientSock);
event.events = EPOLLIN|EPOLLET;
event.data.fd = clientSock;
epoll_ctl(epfd, EPOLL_CTL_ADD, clientSock, &event);
printf("connected client: %d\n", clientSock);
}
else{
while()
{
strLen = read(ep_events[i].data.fd, buf, BUF_SIZE);
if(strLen == ){
epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
close(ep_events[i].data.fd);
printf("closed client: %d\n", ep_events[i].data.fd);
break;
}
else if(strLen < ){
if(errno == EAGAIN)
break;
else
puts("???????");
}
else{
write(ep_events[i].data.fd, buf, strLen);
}
}
}
}
}
close(serverSock);
puts("Server close...");
return ;
} void setnonblockingmode(int fd) // 套接字改成非阻塞的
{
int flag = fcntl(fd, F_GETFL, );
fcntl(fd, F_SETFL, flag|O_NONBLOCK);
} void error_handling(char * messages)
{
puts(messages);
exit();
}

linux—epoll的更多相关文章

  1. Server Develop (六) Linux epoll总结

    Linux  epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低效率.因为在内核中的sele ...

  2. Linux Epoll介绍和程序实例

    Linux Epoll介绍和程序实例 1. Epoll是何方神圣? Epoll但是当前在Linux下开发大规模并发网络程序的热门人选,Epoll 在Linux2.6内核中正式引入,和select类似, ...

  3. Linux epoll总结

    Linux epoll总结 Linux  epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低 ...

  4. c/c++ linux epoll系列3 利用epoll_wait设置timeout时间长度

    linux epoll系列3 利用epoll_wait设置timeout时间长度 epoll_wait函数的第四个参数可以设置,epoll_wait函数的等待时间(timeout时间长度). 例子1, ...

  5. c/c++ linux epoll系列2 利用epoll_wait查看是否可以送信

    linux epoll系列2 利用epoll_wait查看是否可以送信 write函数本来是非阻塞函数,但是当缓存区被写满后,再往缓存区里写的时候,就必须等待缓存区再次变成可写,所以这是write就变 ...

  6. c/c++ linux epoll系列1 创建epoll

    linux epoll系列1 创建epoll 据说select和poll的弱点是,随着连接(socket)的增加,性能会直线下降. epoll不会随着连接(socket)的增加,性能直线下降. 知识点 ...

  7. Windows完成端口与Linux epoll技术简介

    收藏自:http://www.cnblogs.com/cr0-3/archive/2011/09/09/2172280.html WINDOWS完成端口编程1.基本概念2.WINDOWS完成端口的特点 ...

  8. Java网络编程和NIO详解6:Linux epoll实现原理详解

    Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...

  9. 源码剖析Linux epoll实现机制及Linux上惊群

    转载:https://blog.csdn.net/tgxallen/article/details/78086360 看源码是对一个技术认识最直接且最有效的方式了,之前用Linux Epoll做过一个 ...

  10. Windows完成端口与Linux epoll技术简介(能看懂)

    WINDOWS完成端口编程1.基本概念2.WINDOWS完成端口的特点3.完成端口(Completion Ports )相关数据结构和创建4.完成端口线程的工作原理5.Windows完成端口的实例代码 ...

随机推荐

  1. 最新QT4.8+kernel_3.2.5+uboot_2010.06+tslib移植成功-问题小结

    2012-02-19 21:34:13 都是从源码下载然后自己修改,使用与TQ2440,之前uboot其实已经完成了.但是yaffs2没带起来.现在回头看来是很简单的了.bootargs参数中我设置成 ...

  2. hbase的一些要点

    hbase特点及简介: hbase源自于谷歌的三大论文之一 GFS -- hdfs MapReduce - MR BigTable - hbase hbase在以Hadoop为基础的生态圈中的地位 h ...

  3. MyTests

    目录 About Tests Selenium自动化测试 Pyppeteer Explain About Tests 扯淡!测试之瞎扯淡 Selenium自动化测试 什么是Selenium? Sele ...

  4. 高级shell 脚本

    1.函数 函数是一个脚本代码块,你可以为其命名并在代码中任何位置重用.要在脚本中使用该代码块时,只要使用所起的函数名就行了(这个过程称为调用函数).本节将会介绍如何在shell脚本中创建和使用函数 创 ...

  5. ubuntu Fcitx 输入法 选择 黑框问题 解决方案

    在虚拟机装了个xubuntu,弄好fcitx 输入法后,打字时看不到选择框,被黑框折腾的不行,后来了一个方法,暂时解决了问题. 用 killall fcitx-qimpanel 结束 fcitx-qi ...

  6. Java基础学习-三元运算符和键盘录入的基本步骤和使用

    1.三元运算符的执行流程   package com.denniscui_05; /*  * 三元运算符:  *         关系表达式?表达式1:表达式2  *  * 执行流程:  *      ...

  7. 详解Bootstrap实现基本布局的方法

    看到了一篇 20 分钟打造 Bootstrap 站点的文章,内容有点老,重新使用bootstrap教程实现一下,将涉及的内容也尽可能详细说明. 1. 创建基本的页面我们先创建一个基本的 HTML 模板 ...

  8. spring事务的7种传播行为

    https://blog.csdn.net/weixin_39625809/article/details/80707695 一般用于并发,分布式锁.复杂业务情况

  9. easyUI combobox使用方法总结

    combobox,中文叫复合框,是把文本框和列表框的特性结合起来的一种控件,这个控件,既可以输入文字,也可以像列表框一样选择选项 Combobox用法和方法参数: 1. 需要引入class=" ...

  10. 解决 scapy “NameError: global name 'wrpcap' is not defined” 错误

    解决 scapy "NameError: global name 'wrpcap' is not defined" 错误 通过 scapy 编写发包脚本时遇到如下错误: Trace ...