当前位置: 首页 > wzjs >正文

数字化展厅建设方案百度seo还有前景吗

数字化展厅建设方案,百度seo还有前景吗,微网站 百度地图,手机做网站的📝个人主页🌹:Eternity._ ⏩收录专栏⏪:Linux “ 登神长阶 ” 🌹🌹期待您的关注 🌹🌹 ❀ Linux高级IO 多路转接:pollpoll函数接口poll优缺点 多路转接:epolle…

📝个人主页🌹:Eternity._
⏩收录专栏⏪:Linux “ 登神长阶 ”
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀ Linux高级IO

  • 多路转接:poll
    • poll函数接口
    • poll优缺点
  • 多路转接:epoll
    • epoll的相关系统调用
    • epoll工作原理
    • epoll的优点
    • epoll工作方式
    • 理解ET模式和非阻塞文件描述符
  • 总结

前言:在现代的Linux网络编程中,高效地管理多个并发连接是服务器性能优化的核心挑战之一。为了应对这一挑战,Linux操作系统提供了多种I/O多路复用技术,其中poll和epoll作为两种重要的机制,在提升系统资源利用率和处理效率方面发挥着关键作用。

poll 作为早期的一种多路转接方案,解决了select函数中文件描述符数量有限和每次调用都需要重新设置的问题。然而,随着网络技术的发展和服务器负载的不断增加,poll在某些场景下也显露出了性能瓶颈。此时,epoll作为Linux 2.6内核引入的一种更为高效的I/O多路复用机制,凭借其出色的性能和灵活性,逐渐成为高性能服务器应用的首选。

epoll 不仅克服了poll和select的诸多限制,如文件描述符数量的限制和每次调用时的效率问题,还引入了边缘触发(Edge Triggered)的工作模式,进一步提高了应用程序的响应速度和系统资源的利用率。通过只通知那些真正发生了I/O事件的文件描述符,epoll显著减少了不必要的上下文切换和CPU资源的浪费。

让我们携手踏上这段探索之旅,一同揭开Linux高级I/O的神秘面纱。

多路转接:poll


在Linux系统中,多路转接技术是一种重要的I/O处理机制,它允许单个线程同时监控多个文件描述符(例如套接字)上的事件,从而有效地管理多个并发连接。由于poll与之前所提到过的select有许多相似之处,所以我们对于poll将只进行简单的介绍

poll函数接口


#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);// pollfd结构
struct pollfd 
{int fd; /* file descriptor */short events; /* requested events */short revents; /* returned events */
};

参数说明:

  • fds是一个poll函数监听的结构列表,每一个元素中,包含了三部分内容:文件描述符、监听的事件集合、 返回的事件集合
  • nfds表示fds数组的长度
  • timeout表示poll函数的超时时间,单位是毫秒(ms)

events和revents的取值:

在这里插入图片描述
返回结果:

  • 返回值小于0,表示出错
  • 返回值等于0,表示poll函数等待超时
  • 返回值大于0,表示poll由于监听的文件描述符就绪而返回

注意:poll中socket就绪条件和select是一样的

poll_server.hpp:

