linux—epoll
一、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的更多相关文章
- Server Develop (六) Linux epoll总结
Linux epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低效率.因为在内核中的sele ...
- Linux Epoll介绍和程序实例
Linux Epoll介绍和程序实例 1. Epoll是何方神圣? Epoll但是当前在Linux下开发大规模并发网络程序的热门人选,Epoll 在Linux2.6内核中正式引入,和select类似, ...
- Linux epoll总结
Linux epoll总结 Linux epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低 ...
- c/c++ linux epoll系列3 利用epoll_wait设置timeout时间长度
linux epoll系列3 利用epoll_wait设置timeout时间长度 epoll_wait函数的第四个参数可以设置,epoll_wait函数的等待时间(timeout时间长度). 例子1, ...
- c/c++ linux epoll系列2 利用epoll_wait查看是否可以送信
linux epoll系列2 利用epoll_wait查看是否可以送信 write函数本来是非阻塞函数,但是当缓存区被写满后,再往缓存区里写的时候,就必须等待缓存区再次变成可写,所以这是write就变 ...
- c/c++ linux epoll系列1 创建epoll
linux epoll系列1 创建epoll 据说select和poll的弱点是,随着连接(socket)的增加,性能会直线下降. epoll不会随着连接(socket)的增加,性能直线下降. 知识点 ...
- Windows完成端口与Linux epoll技术简介
收藏自:http://www.cnblogs.com/cr0-3/archive/2011/09/09/2172280.html WINDOWS完成端口编程1.基本概念2.WINDOWS完成端口的特点 ...
- Java网络编程和NIO详解6:Linux epoll实现原理详解
Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...
- 源码剖析Linux epoll实现机制及Linux上惊群
转载:https://blog.csdn.net/tgxallen/article/details/78086360 看源码是对一个技术认识最直接且最有效的方式了,之前用Linux Epoll做过一个 ...
- Windows完成端口与Linux epoll技术简介(能看懂)
WINDOWS完成端口编程1.基本概念2.WINDOWS完成端口的特点3.完成端口(Completion Ports )相关数据结构和创建4.完成端口线程的工作原理5.Windows完成端口的实例代码 ...
随机推荐
- 《Whitelabel Error Page 404》 对于Springboot初学者可能出现问题的原因
whitelabel error page异常一定是有原因的,比如,访问路径不对,解析不对,注解忘记引入等.对于初学者,一定要注意一点,程序只加载Application.java所在包及其子包下的内容 ...
- activemq修改端口
1.修改TCP 61616端口 cd /apps/svr/activemq/conf cat activemq.xml |grep transportConnector <transportCo ...
- 认识volatile的工作原理
前言 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”.可见性的意思是当 ...
- postman工具的使用
https://www.cnblogs.com/rookie-c/p/5753948.html#4100341 https://www.jellythink.com/archives/category ...
- id、class等各种选择器总结
1. id 选择器 # class 选择器 . 标签 选择器 标签名 群组 ...
- 你不知道的JS(2)深入了解闭包
很久之前就想写一篇关于闭包的博客了,但是总是担心写的不够完全.不够好,不管怎样,还是要把我理解的闭包和大家分享下,比较长,希望耐心看完. 定义 说实话,给闭包下一个定义是很困难的,原因在于javasc ...
- iou与giou对比
设矩形1大小为100x100,矩形2从左上角顶点重合开始,向右滑动250个单位. c++源码(基于opencv3.4.0) float iou(const cv::Rect& r1, cons ...
- 读Vue源码 (依赖收集与派发更新)
vue的依赖收集是定义在defineReactive方法中,通过Object.defineProperty来设置getter,红字部分主要做依赖收集,先判断了Dep.target如果有的情况会执行红字 ...
- idea自个常用工具的总结
1.直接打开某类:ctrl+shift+t2.注释某类:ctrl+?3. implementation :Ctrl+T4.rename:Alt +Shirft +R5.Show Intention A ...
- 數據監控与診斷--環形緩沖區(RING BUFFER)
1. 環形緩沖區 動態管理視圖: sys.dm_os_ring_buffers 查看ring_buffers: Select distinct ring_buffer_type from sys.d ...