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完成端口的实例代码 ...
随机推荐
- jQuery的deferred对象使用详解
转自: https://www.cnblogs.com/PengLee/p/5657101.html jQuery的开发速度很快,几乎每半年一个大版本,每两个月一个小版本.每个版本都会引入一些新功能. ...
- Linux中检查本地系统上的开放端口列表的方法
在 Linux 中很少有用于此目的的实用程序.然而,我提供了四个最重要的 Linux 命令来检查这一点. 你可以使用以下四个命令来完成这个工作.这些命令是非常出名的并被 Linux 管理员广泛使用.n ...
- 2.获取指定目录及子目录下所有txt文件的个数,并将这些txt文件复制到F盘下任意目录
package cn.it.text; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import ...
- Centos7配置SVN服务端
环境 Centos 7 SVN 1.7 安装SVN Shell> yum install subversion -y 准备配置和仓库 Shell> mkdir -p /mydata/rep ...
- Android组件系列----Intent详解(转载笔记)
[正文] Intent组件虽然不是四大组件,但却是连接四大组件的桥梁,学习好这个知识,也非常的重要. 一.什么是Intent 1.Intent的概念: Android中提供了Intent机制来协助应用 ...
- 设计模式理解(八)结构型——装饰者模式(记得加上UML图 --- 未完)
一段时间没写,又忘了,晕...设计模式这种东西一定要经常用. 装饰者模式(Decorator)用于动态地给一个对象增加一些额外的职责,就增加功能来说,他比生成子类更为灵活. 装饰者模式的原则是: 能用 ...
- Raphael.js--基础1
Raphael.js 特点: 1.兼容VML和SVG 2.扩展功能——动画 用法: //1.创建画布 let paper=Raphael(x,y,width,height); //2.创建形状 let ...
- dnsmasq 设置自动获取主机名
A1_IP:192.168.164.145 A1# yum install dnsmasq -y A1# echo "addn-hosts=/etc/domains" >&g ...
- java中annotation
什么是annotation(注解)? java.lang.annotation,接口Annotation.对于Annotation,是Java5的新特性,JDK5引入了Metadata(元数据)很容易 ...
- @resource、@Autowired、@Service在一个接口多个实现类中的应用
Spring在没有引入注解之前,传统的Spring做法是使用.xml文件来对bean进行注入,所有的内容都需要配置在.xml文件中,使配置和编程分离,却增加了可读性和复杂度. Spring注解将复杂的 ...