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完成端口的实例代码 ...
随机推荐
- Redis连接池
package com.lee.utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; impor ...
- freeswitch reloadxml 出错
1.修改fs配置文件后,reloadxml控制台上报错误. 2,控制台日志显示 error near line 7301]:missing>] 查询 log 下的 freeswitch.xml. ...
- UVA1030 Image Is Everything
思路 如果两个面看到颜色不同,则这个正方体一定要被删掉 然后依次考虑每个面即可 注意坐标的映射 代码 #include <cstdio> #include <algorithm> ...
- C# 简单粗暴写日志
public static void WriteLog(string text) { string path = AppDomain.CurrentDomain.BaseDirectory; path ...
- Markdown简记
一篇好的博客文档离不开一个优秀的编辑器.借此篇文章介绍一下编写该博客markdown的语法,方便大家写出更好更漂亮的文档.重点是点击左上角的Github链接,有主题源码哦 一篇好的博客文档离不开一个优 ...
- Linux常用命令——关机重启命令
Linux常用命令--关机重启命令 Linux shutdown 语法:shutdown [选项] 时间 -c 取消前一个关机命令 -h 关机 -r 重启 示例:shutdown -r now 其它 ...
- 20165306 Exp1 PC平台逆向破解
20165306 Exp1 PC平台逆向破解 一.逆向及Bof基础实践说明 1. 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,fo ...
- 练习markdown语法
这是一级标题 这是二级标题 这是三级标题 -列表试验 -据说这样无编号 编号文档 编号文档 编号文档 插入链接测试 插入图片测试 引用测试> 一蓑烟雨任平生 粗体测试我是加粗的 斜体测试我是斜体 ...
- centos7 mysql数据库的安装与使用
一:数据库的安装 第一步 下载数据库到主机,, 第二步 通过xshell将数据库压缩包上传至centos7虚拟主机(#注意:服务器主机需下载上传工具lrzsz 命令:yun -y install ...
- DAY 24继承与组合
一.继承 继承就是子类与父类形成的一种关系,可以让子类能直接从父类中获取属性与方法 优点:减少了类与类之间的代码冗余 语法: class 父类: # 父类是多个有共同点的普通类抽离共有属性与方法形成的 ...