c++高级篇(三) ——Linux下IO多路复用之poll模型

news2024/10/7 20:25:50

poll模型

前言

poll模型与select的实现原理相近,所以绝大数的原理其实可以参考select,我们这里对二者的相同点不做过多探究,如果有需要可以去看一下博主的上一篇文章:
c++高级篇(二) ——Linux下IO多路复用之select模型
这里我们只对二者的不同处做说明。

poll结构体

在poll模型中,是利用pollfd结构体数组来储存socket通讯中使用的socket,pollfd的结构体实现如下:

struct pollfd
{
    int fd; //存储的socket
    short events; // socket触发的事件
    short revents; // 返回的事件
}

由于poll使用的是结构体数组,所以相比于select,poll没有1024的数量限制。

poll模型存在的问题与一些细节

  • 在程序中,poll’的数据结构是数组,传入内核里面切换为链表
  • 每次调用select()需要拷贝两次bitmap,poll拷贝一次结构体数组
  • poll监视的连接数没有1024的限制,但是随着socket的增多,poll的效率会降低

poll流程图(这里以服务端监听socket为例,只有只读事件)

在这里插入图片描述

代码示例

  • poll.h
#include "data-sharing-center/public/_cmpublic.h"

int initsocket(int port);
  • poll.cpp
#include "poll.h"

using namespace std;

int main(int argc,char* argv[])
{
     if(argc!=2)
    {
        cout<<"using example:./server [port]"<<endl;
        return -1;
    }
    int listensock=initsocket(atoi(argv[1]));
    if(listensock<0)
    {
        perror("initsocket() error");
        return -1;
    }

    //定义poll模型的结构体数组
    struct pollfd fds[2048];   //这里写的数字仅说明可以超过1024,具体情况请根据实际情况来判断

    //初始化结构体数组
    for(int ii=0;ii<2048;ii++)
    {
        fds[ii].fd=-1;
        fds[ii].events=POLLIN;   //POLLIN:读,POLLOUT:写,POLLIN|POLLOUT:读写
    }

    int maxfd=listensock;

    while(true)
    {
        //开始监听
        int infds=poll(fds,maxfd+1,100); //最后的数字是超时机制所需的时间,单位为微秒

        if(infds<0)  //连接失败
        {
            perror("poll() error");
            break;
        }
        else if(infds==0)  //超时
        {
            cout<<"poll() timeout"<<endl;
            continue;
        }

        else  //有事件发生
        {
            for(int ii=0;ii<maxfd+1;ii++)  //遍历结构体数组,寻找发生事件的socket
            {
                if(fds[ii].fd==-1) continue;
                if((fds[ii].events&&POLLIN)==0) continue; //没有读事件
                if(fds[ii].fd==listensock)  // 有客户端发送了连接请求
                {
                    struct sockaddr_in clientaddr;
                    socklen_t len=sizeof(clientaddr);
                    int clientsock=accept(listensock,(struct sockaddr*)&clientaddr,&len);
                    if(clientsock<0)
                    {
                        perror("accept() error");
                        break;
                    }
                    cout<<"new client connect"<<endl;
                    //将新的socket加入到结构体数组中
                    fds[maxfd].fd=clientsock;
                    fds[maxfd].events=POLLIN;
                    if(maxfd<clientsock) maxfd=clientsock;
                }
                else
                {
                    //有客户端发送了数据
                    char buff[1024];
                    memset(buff,0,sizeof(buff));
                    int len=recv(fds[ii].fd,buff,sizeof(buff),0);
                    if(len<0)  //说明是客户端关闭了连接
                    {
                        close(fds[ii].fd);
                        fds[ii].fd=-1;
                        fds[ii].events=0;
                        if(fds[ii].fd==maxfd)
                        {
                            for(int ii=maxfd;ii>0;ii--)
                            {
                                if(fds[ii].fd!=-1)
                                {
                                    maxfd=ii;
                                    break;
                                }
                            }
                        }
                    }
                    cout<<"recv data:"<<buff<<endl;
                    //将数据原封不动的发送给客户端
                    send(fds[ii].fd,buff,len,0);
                }
            }
        }
    }
    return 0;
}


