IO多路复用-poll(附通信代码)

IO多路复用-poll

1. poll函数

select函数的比较

  • 内核对应文件描述符的检测也是以线性的方式进行轮询,根据描述符的状态进行处理
  • poll和select检测的文件描述符集合会在检测过程中频繁的进行用户区和内核区的拷贝,它的开销随着文件描述符数量的增加而线性增大,从而效率也会越来越低。
  • select检测的文件描述符个数上限是1024,poll没有最大文件描述符数量的限制
  • select可以跨平台使用,poll只能在Linux平台使用

poll函数的原型如下:

#include <poll.h>
// 每个委托poll检测的fd都对应这样一个结构体
struct pollfd {
    int   fd;         /* 委托内核检测的文件描述符 */
    short events;     /* 委托内核检测文件描述符的什么事件 */
    short revents;    /* 文件描述符实际发生的事件 -> 传出 */
};

struct pollfd myfd[100];
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

先看**struct pollfd结构体**:

  • fd:委托内核检测的文件描述符
  • events:委托内核检测的fd事件(输入、输出、错误),每一个事件有多个取值
  • revents:这是一个传出参数,数据由内核写入,存储内核检测之后的结果

在这里插入图片描述

再看poll函数的参数

  • fds: 这是一个struct pollfd类型的数组, 里边存储了待检测的文件描述符的信息

  • nfds: 这是第一个参数数组中最后一个有效元素的下标 + 1(也可以指定参数1数组的元素总个数)

  • timeout: 指定poll函数的阻塞时长

    • -1:一直阻塞,直到检测的集合中有就绪的文件描述符(有事件产生)解除阻塞

    • 0:不阻塞,不管检测集合中有没有已就绪的文件描述符,函数马上返回

    • 大于0:阻塞指定的毫秒(ms)数之后,解除阻塞

函数返回值:

  • 失败: 返回-1
  • 成功:返回一个大于0的整数,表示检测的集合中已就绪的文件描述符的总个数

2. 通信代码

服务器端

//
// Created by 47468 on 2024/1/25.
// server.cpp
#include "arpa/inet.h"
#include "poll.h"
#include "unistd.h"
#include <cstdio>
#include "cstdlib"
#include "iostream"
using namespace std;

int main(){
    // 1.创建套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1){
        perror("socket");
        exit(0);
    }

    // 2. 绑定 ip, port
    struct sockaddr_in saddr{};
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    saddr.sin_addr.s_addr = INADDR_ANY;
    int res = bind(lfd, (struct sockaddr*)&saddr, sizeof(saddr));
    if(res == -1){
        perror("bind");
        exit(0);
    }

    // 3. 监听
    res = listen(lfd, 128);
    if(res == -1){
        perror("listen");
        exit(0);
    }

    // 4. 等待连接 -> 循环
    // 检测 -> 读缓冲区, 委托内核去处理
    // 数据初始化, 创建自定义的文件描述符集
    pollfd fds[1024];
    // 初始化
    for (int i = 0; i < 1024; ++i) {
        fds[i].fd = -1;
        fds[i].events = POLLIN; // 检测读事件
    }
    // 把监听描述符放到0索引
    fds[0].fd = lfd;
    int maxfd = 0;

    while (true){
        // 委托内核检测
        res = poll(fds, maxfd + 1, -1); // 一直阻塞, 直到检测到
        if(res == -1){
            perror("poll");
            exit(0);
        }

        // 检测的读缓冲区有变化
        // 有新连接, 检测的是监听描述符, 下表为0的那个
        if(fds[0].revents & POLLIN){
            // 接收连接请求
            sockaddr_in cliaddr{};
            int len = sizeof(cliaddr);
            int cfd = accept(fds[0].fd, (sockaddr*)&cliaddr, (socklen_t*)(&len));
            // 输出客户端信息
            char ip[32];
            cout << "有客户端连接, 客户端ip: "
                 << inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ip, sizeof(ip))
                 << ", 端口: "
                 << ntohs(cliaddr.sin_port)
                 << endl;
            int i;
            for(i = 1; i < 1024; ++i){
                if(fds[i].fd == -1){ // 这个下标可用
                    fds[i].fd = cfd;
                    break;
                }
            }
            maxfd = max(maxfd, i);
        }

        // 通信, 有客户端发送数据过来
        for (int i = 1; i <= maxfd; ++i) {
            if(fds[i].revents & POLLIN){ // 说明读缓冲区有数据
                char buf[100];
                ssize_t len = read(fds[i].fd, buf, sizeof(buf));
                if(len == -1){
                    perror("read");
                    exit(0);
                }
                else if(len == 0){
                    cout << "客户端断开了连接" << endl;
                    close(fds[i].fd);
                    fds[i].fd = -1;
                }
                else{
                    buf[len] = '\0';
                    cout << "客户端说: " << buf << endl;
                    for(int j = 0; j < len; ++j){
                        buf[j] = toupper(buf[j]);
                    }
                    write(fds[i].fd, buf, len);
                }
                
            }
        }

    }
    close(lfd);
    return 0;
}