#pragma once#include <iostream>
#include <string>
#include <poll.h>
#include "Log.hpp"
#include "Socket.hpp"using namespace Net_Work;const static int gdefaultport = 8888;
const static int gbacklog = 8;
const int gnum = 1024;class PollServer
{
private:void HandlerEvent(){for (int i = 0; i < _num; i++){if (_rfds[i].fd == -1)continue;// 合法的fd// 读事件分两种,一类是新链接的到来,一类是新数据的到来int fd = _rfds[i].fd;short revent = _rfds[i].revents;if (revent & POLLIN){// 读事件就绪 -> 新链接的到来if (fd == _listensock->GetSocket()){lg.LogMessage(Info, "get a new link\n");std::string clientip;uint16_t clientport;// 这里不会阻塞,因为select已经检测到listensock就绪了int sock = _listensock->AcceptConnection(&clientip, &clientport);if (!sock){lg.LogMessage(Error, "accept error\n");continue;}lg.LogMessage(Info, "get a client, client info is# %s:%d, fd:%d\n", clientip.c_str(), clientport, sock);// 获取成功了,但是我们不能直接读写,底层的数据不确定是否就绪// 新链接fd到来时,要把新链接fd交给select托管 --- 只需要添加到数组_rfds_array中即可int pos = 0;for (; pos < _num; pos++){if (_rfds[pos].fd == -1){_rfds[pos].fd = sock;break;}}if (pos == _num){// 1. 扩容// 2. 关闭close(sock);lg.LogMessage(Warning, "server is full ... !\n");}}// 新数据的到来else{char buffer[1024];ssize_t n = recv(fd, buffer, sizeof(buffer-1), 0);if(n){buffer[n] = 0;lg.LogMessage(Info, "client say# %s\n", buffer);std::string message = "你好,";message += buffer;send(fd, message.c_str(), message.size(), 0);}else{lg.LogMessage(Warning, "client quit, maybe close or error, close fd: %d\n", fd);close(fd);// 取消对poll的关心_rfds[i].fd = -1;_rfds[i].events = 0;_rfds[i].revents = 0;}}}}}public:PollServer(int port = gdefaultport): _port(port), _listensock(new TcpSocket()),_isrunning(false),_num(gnum){}void InitServer(){_listensock->BuildListenSocketMethod(_port, gbacklog);_rfds = new struct pollfd[_num];for(int i = 0; i < _num; i++){_rfds[i].fd = -1;_rfds[i].events = 0;_rfds[i].revents = 0;} // 刚开始时,只有一个文件描述符listensock_rfds[0].fd = _listensock->GetSocket();_rfds[0].events |= POLLIN;}void Loop(){_isrunning = true;while (_isrunning){// 定义时间int timeout = 1000;// rfds本质是一个输入输出型参数,rfds是在select调用返回的时候,不断被修改,所以每次都要重置// PrintDebug();int n = poll(_rfds, _num, timeout);switch (n){case 0:lg.LogMessage(Info, "poll timeout ... \n");break;case -1:lg.LogMessage(Error, "poll error !!! \n");default:lg.LogMessage(Info, "poll success, begin event handler\n");HandlerEvent();break;}}_isrunning = false;}void stop(){_isrunning = false;}~PollServer(){delete []_rfds;}private:std::unique_ptr<Socket> _listensock;int _port;bool _isrunning;struct pollfd *_rfds;int _num;
};

poll代码完整示例

poll优缺点


poll的优点

  • 可以等待多个fd,效率高
  • 输入,输出参数分离,events和revents,不用在频繁的对poll参数进行重置
  • poll关心的fd没有上限

poll的缺点:

  • 用户到内核空间,要有数据拷贝 — 必要开销
  • poll应用层,要遍历。在内核层面,遍历检测,关心的fd是否有对应的事件就绪

poll作为Linux中的多路转接技术之一,在处理多个并发连接时具有一定的优势。然而,随着网络技术的发展和服务器负载的不断增加,poll在某些场景下可能无法满足高性能的需求。因此,在实际应用中需要根据具体场景选择合适的I/O多路复用技术。

多路转接:epoll


epoll是Linux下多路复用I/O接口select/poll的增强版本,旨在提高程序在大量并发连接中只有少量活跃情况下的系统CPU利用率。按照man手册的说法:是为处理大批量句柄而作了改进的poll,但其实epoll和poll还是有很大差别的

epoll的相关系统调用


epoll 有3个相关的系统调用:

  • epoll_create
  • epoll_ctl
  • epoll_wait

epoll_create:

int epoll_create(int size);

epoll_create的功能是创建一个epoll的句柄,自从linux2.6.8之后,size参数是被忽略的,注意用完之后, 必须调用close()关闭

epoll_ctl:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epoll的事件注册函数,它不同于select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型

  • 第一个参数是epoll_create()的返回值(epoll的句柄)
  • 第二个参数表示动作,用三个宏来表示
  • 第三个参数是需要监听的fd
  • 第四个参数是告诉内核需要监听什么事

第二个参数的取值:

  • EPOLL_CTL_ADD :注册新的fd到epfd中
  • EPOLL_CTL_MOD :修改已经注册的fd的监听事件
  • EPOLL_CTL_DEL :从epfd中删除一个fd

struct epoll_event结构如下:

在这里插入图片描述
events可以是以下几个宏的集合:

含义
EPOLLIN表示对应的文件描述符可以读 (包括对端SOCKET正常关闭)
EPOLLOUT表示对应的文件描述符可以写
EPOLLPRI表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来);
EPOLLERR表示对应的文件描述符发生错误
EPOLLHUP表示对应的文件描述符被挂断
EPOLLET将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的
EPOLLONESHOT只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

epoll_wait:

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

epoll_wait的功能是收集在epoll监控的事件中已经发送的事件

  • 参数events是分配好的epoll_event结构体数组
  • epoll将会把发生的事件赋值到events数组中 (events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存)
  • maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size
  • 参数timeout是超时时间 (毫秒,0会立即返回,-1是永久阻塞)
  • 如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时, 返回小于0表示函数失败

epoll工作原理


在这里插入图片描述

当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关

关于epoll的使用其实就只有三步:

  • 调用epoll_create创建一个epoll句柄
  • 调用epoll_ctl,将要监控的文件描述符进行注册
  • 调用epoll_wait,等待文件描述符就绪

epoll完整代码示例

epoll的优点


  • 接口使用方便: 虽然拆分成了三个函数,反而使用起来更方便高效,不需要每次循环都设置关注的文件描述符,同时做到了输入输出参数分离开
  • 数据拷贝轻量: 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中,这个操作并不频繁(select/poll都是每次循环都要进行拷贝)
  • 事件回调机制: 避免使用遍历,而是使用回调函数的方式,将就绪的文件描述符结构加入到就绪队列中,epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪,这个操作时间复杂度O(1),即使文件描述符数目很多,效率也不会受到影响
  • 没有数量限制: 文件描述符数目无上限

注意:有人说,epoll中使用了内存映射机制,这种说法是不准确的,我们定义的struct epoll_event是我们在用户空间中分配好的内存,势必还是需要将内核的数据拷贝到这个用户空间的内存中的

我们来看看内存映射机制是什么:

  • 内存映射机制: 内核直接将就绪队列通过mmap的方式映射到用户态,避免了拷贝内存这样的额外性能开销

epoll工作方式


我们来举个生活中例子:你在网上网购了一袋零食,快递员送到你家楼下的时候,这时候就有可能出现两种方式:

  1. 新来的快递员小王,在楼下叫你下楼取快递,你可能觉得他好欺负,就没有下楼,小王就一直在楼下喊你,一遍,两遍,三遍 (水平触发)
  2. 后面换了快递员小赵来给你送快递,在楼下叫了你一次,你没下来,他也没惯着你,就离开去送下一个快递了(边缘触发)

epoll有2种工作方式:

  • 水平触发(Level Triggered简称LT)
  • 边缘触发(Edge Triggered简称ET)

水平触发Level Triggered 工作模式:

epoll默认状态下就是LT工作模式,当epoll检测到socket上事件就绪的时候,可以不立刻进行处理或者只处理一部分

  • 当我们写入2K数据时,第一次调用epoll_wait可能只读了1K数据,缓冲区中还剩1K数据, 在第二次调用 epoll_wait 时, epoll_wait仍然会立刻返回并通知socket读事件就绪.
  • 直到缓冲区上所有的数据都被处理完, epoll_wait 才不会立刻返回
  • 支持阻塞读写和非阻塞读写

边缘触发Edge Triggered工作模式:

将socket添加到epoll描述符的时候使用EPOLLET标志,epoll进入ET工作模式

  • 当epoll检测到socket上事件就绪时,必须立刻处理.=
  • 如上面的例子,虽然只读了1K的数据,缓冲区还剩1K的数据,在第二次调用 epoll_wait 的时候,epoll_wait 不会再返回了
  • ET模式下,文件描述符上的事件就绪后,只有一次处理机会
  • ET的性能比LT性能更高( epoll_wait 返回的次数少了很多),Nginx默认采用ET模式使用epoll
  • 只支持非阻塞的读写

select和poll其实也是工作在LT模式下,epoll既可以支持LT,也可以支持ET

对比LT和ET:

  • LT是 epoll 的默认行为. 使用 ET 能够减少 epoll 触发的次数. 但是代价就是强逼着程序猿一次响应就绪过程中就把
    所有的数据都处理完.
  • 相当于一个文件描述符就绪之后, 不会反复被提示就绪, 看起来就比 LT 更高效一些. 但是在 LT 情况下如果也能做到
    每次就绪的文件描述符都立刻处理, 不让这个就绪被重复提示的话, 其实性能也是一样的.
  • 另一方面, ET 的代码复杂程度更高了

理解ET模式和非阻塞文件描述符


使用 ET 模式的 epoll, 需要将文件描述设置为非阻塞

  • 假设这样的场景:服务器接受到一个10k的请求,会向客户端返回一个应答数据,如果客户端收不到应答,不会发送第二个10k请求

在这里插入图片描述

  • 如果服务端写的代码是阻塞式的read, 并且一次只 read 1k 数据的话,剩下的9k数据就会待在缓冲区中

在这里插入图片描述

  • 此时由于 epoll 是ET模式,并不会认为文件描述符读就绪,epoll_wait 就不会再次返回,剩下的 9k 数据会一直在缓冲区中,直到下一次客户端再给服务器写数据,epoll_wait 才能返回

到这里初见端倪:

  • 服务器只读到1k个数据,要10k读完才会给客户端返回响应数据
  • 客户端要读到服务器的响应
  • 客户端发送了下一个请求,epoll_wait 才会返回, 才能去读缓冲区中剩余的数据

在这里插入图片描述
为了解决上述问题(阻塞read不一定能一下把完整的请求读完),于是就可以使用非阻塞轮训的方式来读缓冲区,保证一定能把完整的请求都读出来,如果是LT没这个问题,只要缓冲区中的数据没读完,就能够让 epoll_wait 返回文件描述符读就绪

总结


随着我们对Linux中的多路转接机制,特别是poll和epoll的深入探讨,这段学习之旅已接近尾声。从最初的概念理解,到深入的工作原理分析,再到实际应用中的性能考量,我们一步步揭开了poll和epoll的神秘面纱。

epoll以其高效的处理能力和扩展性成为了高性能网络编程的首选。epoll通过减少不必要的系统调用和内存拷贝,以及利用内核级的回调机制,显著提高了I/O事件的处理效率。特别是在处理大量并发连接时,epoll的性能优势尤为明显。

每一次的学习都是一次自我提升的机会,每一次的实践都是向更高目标迈进的步伐。愿我们在技术的道路上越走越远,共创更加辉煌的未来!

在这	里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

http://www.dtcms.com/wzjs/103384.html

相关文章:

  • 山西建设行政主管部门官方网站怎么建免费网站
  • 电子商务网站建设的结论最近新闻报道
  • 上海门户网站制作营销策略都有哪些方面
  • 大学网站建设策划书百度信息流怎么投放
  • 建设银行网站招聘官网360地图怎么添加商户
  • 国外网站推广如何做三一crm手机客户端下载
  • 网站建设新一点网络哈尔滨关键词优化方式
  • 邢台市最新消息优化大师怎么强力卸载
  • 容城县建设银行网站做网站的步骤
  • 怎么做网站讯息网站推广平台
  • 惠州淘宝网站建设上海营销seo
  • 一个人免费视频在线观看动漫江门seo
  • 低成本网站制作百度官方网平台
  • 做竞拍网站最近社会热点新闻事件
  • 哪些网站是phpwind做的生意参谋指数在线转换
  • 北京网站推广排名公司东莞网站建设方案报价
  • 品牌网站建设h合肥刷外链网站
  • 网站模板的功能怎么去做网络推广
  • 企业网站备案意义百度影音在线电影
  • 精品课程网站设计站长工具查询入口
  • 如何建设好政府门户网站百度网盘在线登录
  • 网站开发有很多种吗今日刚刚发生的国际新闻
  • 盐城网站建设有限公司网络推广有几种方法
  • wamp可以做视频网站吗营业推广名词解释
  • 东阿县建设招标网站免费好用的网站
  • 房产网站定制怎样做网站的优化、排名
  • 网站规划与建设 试卷手机百度正式版
  • 国外做美食的网站营销网站seo推广
  • 沈阳建站模板系统包括中国站长网站
  • 电子商务网站开发实务石道元搜索引擎排名2020