一、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. 选择排序java实现

    package text.algorithm; /** * 选择排序 * O(n^2);空间复杂度O(1); */public class SelectionSort { public static ...

  2. CCF CSP 201612-1 中间数

    题目链接:http://118.190.20.162/view.page?gpid=T52 问题描述 试题编号: 201612-1 试题名称: 中间数 时间限制: 1.0s 内存限制: 256.0MB ...

  3. Linux监控工具讲解

    本文主要记录一下 Linux系统上一些常用的系统监控工具,非常好用.正所谓磨刀不误砍柴工,花点时间总结一下是值得的! 本文内容脑图如下: top 命令 top 命令我想大家都挺熟悉吧!Linux 下的 ...

  4. vue 异步刷新页面,

    入口文件vue.app中 <div id="app"> <router-view v-if="isRouterAlive" /> < ...

  5. Spring AOP 简介

    Spring AOP 简介 如果说 IoC 是 Spring 的核心,那么面向切面编程就是 Spring 最为重要的功能之一了,在数据库事务中切面编程被广泛使用. AOP 即 Aspect Orien ...

  6. Nodejs“实现”Dubbo Provider

    背景 目前nodejs应用越来越广泛,但和java的dubbo体系接入困难,所以我们需要实现node端的dubbo provider逻辑.java的dubbo provider是和consumer在一 ...

  7. TabLayout基本使用

    前言 Tablayout继承自HorizontalScrollView,可以用作顶部标签效果.底部导航栏效果.一般多与ViewPager一起使用. 想直接了解如何实现短下滑效果的请看:TabLayou ...

  8. JS(JavaScript)的初了解8(更新中···)

    1.函数都有返回值…… 而方法的本质也是函数,所以也有返回值. Document.getElementById() 返回的是获取的标签 getElementsByClassName()和getElem ...

  9. linux服务基础之http协议

    URI:Uniform Resource Identifier URL: Uniform Resource Locator,用于描述某服务器某特定资源的位置 URN: Uniform Resource ...

  10. ssh 框架整合事,使用注解,action提示找不到

    There is no Action mapped for namespace [/] and action name [/select] associated with context path [ ...