int inintsocket(int port)
{
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket() error");
        return -1;
    }

    //设置端口复用
    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,len);

    //绑定端口
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(port);
    serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);

    if(bind(sock,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0)
    {
        perror("bind() error");
        close(sock);
        return -1;
    }

    //监听
    if(listen(sock,5)<0)
    {
        perror("listen() error");
        close(sock);
        return -1;
    }

    return sock;

}

注意: 这里的头文件是博主自己封装的,大家可以使用’man+函数名的方式查看相关函数所需的头文件以及其帮助文档,示例:
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

全志ARM-蜂鸣器

sh操作准备&#xff1a; 1.使Tab键的缩进和批量对齐为4格 在/etc/vim/vimrc 中添加一项配置 set tabstop 4; 也可以再加一行 set nu显示代码的行数 vim的设置&#xff0c;修改/etc/vim/vimrc文件&#xff0c;需要用超级用户权限 /etc/vim/vimrc set shiftwidth4 设置批量…

OpenTiny开源之夏编程达人集结令:4月30日正式上线,寻找最强代码战士!

五一来袭&#xff0c;OpenTiny 开源之夏编程项目正式上线&#xff01; 已梦为马&#xff0c;不负韶华 聚焦前端&#xff0c;OpenTiny 喊你来参加编程活动了 10个赛题任你选&#xff01; 我们诚挚邀请你参与本次 OpenTiny 开源之夏编程活动&#xff0c; 用你的智慧和才能&a…

[移动通讯]【无线感知-P1】[从菲涅尔区模型到CSI模型-5]【The Riemann Mapping Theorem】

前言&#xff1a; mobius变换保角性证明一直困扰我很久.当看完黎曼映射定理以及结合MIT的数学证明 深刻的感触到数学之美&#xff0c;“知之深&#xff0c;情之切”。 黎曼映射&#xff08;The Riemann Mapping&#xff09;定理是复分析最深刻的定理之一&#xff0c;也是复变函…

帮助文档更新了

原先的帮助文档比较简单&#xff0c;大家可能对大部分功能都比较陌生&#xff0c; 最近对帮助文档进行了一轮改版&#xff0c;整个帮助文档更加详细了&#xff0c;对新用户更加友好&#xff0c;这里给大家介绍一下最新的帮助中心 大家进入官网&#xff08;zyjj.cc&#xff09;的…

【再探】设计模式— 工厂方法、单例及原型模式

创建型设计模式是处理对象创建的设计模式&#xff0c;主要特点是“将对象的创建与业务代码分离”。一共有五种&#xff1a;工厂方法模式、单例模式、原型模式、抽象工厂模式及建造者模式。 1 单例模式 需求&#xff1a; 在整个系统中只需要一个实例。管理共享资源&#xff0…

看见游戏出海赛道的新机会

目前游戏出海的主要地区和国家都已经非常成熟&#xff0c;原有的发行方式方法也基本标配化&#xff0c;除了产品玩法的差异化&#xff0c;多元化渠道及获量新方式是提升竞争力的有效手段 4月24日&#xff0c;在深圳南山区&#xff0c;VERYCLOUD睿鸿股份与罗斯基、热力引擎共同主…

基于Spring Boot的外卖点餐系统设计与实现

基于Spring Boot的外卖点餐系统设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 网站首页界面图&#xff0c;通过进入网站可以查看首页、…

新时代教师口才演讲稿(3篇)

新时代教师口才演讲稿&#xff08;3篇&#xff09; 新时代教师口才演讲稿&#xff08;一&#xff09; 尊敬的各位领导、亲爱的同事们&#xff1a; 大家好&#xff01; 今天&#xff0c;我站在这里&#xff0c;深感荣幸与激动。在这个新时代里&#xff0c;教师的口才不仅仅是传…

后端java部署教程,docker配置解读(linux用docker部署新手入门)

文件夹结构 然后解读几个启动脚本 首先dockerFile # 使用anapsix/alpine-java:8_server-jre_unlimited作为基础镜像 FROM anapsix/alpine-java:8_server-jre_unlimited# 设置维护者信息 MAINTAINER adminxiaohuaikeji.com# 设置时区为Asia/Shanghai RUN ln -sf /usr/share/z…

组装nas的 神器 n100 ,改天组装一个!

