多路io复用pool [补档-2023-07-19]
多路IO- poll
3.1简介
poll的机制与select类似,他们都是让内核在以线性的方法对文件描述符集合进行检测,根据描述符的状态进行具体的操作。并且poll和select在检测描述符集合时,会在检测的过程中频繁的进行用户区和内核区的拷贝,随着文件描述符集合中的数量增大,开销也随之增大,效率也会变低。
select检测的文件描述符数量最大为1024个,而poll则没有数量限制。并且select可以跨平台,而poll只能在Linux系统中使用。
3.2 poll函数
头文件:#include <poll.h>
函数原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
函数参数:
fds:是一个struct pollfd类型的结构体数组,里面存储了要检测的文件描述符的信息,稍后详述。
nfds:数组实际有效内容的个数。
timeout:
-1 一直阻塞,直到检测的集合中有就绪的文件描述符(发送事件的),然后解除阻塞。
0 不阻塞,不管检测集合中有没有已经就绪的文件描述符,函数会马上返回。
大于0 阻塞指定的毫秒数之后,然后解除阻塞。
函数返回值:
大于0的整数:表示检测的集合中已就绪的文件描述符总个数。
-1:表示调用失败。
结构体struct pollfd的成员(三个):
int fd:委托内核检测的文件描述符。
short events:委托内核要检测文件描述符的事件。
short revents:文件描述符实际发送的事件,这是一个传出参数。
结构体struct pollfd事件表:
| 事件 | 常值 | 作为events的值 | 作为revents的值 | 说明 |
|---|---|---|---|---|
| 读事件 | POLLIN | 是 | 是 | 普通或优先带数据可读 |
| POLLRDNORM | 是 | 是 | 普通数据可读 | |
| POLLRDBAND | 是 | 是 | 优先级带数据可读 | |
| POLLPRI | 是 | 是 | 高优先级带数据可读 | |
| 写事件 | POLLOUT | 是 | 是 | 普通或优先带数据可写 |
| POLLWRNORM | 是 | 是 | 普通数据可写 | |
| POLLWRBAND | 是 | 是 | 优先级带数据可写 | |
| 错误事件 | POLLERR | 是 | 发生错误 | |
| POLLHUP | 是 | 发送挂起 | ||
| POLLNVAL | 是 | 描述不是打开的文件 |
3.3 使用poll实现高并发的步骤:
第一步:通过socket函数创建一个监听描述符。
第二步:通过bind函数将监听描述符和服务端本地地址进行绑定。
第三步:通过listen函数将监听文件描述符切换至监听状态。
第四步:自定义一个文件描述符集和结构体,然后对其初始化,然后准备一个变量用于记录最大描述符的值。
第五步:将监听文件描述符放入自定义文件描述集合下标为0的地方(不这样做的话集合为空,poll的第三参数是-1则会一直阻塞,如果是其他数则还是不行),然后进入无限循环
使用poll函数检测刚才自定义的文件描述符集合,如果集合中的某个描述符有信号了(读,写,错误等),那么则根据poll的第三参数来判断是否阻塞。(因为集合第0个位置是监听符,所以如果监听符有动静代表有客户端连接服务端了)
然后通过对监听描述符的读缓冲区进行判断,因为如果有客户端连接服务端,那么监听描述符的读缓存区就是这个客户端的信息,然后通过accept和监听文件描述符与刚才的客户端产生连接,返回一个与客户端产生连接的描述符,然后再拿这个与客户端建立连接的文件描述符存入自定义文件描述符集合供poll进行检测,加入之后记得跳出循环。
之后我们判断现在已建立链接的文件描述符是否是最大的,如果是则记录一下。
然后我们可以使用循环遍历的方法来遍历整个自定义文件描述符集合,来看看那个文件描述符是已建立链接的状态,然后通过使用这个文件描述符与对应的客户端进行数据传输,回应和处理客户端的各种请求等等。当回应完毕,处理完毕之后又或者客户端没有请求了,那么记得关闭这个与客户端建立连接的文件描述符,然后将这个文件描述符所在的自定义文件描述符集合中的位置置空,留给其他人使用。
第六步:可以不断重复第五步,如果所有的事情都做完了,那么可以关闭监听文件描述符。
3.4 使用poll实现高并发的服务端代码:
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <poll.h>
int main()
{
int i;
//1.创建套接字,使用ipv4和tcp
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd == -1) {
printf("创建监听套接字失败!\n");
exit(0);
}
//2.绑定套接字
struct sockaddr_in serv;
serv.sin_family = AF_INET;
serv.sin_port = htons(10066);
serv.sin_addr.s_addr = INADDR_ANY;
int rent = bind(sfd, (struct sockaddr*)&serv, sizeof(serv));
if (rent == -1) {
printf("绑定套接字失败!\n");
exit(0);
}
//3.监听
rent = listen(sfd, 128);
if (rent == -1) {
printf("监听失败!\n");
exit(0);
}
//4.创建和初始化自定义文件描述符集合
struct pollfd fds[1024];
for (i = 0; i < 1024; i++) {
//初始化,-1代表这个位置为空,可用
fds[i].fd = -1;
fds[i].events = POLLIN;//设定事件
}
fds[0].fd = sfd;//自定义文件描述符集合第一个位置存放监听文件描述符
int maxfd = 0;//用来记录最大的文件描述符
//5.使用循环来等待链接。
while (1) {
//委托内核检测
rent = poll(fds, maxfd + 1, -1);
if (rent == -1) {
printf("失败!\n");
exit(0);
}
//代码执行到这里了代表有客户端的连接请求了
//因为集合的第一个位置是监听文件描述符,监听文件描述符有动静了
//代表有连接
if (fds[0].revents & POLLIN) {
//接收连接请求
struct sockaddr_in sockcli;
int len = sizeof(sockcli);
int connfd = accept(sfd, (struct sockaddr*)&sockcli, &len);
//将已建立连接的描述符交给内核来检测读缓冲区
for (i = 1; i < 1024; i++) {
if (fds[i].fd == -1) {
fds[i].fd = connfd;//将已连接的描述符加入检测
break;
}
}
//记录最大的值
maxfd = i > maxfd ? i : maxfd;
}
//如果有客户端发送数据
int j;
for (j = 1; j <= maxfd; j++) {
if (fds[i].revents & POLLIN) {
char buf[100];
//读数据
int ret = read(fds[i].fd, buf, sizeof(buf));
if (ret == -1) {
printf("读取来自数据失败!\n");
exit(0);
}
else if (ret == 0) {
printf("对方已经关闭了连接!\n");
//关闭连接之后记得关闭对应的描述符,然后将自定义的集合中相应的位置值为-1
close(fds[i].fd);
fds[i].fd = -1;
}
else {
printf("来自客户端:%s\n",buf);
//回应客户端
write(fds[i].fd, buf, sizeof(buf));
}
}
}
}
close(sfd);
return 0;
}
多路io复用pool [补档-2023-07-19]的更多相关文章
- Redis03——Redis之单线程+多路IO复用技术
Redis 是单线程+多路IO复用技术 多路复用:使用一个线程来检查多个文件描述符的就绪状态 如果有一个文件描述符就绪,则返回 否则阻塞直到超时 得到就绪状态后进行真正的操作可以在同一个线程里执行,也 ...
- 多路IO复用模型--select, poll, epoll
select 1.select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数 2.解决1024以下客户端时使用se ...
- Linux企业级项目实践之网络爬虫(27)——多路IO复用
与多线程和多进程相比,I/O多路复用的最大优势是系统开销小,系统不需要建立新的进程或者线程,也不必维护这些线程和进程. 主要应用: (1)客户程序需要同时处理交互式的输入和服务器之间的网络连接 (2) ...
- 协程与多路io复用epool关系
linux上其实底层都基于libevent.so模块实现的,所以本质一样 gevent更关注于io和其它 epool只是遇到io就切换,而gevent其它等待也切换
- python3.x 多路IO复用补充asyncio
asyncio模块是python之父写的模块,按说应该是靠谱的,python3.6版本定义为稳定版本. 说明书:https://docs.python.org/3/library/asyncio.ht ...
- 基于select类型多路IO复用,实现简单socket并发
还有很多缺限,如客户断开无限重复 以下转至老师博客: server: #!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = " ...
- Reactor模式,或者叫反应器模式 - 为什么用多路io复用提供吞吐量
Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤,或 ...
- 20190925-03Redis端口号的由来及单线程加多路IO复用 000 024
- 应用层协议实现系列(一)——HTTPserver之仿nginx多进程和多路IO的实现
近期在尝试自己写一个Httpserver,在粗略研究了nginx的代码之后,决定仿照nginx中的部分设计自己实现一个高并发的HTTPserver,在这里分享给大家. 眼下使用的较多的Httpserv ...
- IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别参考
参考https://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral IO复用,AI ...
随机推荐
- 什么?你居然没有鸭鸭邮箱?@duck.com邮箱注册与使用
@duck.com 是由专注于隐私的搜索引擎DuckDuckGo提供的面向所有人的匿名邮箱. 注册者可以设置一个自定义前缀,比如 one@duck.com,接着设置接收邮箱(如pete@gmail.c ...
- C++右值引用与转移语义简要介绍
在 C++11 之前,值类型变量的传递会导致把它完整的拷贝一份 比如说把一个 vector 作为函数返回值赋值给某个局部变量,他就会调用 vector 的拷贝构造函数创建一个完整的副本,把这个副本作为 ...
- SpringBoot 项目实战 | 瑞吉外卖 Day02
该系列将记录一份完整的实战项目的完成过程,该篇属于第二天 案例来自B站黑马程序员Java项目实战<瑞吉外卖>,请结合课程资料阅读以下内容 该篇我们将完成以下内容: 完善登陆系统 新增员工 ...
- modint 板子
自动对 int 取模 // modint template<int MOD> struct Fp { ll val; constexpr Fp(ll v = 0) noexcept : v ...
- Round A 2021 - Kick Start 2021
比赛链接:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140 K-Goodness String (5 ...
- 【体验有奖】使用 Serverless 1 步搭建照片平台!
实验介绍 当前,Serverless 技术已经被广泛应用,Serverless = FaaS + BssS 的概念已经深入人心.本场景由函数计算和 RDS MySQL Serverless 联合打造, ...
- 1、springboot工程新建(单模块)
系列导航 springBoot项目打jar包 1.springboot工程新建(单模块) 2.springboot创建多模块工程 3.springboot连接数据库 4.SpringBoot连接数据库 ...
- 机器学习-无监督机器学习-SVD奇异值分解-24
[POC] 1. 奇异值分解的本质 特征值分解只能够对于方阵提取重要特征, Ax=λx λ为特征值 x为对应的特征向量 奇异值分解可以对于任意矩阵: 注意看中间的矩阵是一个对角矩阵,颜色越深越起作用- ...
- nginx 工作原理及特点
本文为博主原创,未经允许不得转载: nginx 简介:是一个高性能 HTTP 和 反向代理 服务器. Nginx 特点是占有内存少,并发能力强,事实上 Nginx 的并发能力确实在同类型的网页服务器中 ...
- [转帖]Linux命令(64)——strings命令
https://cloud.tencent.com/developer/article/1414999 1.命令简介 strings命令是二进制工具集GNU Binutils的一员,用于打印文件中可打 ...