客户端

//
// Created by 47468 on 2024/1/25.
//
#include "arpa/inet.h"
#include "poll.h"
#include "unistd.h"
#include <cstdio>
#include <cstring>
#include "cstdlib"
#include "iostream"
using namespace std;

int main(){
    // 1. 创建用于通信的套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1){
        perror("socket");
        exit(0);
    }

    // 2. 连接服务器
    sockaddr_in saddr{};
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    inet_pton(AF_INET, "192.168.110.129", &saddr.sin_addr.s_addr);
    int res = connect(fd, (sockaddr *) &saddr, sizeof(saddr));
    if(res == -1){
        perror("connet");
        exit(0);
    }
    
    // 通信
    while(true){
        // 读数据
        char readBuf[1024];
        // 写数据
        cout << "请输入要发送的字符串: " << endl;
        cin.getline(readBuf, sizeof(readBuf));
        // 发送数据到客户端
        write(fd, readBuf, strlen(readBuf));
        // 接收服务器发送的数据
        read(fd, readBuf, sizeof(readBuf));
        cout << readBuf << endl;
    }
    close(fd);
    return 0;
}

测试:

服务器:

在这里插入图片描述

两个客户端:

在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

恒峰配网行波型故障预警定位装置特点及优势

随着电力系统的不断发展&#xff0c;电网运行的安全性和稳定性对于国家经济和人民生活至关重要。为了提高电网运行的可靠性&#xff0c;减少故障发生的可能性&#xff0c;我国电力行业不断引进新技术、新设备&#xff0c;其中配网行波型故障预警定位装置在电网安全领域发挥着越…

CentOS安装Redis教程-shell脚本一键安装配置

文章目录 前言一、Redis单机版安装教程1. 复制脚本2. 增加执行权限3. 执行脚本 二、Redis扩展集群版安装教程1. 安装Redis单机版2. 复制脚本3. 增加执行权限4. 执行脚本5. 测试6. redis_cluster.sh 命令6.1 启动Redis扩展集群6.2 停止Redis扩展集群6.3 查看Redis扩展集群节点信…

mysql 基础(三)

一、多表设计 数据库设计范式 第一范式(确保每列保持原子性) 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值&#xff0c;就说明该数据库表满足了第一范式。第二范式就是要有主键&#xff0c;要求其他字段都依赖于主键。 没有主键就没有唯一性&…

知识产权实缴注册资金的流程

随着新《公司法》的出台&#xff0c;很多企业老板几乎睡不着&#xff0c;都在为实缴注册资本苦恼。前文有谈到目前比较靠谱的实缴方式是知识产权实缴。那么知识产权实缴的流程是怎么样的&#xff1f;需要准备哪些资料&#xff1f; 下面用一张图为各位企业老板们解读知识产权实…

ios上架缺少info.plist文件

app打包ios提示修改info.plist文件&#xff0c;在iOS原生开发中提供了配置 Info.plist 和 资源文件&#xff08;Bundle Resources&#xff09;。uni-app中对常用项进行了封装&#xff0c;提供了manifest.json。 但manifest.json不能包含所有iOS的配置。需要自定义一个Info.plis…

掌握大语言模型技术: 推理优化

掌握大语言模型技术_推理优化 堆叠 Transformer 层来创建大型模型可以带来更好的准确性、少样本学习能力&#xff0c;甚至在各种语言任务上具有接近人类的涌现能力。 这些基础模型的训练成本很高&#xff0c;并且在推理过程中可能会占用大量内存和计算资源&#xff08;经常性成…

【本科生机器学习】【北京航空航天大学】课题报告:支持向量机(Support Vector Machine, SVM)初步研究【上、原理部分】

说明&#xff1a; &#xff08;1&#xff09;、仅供个人学习使用&#xff1b; &#xff08;2&#xff09;、本科生学术水平有限&#xff0c;故不能保证全无科学性错误&#xff0c;本文仅作为该领域的学习参考。 一、课程总结 1、机器学习&#xff08;Machine Learning, ML&am…

【9.DAC数模转换器】蓝桥杯嵌入式一周拿奖速成系列

系列文章目录 蓝桥杯嵌入式系列文章目录(更多此系列文章可见) DAC数模转换器 系列文章目录一、STM32CUBEMX配置二、项目代码1.main.c --> DACProcess 总结 一、STM32CUBEMX配置 STM32CUBEMX PA4 -> DAC1_OUT1 ; PA5 -> DAC1_OUT2DACProcess 二、项目代码 1.main.c -…

