热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一个epoll的ET模式下的非阻塞的服务端小用例

后续知识会进行整理代码**echoserver*Time:2021-12-02*Author:LH*code:--utf8--*#ifdef____Win32#els

后续知识会进行整理

代码

/** echo server
* Time: 2021-12-02
* Author: LH
* code: --utf8--
*/
#ifdef ____Win32
#else
/* network io */
#include
#include
#include
#include
#include /* linux */
#include
#include
#include /* C */
#include
#include #define SERVERPORT 3119int main() {/** Create listening sockets*/int listenfd &#61; socket(AF_INET, SOCK_STREAM, 0);if (listenfd &#61;&#61; -1) {printf("socket error \n");return -1;}/* Set reuse IP and port number */int on &#61; 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));/* Set feizuse */int oldSocketFlag &#61; fcntl(listenfd, F_GETFL, 0);int newSocketFlag &#61; oldSocketFlag | O_NONBLOCK;if (fcntl(listenfd, F_SETFL, newSocketFlag) &#61;&#61; -1) {close(listenfd);printf("fcntl error \n");return -1;}/* Initializing the server */struct sockaddr_in bindaddr;bindaddr.sin_family &#61; AF_INET;bindaddr.sin_addr.s_addr &#61; htonl(INADDR_ANY);bindaddr.sin_port &#61; htons(SERVERPORT);if (bind(listenfd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) &#61;&#61; -1) {printf("bind error \n");close(listenfd);return -1;} /* Start Listening */if (listen(listenfd, SOMAXCONN) &#61;&#61; -1) {printf("listen error \n");close(listenfd);return -1; }/* create epoll */int epollfd &#61; epoll_create(1);if (epollfd &#61;&#61; -1) {printf("epoll_create error \n");close(listenfd);return -1; }/** struct epoll_event {* uint32_t events; fd event flags to be monitored* epoll_data_t data; User-defined data* }* typedef union epoll_data {* void *prt;* int fd;* uint32_t u32;* uint64_t u64;* }*/struct epoll_event listen_fd_event;listen_fd_event.data.fd &#61; listenfd;listen_fd_event.events &#61; EPOLLIN; /**The default is LT mode, * where a fixed number of bytes are charged at once according to the* service until they are collected *//**ET mode, when the readable event is triggered, the data on the * socket must be collected at once to feel, must be the village to * call the recv function until the recv error, the error code is EWOULDBLOCK*/// listen_fd_event.events |&#61; EPOLLET; /* start ET *//* Bind the listening socket to epollfd */if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &listen_fd_event) &#61;&#61; -1) {printf("epoll_ctl error \n");close(listenfd);return -1; }int n;while(1) {struct epoll_event epoll_events[1024];/* Returns the number of fd&#39;s with time */n &#61; epoll_wait(epollfd, epoll_events, 1024, 1000);if (n < 0) {/* Interrupted by signal */if (errno &#61;&#61; EINTR) continue;break;}else if (n &#61;&#61; 0) {/* Timeout, continue */continue;}for (size_t i &#61; 0; i < n; &#43;&#43; i) {/* Event Readable */if (epoll_events[i].events & EPOLLIN) {if (epoll_events[i].data.fd &#61;&#61; listenfd) {printf("a new client is connect! \n");/* Listening to sockets and receiving new connections */struct sockaddr_in clientaddr;socklen_t clientaddrlen &#61; sizeof(clientaddr);int clientfd &#61; accept(listenfd, (struct sockaddr *) &clientaddr, &clientaddrlen);if (clientfd !&#61; -1) {/* Set feizuse */int oldSocketFlag &#61; fcntl(clientfd, F_GETFL, 0);int newSocketFlag &#61; oldSocketFlag | O_NONBLOCK;if (fcntl(clientfd, F_SETFL, newSocketFlag) &#61;&#61; -1) {close(clientfd);printf("set client to nonblocking error \n");}else {/** struct epoll_event {* uint32_t events; fd event flags to be monitored* epoll_data_t data; User-defined data* }*/struct epoll_event client_fd_event;client_fd_event.data.fd &#61; clientfd;/* Listening to both read and write events */client_fd_event.events &#61; EPOLLIN | EPOLLOUT; client_fd_event.events |&#61; EPOLLET;/* Add to epollfd */if (epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &client_fd_event) !&#61; -1) {// printf("new client accepted, clientfd: %d \n", clientfd); }else {printf("add client fd to epollfd error \n");close(clientfd);}}}}else {printf("client fd: %d recv data \n", epoll_events[i].data.fd);char recvbuf[1024] &#61; { 0 };/* Receive 1 byte at a time */int m &#61; recv(epoll_events[i].data.fd, &recvbuf, 1024, 0);if (m &#61;&#61; 0) {/* The other end closes the connection and removes the clienfd from the epollfd */if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) !&#61; -1) {printf("client disconnected clientfd: %d \n", epoll_events[i].data.fd);}close(epoll_events[i].data.fd);}else if (m < 0) {/* error */if (errno !&#61; EWOULDBLOCK && errno !&#61; EINTR) {/* The other end closes the connection and removes the clienfd from the epollfd */if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) !&#61; -1) {printf("client disconnected clientfd: %d \n", epoll_events[i].data.fd);}close(epoll_events[i].data.fd);}}else {/* normal */printf("recv from client: %d,%s", epoll_events[i].data.fd, recvbuf);struct epoll_event client_fd_event;client_fd_event.data.fd &#61; epoll_events[i].data.fd;/* Register the writeable event to clientfd again *//**In ET mode, the writable event will not be triggered all the time,* he will only trigger once and register again after the trigger is * completed, and the writable event will continue to trigger only * when the writable event is monitored. LT is repeatedly triggered * by writable events. After a writable event is triggered, if it * is no longer needed, the registration of the writable event should* be removed immediately*/client_fd_event.events &#61; EPOLLIN | EPOLLOUT | EPOLLET;if (epoll_ctl(epollfd, EPOLL_CTL_MOD, epoll_events[i].data.fd, &client_fd_event) !&#61; -1) {// printf("epoll_ctl successfully, mode: EPOLL_CTL_MOD, clientfd: %d \n", epoll_events[i].data.fd);}else {printf("epoll_ctl failure, mode: EPOLL_CTL_MOD, clientfd: %d \n", epoll_events[i].data.fd);}}}}/* Listening to write events */else if (epoll_events[i].events & EPOLLOUT) {/* Handle only write events for client fd */if (epoll_events[i].data.fd !&#61; listenfd) {/* print result */// printf("EPOLLOUT Triggered, clientfd: %d \n", epoll_events[i].data.fd);}}else if (epoll_events[i].events & EPOLLERR) {// TODOprintf("epoll error! \n");}}} close(listenfd);return 0;
}
#endif

测试

> gcc -g -o epoll_server epoll_server.c
> ./epoll_server
a new client is connect!
client fd: 5 recv data
recv from client: 5,asdh
client fd: 5 recv data
recv from client: 5,awqr

> nc -v 127.0.0.1 3119
Connection to 127.0.0.1 3119 port [tcp/*] succeeded!
asdh
awqr


推荐阅读
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
author-avatar
曹月洪_867
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有