epoll函数

epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。

目前epell是linux大规模并发网络程序中的热门首选模型。

epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

可以使用cat命令查看一个进程可以打开的socket描述符上限。

    cat /proc/sys/fs/file-max

如有需要,可以通过修改配置文件的方式修改该上限值。

    sudo vi /etc/security/limits.conf在文件尾部写入以下配置,soft软限制,hard硬限制。如下图所示。* soft nofile 65536* hard nofile 100000

基础API

  1. 创建一个epoll句柄,参数size用来告诉内核监听的文件描述符的个数,跟内存大小有关。
        #include <sys/epoll.h>int epoll_create(int size)        size:监听数目
  2. 控制某个epoll监控的文件描述符上的事件:注册、修改、删除。
        #include <sys/epoll.h>int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)epfd:    为epoll_creat的句柄op:        表示动作,用3个宏来表示:EPOLL_CTL_ADD (注册新的fd到epfd),EPOLL_CTL_MOD (修改已经注册的fd的监听事件),EPOLL_CTL_DEL (从epfd删除一个fd);event:    告诉内核需要监听的事件struct epoll_event {__uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */};typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;} epoll_data_t;EPOLLIN :    表示对应的文件描述符可以读(包括对端SOCKET正常关闭)EPOLLOUT:    表示对应的文件描述符可以写EPOLLPRI:    表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)EPOLLERR:    表示对应的文件描述符发生错误EPOLLHUP:    表示对应的文件描述符被挂断;EPOLLET:     将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)而言的EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
  3. 等待所监控文件描述符上有事件的产生,类似于select()调用。
        #include <sys/epoll.h>int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)events:        用来存内核得到事件的集合,maxevents:    告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,timeout:    是超时时间-1:    阻塞0:    立即返回,非阻塞>0:    指定毫秒返回值:    成功返回有多少文件描述符就绪,时间到时返回0,出错返回-1

     

server

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
#include "wrap.h"#define MAXLINE 80
#define SERV_PORT 6666
#define OPEN_MAX 1024int main(int argc, char *argv[])
{int i, j, maxi, listenfd, connfd, sockfd;int nready, efd, res;ssize_t n;char buf[MAXLINE], str[INET_ADDRSTRLEN];socklen_t clilen;int client[OPEN_MAX];struct sockaddr_in cliaddr, servaddr;struct epoll_event tep, ep[OPEN_MAX];listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));Listen(listenfd, 20);for (i = 0; i < OPEN_MAX; i++)client[i] = -1;maxi = -1;efd = epoll_create(OPEN_MAX);if (efd == -1)perr_exit("epoll_create");tep.events = EPOLLIN; tep.data.fd = listenfd;res = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &tep);if (res == -1)perr_exit("epoll_ctl");while (1) {nready = epoll_wait(efd, ep, OPEN_MAX, -1); /* 阻塞监听 */if (nready == -1)perr_exit("epoll_wait");for (i = 0; i < nready; i++) {if (!(ep[i].events & EPOLLIN))continue;if (ep[i].data.fd == listenfd) {clilen = sizeof(cliaddr);connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));for (j = 0; j < OPEN_MAX; j++) {if (client[j] < 0) {client[j] = connfd; /* save descriptor */break;}}if (j == OPEN_MAX)perr_exit("too many clients");if (j > maxi)maxi = j;         /* max index in client[] array */tep.events = EPOLLIN; tep.data.fd = connfd;res = epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &tep);if (res == -1)perr_exit("epoll_ctl");} else {sockfd = ep[i].data.fd;n = Read(sockfd, buf, MAXLINE);if (n == 0) {for (j = 0; j <= maxi; j++) {if (client[j] == sockfd) {client[j] = -1;break;}}res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL);if (res == -1)perr_exit("epoll_ctl");Close(sockfd);printf("client[%d] closed connection\n", j);} else {for (j = 0; j < n; j++)buf[j] = toupper(buf[j]);Writen(sockfd, buf, n);}}}}close(listenfd);close(efd);return 0;
}

client

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"#define MAXLINE 80
#define SERV_PORT 6666int main(int argc, char *argv[])
{struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));while (fgets(buf, MAXLINE, stdin) != NULL) {Write(sockfd, buf, strlen(buf));n = Read(sockfd, buf, MAXLINE);if (n == 0)printf("the other side has been closed.\n");elseWrite(STDOUT_FILENO, buf, n);}Close(sockfd);return 0;
}

 

转载于:https://www.cnblogs.com/wanghao-boke/p/11425924.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

epoll事件模型

事件模型 EPOLL事件有两种模型&#xff1a; Edge Triggered (ET) 边缘触发只有数据到来才触发&#xff0c;不管缓存区中是否还有数据。 Level Triggered (LT) 水平触发只要有数据都会触发。 思考如下步骤&#xff1a; 假定我们已经把一个用来从管道中读取数据的文件描述符(RFD)…

epoll反应堆模型代码

libevent函数库核心思想 /*** epoll_loop.c ***/ #include<stdio.h> #include<sys/epoll.h> #include<sys/socket.h> #include<arpa/inet.h> #include<fcntl.h> #include<unistd.h> #include<errno.h> #include<string.h> #in…

UDP广播

广播是在局域网之间的一对多的通信方式&#xff0c;使用的udp协议 /*** client.c ***/ #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h>#define SERVER_PORT 8000 #define MAXLINE…

UDP组播

多播(组播) 组播组可以是永久的也可以是临时的。组播组地址中&#xff0c;有一部分由官方分配的&#xff0c;称为永久组播组。永久组播组保持不变的是它的ip地址&#xff0c;组中的成员构成可以发生变化。永久组播组中成员的数量都可以是任意的&#xff0c;甚至可以为零。那些没…

