当前位置:网站首页>epoll 的 ET,LT工作模式———实例程序
epoll 的 ET,LT工作模式———实例程序
2022-04-23 14:36:00 【m0_51551385】
下面是一个服务器程序,可通过LT
或 ET
两种模式接收客户端发来的数据,并打印到标准输出。
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<assert.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<errno.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<sys/epoll.h>
#include<pthread.h>
#define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 10
/* 将文件描述符设置成非阻塞的 */
int setnonblocking(int fd)
{
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
/* 将文件描述符 fd 上的 EPOLLIN 注册到 epollfd 指示的 epoll 内核事件表中,参数 enable_et 指定是否对 fd 启用 ET 模式 */
void addfd(int epollfd, int fd, bool enable_et)
{
epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN;
if (enable_et)
{
event.events |= EPOLLET;
}
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblocking(fd);
}
/* LT 模式工作流程 */
void lt(epoll_event* events, int number, int epollfd, int listenfd)
{
char buf[BUFFER_SIZE];
for (int i = 0; i < number; i++)
{
int sockfd = events[i].data.fd;
if (sockfd == listenfd)
{
struct sockaddr_in client_address;
socklen_t client_addrlength = sizeof(client_address);
int connfd = accept(listenfd, (struct sockaddr*)&client_address, &client_addrlength);
addfd(epollfd, connfd, false); /* 把 connfd 添加到内核事件表中,并禁用 ET 模式 */
}
else if (events[i].events & EPOLLIN)
{
/* 只要 socket 读缓存中还有未读出的数据,这段代码就被触发 */
printf("EPOLLIN event trigger once\n");
memset(buf, '\0', BUFFER_SIZE);
int ret = recv(sockfd, buf, BUFFER_SIZE - 1, 0);
if (ret <= 0)
{
close(sockfd);
continue;
}
printf("get %d bytes of content: %s\n", ret, buf);
}
else
{
printf("something else happened \n");
}
}
}
/* ET 模式的工作流程 */
void et(epoll_event* events, int number, int epollfd, int listenfd)
{
char buf[BUFFER_SIZE];
for (int i = 0; i < number; i++)
{
int sockfd = events[i].data.fd;
if (sockfd == listenfd)
{
struct sockaddr_in client_address;
socklen_t client_addrlength = sizeof(client_address);
int connfd = accept(sockfd, (struct sockaddr*)&client_address, &client_addrlength);
addfd(epollfd, connfd, true); /* 把 connfd 添加到内核事件表中,并开启 ET 模式 */
}
else if (events[i].events & EPOLLIN)
{
/* 这段代码不会被重复触发,所以必须循环读取数据,以确保把 socket 读缓存中的所有数据读出 */
printf("EPOLLIN event trigger once\n");
while (1)
{
memset(buf, '\0', BUFFER_SIZE);
int ret = recv(sockfd, buf, BUFFER_SIZE - 1, 0);
if (ret < 0)
{
/* 对于非阻塞IO,下面的条件成立表示数据已全部读取完毕。此后,epoll就能再次触发 sockfd 上的 EPOLLIN 事件,进行下一次读操作*/
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
printf("raed later\n");
break;
}
close(sockfd);
break;
}
else if (ret == 0) /* 返回0,表示对方已经关闭连接了 */
{
close(sockfd);
}
else
{
printf("get %d bytes of content: %s\n", ret, buf);
}
}
}
else
{
printf("something else happened \n");
}
}
}
int main(int argc, char* argv[])
{
if (argc <= 2)
{
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET, ip, &address.sin_addr);
int listenfd = socket(PF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);
ret = listen(listenfd, 5);
assert(ret != -1);
epoll_event events[MAX_EVENT_NUMBER];
int epollfd = epoll_create(10);
assert(epollfd != -1);
addfd(epollfd, listenfd, true);
while (1)
{
int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
if (ret < 0)
{
printf("epoll filure\n");
break;
}
// lt(events, ret, epollfd, listenfd);
et(events, ret, epollfd, listenfd);
}
close(listenfd);
return 0;
}
版权声明
本文为[m0_51551385]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_51551385/article/details/124358775
边栏推荐
- The initial C language framework is suitable for review and preliminary understanding
- 初识STL
- Basic regular expression
- 51单片机+LCD12864液晶显示的俄罗斯方块游戏,Proteus仿真、AD原理图、代码、论文等
- On the insecurity of using scanf in VS
- SVN详细使用教程
- async void 导致程序崩溃
- C语言知识点精细详解——初识C语言【1】——你不能不知的VS2022调试技巧及代码实操【1】
- 【工厂模式详解】工厂方法模式
- vscode中文插件不生效问题解决
猜你喜欢
基于TLC5615的多路可调数控直流稳压电源,51单片机,含Proteus仿真和C代码等
flannel 原理 之 TUN模式
Interviewer: let's talk about the process of class loading and the mechanism of class loading (parental delegation mechanism)
【工厂模式详解】工厂方法模式
电子秤称重系统设计,HX711压力传感器,51单片机(Proteus仿真、C程序、原理图、论文等全套资料)
ASEMI整流模块MDQ100-16在智能开关电源中的作用
AT89C52单片机的频率计(1HZ~20MHZ)设计,LCD1602显示,含仿真、原理图、PCB与代码等
51 MCU flowers, farmland automatic irrigation system development, proteus simulation, schematic diagram and C code
流程控制之分支语句
本以为能躺着进华为,结果陆续收到京东/滴滴/爱奇艺offer的我迷茫了
随机推荐
Matrix exchange row and column
[servlet] detailed explanation of servlet (use + principle)
面试官:说一下类加载的过程以及类加载的机制(双亲委派机制)
外包幹了四年,廢了...
直流可调稳压电源的Proteus仿真设计(附仿真+论文等资料)
Solve the problem of SSH configuration file optimization and slow connection
拼接hql时,新增字段没有出现在构造方法中
51单片机的花卉、农田自动浇水灌溉系统开发,Proteus仿真,原理图和C代码
【JZ46 把数字翻译成字符串】
Qt实战:云曦日历篇
pnpm安装使用
Ali developed three sides, and the interviewer's set of combined punches made me confused on the spot
如何5分钟上手使用OCR
阿里研发三面,面试官一套组合拳让我当场懵逼
Want to be an architect? Tamping the foundation is the most important
Golang 对分片 append 是否会共享数据
Redis源码分析之HSET流程与ziplist
全连接层的作用是什么?
8.5 循环神经网络简洁实现
51 MCU flowers, farmland automatic irrigation system development, proteus simulation, schematic diagram and C code