N100的CPU性能虽然不是很强&#xff0c;性能接近4代i5移动端&#xff0c;但功耗很低&#xff0c;TDP只有6W&#xff0c;而且有个24单元的核显&#xff0c;解码视频能力不差。N100和Intel的i系列CPU是不同厂商生产的&#xff0c;并且它们的设计和架构也有所不同&#xff0c;因此…

Vitis HLS 学习笔记--Schedule Viewer 调度查看器

目录 1. 简介 2. Schedule Viewer详解 2.1 视图说明 2.1.1 Operation\Control Step 2.1.2 周期关系图 2.1.3 Schedule Viewer 菜单栏 2.1.4 属性视图 2.2 内容说明 2.2.1 实参&#xff08;b&#xff09;解释 2.2.2 实参&#xff08;a&#xff09;解释 2.2.3 变量&am…

# Windows 环境变量 Path 显示样式更改

Windows 环境变量 Path 显示样式更改 1、传统 Path 环境变量显示&#xff1a; ---》键盘上按【WIN I 】打开系统【设置】 ---》依次点击 ---》【系统】 ---》【系统信息】 ---》【高级系统设置】 ---》【高级】 ---》【环境变量】。或者依次点击&#xff1a; ---》右键 【我…

利用kimi等大模型进行运维参数解析和调优

在运维时&#xff0c;经常遇到很多参数&#xff0c;有些参数不知道意义&#xff0c;知道意义的也有些不知道合理参考值是多少。利用kimi等大模型来当老司机&#xff0c;轻松解决运维难题。 例如在运维hive参数时&#xff0c;有些不知道作用&#xff0c;提示次如下 你的角色是…

iOS上的UI是如何渲染出来的? 深入浅出UIKit渲染

我们在代码中写的View、Image等组件&#xff0c;最终是如何一步步渲染到屏幕上的呢&#xff1f;触摸、动画等是如何实现的&#xff1f;我们可以利用这些知识做哪些优化呢&#xff1f; 本文先从屏幕物理层原理出发&#xff0c;一步步介绍渲染流程&#xff0c;然后介绍iOS的UIKi…

go idea 不同区域的字体行距设置

1、代码区域的设置&#xff1a; 2、左侧project导航栏的设置&#xff1a; 3、问&#xff1a;go idea 底部的窗口&#xff0c;比如run、terminal、debug、version control等的设置&#xff1a;

pytorch 实现语义分割 PSPNet

语意分割是指一张图片上包含多个物体&#xff0c;通过语义分割可以识别物体分类、物体名称、像素识别的任务。和物体检测不同&#xff0c;他不会将物体框出来&#xff0c;而是根据像素的归属把物体标注出来。PSPNet 的输入是一张图片&#xff0c;例如300500&#xff0c;那么输出…

全志ARM-修改开发板内核启动日志

修改开发板内核日志输出级别&#xff1a; 默认输出级别为1&#xff0c;需要用超级用户权限修改 sudo vi /boot/orangepiEvn.txt 把第一行内核启动输出权限改为7&#xff0c;第二行把输出方式该为“serial”串口输出

QT:小项目:登录界面 (下一个连接数据库)

一、效果图 登录后&#xff1a; 二、项目工程结构 三、登录界面UI设计 四主界面 四、源码设计 login.h #ifndef LOGIN_H #define LOGIN_H#include <QDialog>namespace Ui { class login; }class login : public QDialog {Q_OBJECTpublic:explicit login(QWidge…

区块链技术下的DApp与电商:融合创新,开启商业新纪元

区块链技术的蓬勃发展正引领着一种新型应用程序的崛起——去中心化应用程序&#xff08;DApp&#xff09;。DApp并非传统的中心化应用&#xff0c;它构建于去中心化网络之上&#xff0c;融合了智能合约与前端用户界面&#xff0c;为用户提供了全新的交互体验。智能合约&#xf…

Leetcode—1146. 快照数组【中等】(ranges::lower_bound、std::prev函数)

2024每日刷题&#xff08;121&#xff09; Leetcode—1146. 快照数组 思路 题意很绕&#xff0c;解释一下&#xff1a; 拍一次照&#xff0c;复制出一个新数组&#xff0c;set 都在这个新的上面进行get 目标是得到第 id 个数组的特定位置的值 实现代码 class SnapshotArray…