Python3数据结构

列表&#xff1a; Python列表是可变的&#xff0c;这是它区别于字符串数组和元组的最重要的特点。列表可以修改&#xff0c;而字符串和元组不能。 以下是Python中列表的描述方法&#xff1a; 方法 描述 list.append(x) 将元素添加到列表结尾 list.extend(L) 通过添加指定列…

sed、awk工具

ed sed意为流编辑器&#xff08;Stream Editor&#xff09;&#xff0c;在Shell脚本和Makefile中作为过滤器使用非常普遍&#xff0c;也就是把前一个程序的输出引入sed的输入&#xff0c;经过一系列编辑命令转换为另一种格式输出。sed和vi都源于早期UNIX的ed工具&#xff0c;所…

C语言正则表达式

POSIX规定了正则表达式的C语言库函数&#xff0c;详见regex(3)。我们已经学习了很多C语言库函数的用法&#xff0c;读者应该具备自己看懂man手册的能力了。本章介绍了正则表达式在grep、sed、awk中的用法&#xff0c;学习要能够举一反三&#xff0c;请读者根据regex(3)自己总结…

makefile通用版本

实际当中程序文件比较大&#xff0c;这时候对文件进行分类&#xff0c;分为头文件、源文件、目标文件、可执行文件。也就是说通常将文件按照文件类型放在不同的目录当中&#xff0c;这个时候的Makefile需要统一管理这些文件&#xff0c;将生产的目标文件放在目标目录下&#xf…

Python3OS文件/方法

Python3OS文件/方法 os模块提供了非常丰富的方法用来处理文件和目录。 方法 描述 os.access(path,mode) 检验权限模式 os.chdir(path) 改变当前工作目录 os.chflags(path,flags) 设置路径的标记为数字标记 os.chmod(path,mode) 更改权限 os.chown(path,uid,gid) 更改…

Python3文件

open()方法 Python open()方法永于打开一个文件&#xff0c;并返回文件对象&#xff0c;并对文件进行处理过程中都需要用到这个方法&#xff0c;如果该文件无法被打开&#xff0c;则抛出OSError 注意&#xff1a;使用open()方法一定要保证关闭文件对象&#xff0c;即调用close(…

Python3输入输出

Python两种输出值的方式&#xff0c;表达式语句和print()函数。 第三种方式是使用文件对象的write()方法&#xff0c;标准输出文件可以用sys.stdout的引用。 如果你希望输出的形式更加多样&#xff0c;可以使用str.fomat()函数来格式化输出值。 如果你希望将输出的值转化成字符…

动态库加载顺序

1.编译目标代码时指定的动态库搜索路径&#xff1b; 2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径&#xff1b; 3.配置文件/etc/ld.so.conf中指定的动态库搜索路径&#xff1b; 4.默认的动态库搜索路径/lib&#xff1b; 5.默认的动态库搜索路径/usr/lib。 转载于:https://ww…

Python3正则表达式

正则表达式是一个特殊的字符序列&#xff0c;他能帮助你方便的检查一个字符串是否与某种模式匹配。re.match函数 re.match尝试从字符串的起始位置匹配一个模式&#xff0c;如果不是起始位置匹配成功的话&#xff0c;match()就返回一个none。 函数语法&#xff1a; re.match(pat…

C/C++输入

fgets(str,n,stdin) 从键盘输入一行&#xff0c;替代gets()。读取到n-1字节时或换行符时终止&#xff0c;如果是文件的话&#xff0c;读到文件结尾也会停止 getline(cin,str) str的类型必须是string类&#xff0c;它是C特定的字符串类&#xff0c;区别于C的char *数据类型。 ci…

strlen和sizeof的区别

C语言中没有字符串&#xff0c;用的是字符数组来模拟字符串。 C风格的字符串时字符数组然后在末尾加0表示结尾。 在C语言中有strlen和sizeof两个函数求字符数组的长度函数&#xff0c;他们俩的区别就是是否把最后的结束标志也加上去。 strlen是不加的&#xff0c;他表示字符串的…

shell编程练习题

求2个数之和计算1-100的和将一目录下所有的文件的扩展名改为bak编译当前目录下的所有.c文件&#xff1a;打印root可以使用可执行文件数&#xff0c;处理结果: roots bins: 2306打印当前sshd的端口和进程id&#xff0c;处理结果: sshd Port&&pid: 22 5412输出本机创建20…

shell编程题(一)

求2个数之和 #!/bin/bashfunction add {if(( $# < 2 )); thenecho "The arg int correct"elsesum$(($1$2))echo $sumfi }add 1 add 1 2 运行结果&#xff1a; exbotubuntu:~/shareWin/linux/shell$ ./sum.sh 1 2The arg int correct3 $#&#xff1a;相当于C语言…

vimset

vim ~./vimrc set nocompatible "去掉有关vi一致性模式&#xff0c;避免以前版本的bug和局限 set nu! "显示行号 set guifontLuxi/ Mono/ 9 " 设置字体&#xff0c;字体名称和字号 filetype on …

shell编程题(二)

计算1-100之和 #!/bin/bashsum0 for i in seq 1 100;do #符号不是单引号 是 1左边的符号sum$[$i $sum ] done echo $sum #!/bin/bashi0 n1              #定义循环变量 while [ $n -lt 101 ];do  #循环变量小于101 i$(( $i $n))        #累加 n$(( …

vim命令大全

1. vim模式 正常模式&#xff08;按Esc或Ctrl[进入&#xff09; 左下角显示文件名或为空 插入模式&#xff08;按i进入&#xff09; 左下角显示--INSERT-- 可视模式&#xff08;按v进入&#xff09; 左下角显示--VISUAL-- 替换模式&#xff08;按r或R开始&#xff09; 左下角显…