司铭宇老师:销售人员心态激励培训:销售心态调整与情绪压力管理

销售人员心态激励培训&#xff1a;销售心态调整与情绪压力管理&#xff1a;迈向成功的关键要素 导语&#xff1a;在竞争激烈的销售行业中&#xff0c;心态调整与情绪压力管理成为销售人员至关重要的能力。如何在这场博弈中保持良好的心态&#xff0c;有效应对压力&#xff0c;…

C++的关键字,命名空间,缺省参数,函数重载以及原理

文章目录 前言一、C关键字(C98)二、命名空间命名空间介绍命名空间的使用 三、C输入【cin】& 输出【cout】四、缺省参数缺省参数概念缺省参数分类缺省参数的使用小结一下 五、函数重载函数重载介绍函数重载类型 六、C支持函数重载的原理--名字修饰(name Mangling)【重点】 前…

科普栏目|负氧离子水壁炉低能耗的背后的原因与生活优势

科普栏目&#xff5c;负氧离子水壁炉低能耗的背后的原因与生活优势 在当今追求绿色生活和能源高效利用的潮流中&#xff0c;负氧离子水壁炉以其低能耗的特性成为了家庭装饰领域的一颗明珠。究竟是什么原因使得这项技术在能耗方面脱颖而出呢&#xff1f;而低能耗又能为生活带来…

freeswitch智能外呼系统搭建流程

1.获取实时音频数据 media_bug &#xff08;好多mrcp方式也崩溃所以用以下方式&#xff09; 可以参考 方式可以通过socket或者webscoket freeswitch[1.05]用websocket发送mediabug语音流到ASRProxy实现实时质检和坐席辅助 - 知乎 2.webscoket 好多c的库放模块容易崩溃 可以…

适合孩子读书用什么的落地灯?落地护眼灯测评推荐

现代人用眼负荷极大&#xff0c;不仅白天要办公&#xff0c;晚上更是玩手机、刷短视频或是晚间看书阅读&#xff0c;所以营造一个健康的照明环境很重要&#xff01; 如何营造一个健康的照明环境呢&#xff1f;那就不得不提起最近就很火的落地护眼灯。不同于其他台灯灯具&#…

flutter极光推送配置厂商通道(华为)笔记--进行中

一、基础集成按照下面官方文档进行 厂商通道相关参数申请教程 集成厂商 集成指南 官方文档&#xff1a;厂商通道回执配置指南 注意&#xff1a;不同厂商对app上架的要求不同&#xff0c;华为、荣耀 对app上架没有硬性要求 遇到问题 1、引入apply plugin: com.huawei.agconn…

Java玩转《啊哈算法》排序之桶排序

过去心不可得&#xff0c;现在心不可得&#xff0c;未来心不可得 目录在这里 楔子代码地址桶排序代码核心部分优缺点 完整代码演示 升级版核心代码完整代码演示 楔子 大家好&#xff01;本人最近看了下《啊哈算法》&#xff0c;写的确实不错&#xff0c;生动形象又有趣&#x…

k8s的安全机制

k8s是分布式集群管理工具&#xff0c;k8s作用是容器编排 1、安全机制核心&#xff1a;API server。API server作为整个集群内部通信的中介&#xff0c;也是外部控制的入口&#xff0c;所有的安全机制都是围绕api sserver来进行设计的。请求api server资源要满足3个条件&#x…

Garbage First收集器(简称G1)

概述&#xff1a;Garbage First&#xff08;简称G1&#xff09;收集器是垃圾收集器技术发展历史上的里程碑式的成果&#xff0c;它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。 G1开创的基于Region的堆内存布局是它能够实现这个目标的关键。虽然G1也仍是遵…

开始学习Vue(路由)

一、什么是路由 SPA 指的是一个 web 网站只有唯一的一个 HTML 页面&#xff0c;所有组 件的展示与切换都在这唯一的一个页面内完成。 此时&#xff0c;不同组件之间的切换需要通过前端路由来实现。 结论&#xff1a;在 SPA 项目中&#xff0c;不同功能之间的切换&#xff0…

无人机航迹规划(六):七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划(提供MATLAB代码)

一、七种算法&#xff08;DBO、LO、SWO、COA、LSO、KOA、GRO&#xff09;简介 1、蜣螂优化算法DBO 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁…

LP-AM243x EtherNet/IP 连接施耐德 M241 EIP主站测试

硬件环境&#xff1a;LP-AM243x 开发板 施耐德 Modicon M241 软件环境&#xff1a; INDUSTRIAL-COMMUNICATIONS-SDK-AM243X MCU-PLUS-SDK-AM243X — MCU SDK for AM243x 调试过程&#xff1a; 首先&#xff0c;让AM243x能够运行 Null Boot&#xff0c; Starting NULL Boo…