Linux高级IO之poll

 (。・∀・)ノ゙嗨!你好这里是ky233的主页:这里是ky233的主页,欢迎光临~icon-default.png?t=N7T8https://blog.csdn.net/ky233?type=blog

点个关注不迷路⌯'▾'⌯

目录

一、poll函数接口

1.接口

2.poll做了什么工作

3.events和revents的取值

二、代码

三、poll的优缺点


poll将输入参数和输出参数做了分离,所以我们就不用对参数进行重新设定了。并且把上限取消了 

一、poll函数接口

1.接口

#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 */
}

参数说明:

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

2.poll做了什么工作

poll只负责等!

1.用户告诉内核:你帮我关心,哪些fd,哪些事件

2.内核告诉用户:哪些fd,哪些时间已经就绪了

3.events和revents的取值

二、代码

#ifndef __POLL_SVR_H__
#define __POLL_SVR_H__

#include <iostream>
#include <string>
#include <vector>
#include <poll.h>
#include <sys/time.h>
#include "Log.hpp"
#include "Sock.hpp"

#define FD_NONE -1

using namespace std;
// select 我们只完成读取,写入和异常不做处理 -- epoll(写完整)
class PollServer
{
public:
    static const int nfds = 100;
public:
    PollServer(const uint16_t &port = 8080) : _port(port), _nfds(nfds)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG,"%s","create base socket success");

        _fds = new struct pollfd[_nfds];
        for(int i = 0; i < _nfds; i++) {
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0;
        }
        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN;

        _timeout = 1000;
    }

    void Start()
    {
        while (true)
        {
            int n = poll(_fds, _nfds, _timeout);
            switch (n)
            {
            case 0:
                logMessage(DEBUG, "%s", "time out...");
                break;
            case -1:
                logMessage(WARNING, "select error: %d : %s", errno, strerror(errno));
                break;
            default:
                // 成功的
                HandlerEvent();
                break;
            }
        }
    }

    ~PollServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_fds) delete [] _fds;
    }
private:
    void HandlerEvent() // fd_set 是一个集合,里面可能会存在多个sock
    {
        for(int i = 0; i < _nfds; i++)
        {
            // 1. 去掉不合法的fd
            if(_fds[i].fd == FD_NONE) continue;
            // 2. 合法的就一定就绪了?不一定
            if(_fds[i].revents & POLLIN)
            {
                //指定的fd,读事件就绪
                // 读事件就绪:连接事件到来,accept
                if(_fds[i].fd == _listensock) Accepter();
                else Recver(i);
            }
        }
    }
    void Accepter()
    {
        string clientip;
        uint16_t clientport = 0;
        // listensock上面的读事件就绪了,表示可以读取了
        // 获取新连接了
        int sock = Sock::Accept(_listensock, &clientip, &clientport); // 这里在进行accept会不会阻塞?不会!
        if(sock < 0)
        {
            logMessage(WARNING, "accept error");
            return;
        }
        logMessage(DEBUG, "get a new line success : [%s:%d] : %d", clientip.c_str(), clientport, sock);
        int pos = 1;
        for(; pos < _nfds; pos++){
            if(_fds[pos].fd == FD_NONE) break;
        }
        if(pos == _nfds){
            // 对struct pollfd进行自动扩容
            logMessage(WARNING, "%s:%d", "poll server already full,close: %d", sock);
            close(sock);
        }else{
            _fds[pos].fd = sock;
            _fds[pos].events = POLLIN;
        }
    }
    void Recver(int pos)
    {
        // 读事件就绪:INPUT事件到来、recv,read
        logMessage(DEBUG, "message in, get IO event: %d", _fds[pos]);
        // 暂时先不做封装, 此时select已经帮我们进行了事件检测,fd上的数据一定是就绪的,即 本次 不会被阻塞
        // 这样读取有bug吗?有的,你怎么保证以读到了一个完整包文呢?
        char buffer[1024];
        int n = recv(_fds[pos].fd, buffer, sizeof(buffer)-1, 0);
        if(n > 0){
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _fds[pos].fd, buffer);
        }
        else if(n == 0){
            logMessage(DEBUG, "client[%d] quit, me too...", _fds[pos].fd);
            // 1. 我们也要关闭不需要的fd
            close(_fds[pos].fd);
            // 2. 不要让select帮我关心当前的fd了
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
        else{
            logMessage(WARNING, "%d sock recv error, %d : %s", _fds[pos].fd, errno, strerror(errno));
            // 1. 我们也要关闭不需要的fd
            close(_fds[pos].fd);
            // 2. 不要让select帮我关心当前的fd了
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
    }

    void DebugPrint()
    {
        cout << "_fd_array[]: ";
        for(int i = 0; i < _nfds; i++)
        {
            if(_fds[i].fd == FD_NONE) continue;
            cout << _fds[i].fd << " ";
        }
        cout << endl;
    }
private:
    uint16_t _port;
    int _listensock;
    struct pollfd *_fds;
    int _nfds;
    int _timeout;
};

#endif

三、poll的优缺点

优点:

  1. 效率高,和select一样
  2. 节省资源,有大量的连接,只有少量是活跃的
  3. 输入和输出参数分离,不需要大量的重置
  4. 参数级别没有fd的上限

缺点:

  1. poll还是需要遍历,而且不少,在用户层检测时间就绪,与在内核层检测fd就绪,都是一样的
  2. poll需要用户和内核进行拷贝只需要进行一次,但内核到用户需要一直拷贝,这个时少不了的
  3. poll编写也不太容易,但比select容易

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

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

相关文章

2024 年中国高校大数据挑战赛赛题 C:用户对博物馆评论的情感分析完整思路以及源代码分享

博物馆是公共文化服务体系的重要组成部分。国家文物局发布&#xff0c; 2021 年我国新增备案博物馆 395 家&#xff0c;备案博物馆总数达 6183 家&#xff0c;排 名全球前列&#xff1b;5605 家博物馆实现免费开放&#xff0c;占比达 90%以上&#xff1b;全国 博物馆举办展览 3…

docker 子网

当需要给容器分配指定 ip &#xff0c;为避免ip 冲突&#xff0c;指定容器子网处理 创建 subnet 子网 docker network create --subnet 10.0.0.0/24 --gateway 10.0.0.1 subnet-testdocker network ls NETWORK ID NAME DRIVER SCOPE ... f582ecf297bc sub…

【杂记】IDEA和Eclipse如何查看GC日志

1.Eclipse查看GC日志 1.1 右击代码编辑区 -> Run As -> Run Configurations 1.2 点击Arguments栏 -> VM arguments:区域填写XX参数 -> Run 1.3 控制台输出GC详细日志 2.IDEA查看GC日志 2.1 鼠标右击代码编辑器空白区域&#xff0c;选择Edit 项目名.main()... 2.…

Mysql命令行客户端

命令行客户端 操作数据库操作数据表 操作数据库 mysql> create database mike charsetutf8; Query OK, 1 row affected (0.01 sec) mysql> show databases; -------------------- | Database | -------------------- | information_schema | | mike …

【C语言】linux内核tcp_write_xmit和tcp_write_queue_purge

tcp_write_xmit 一、讲解 这个函数 tcp_write_xmit 是Linux内核TCP协议栈中的一部分&#xff0c;其基本作用是发送数据包到网络。这个函数会根据不同情况推进发送队列的头部&#xff0c;确保只要远程窗口有空间&#xff0c;就可以发送数据。 下面是对该函数的一些主要逻辑的中…

实验二(一):IPV4编址及IPV4路由基础实验

一实验介绍 1.关于本实验 IPv4( Internet Protocol Version 4)是 TCP/IP 协议族中最为核心的协议之一。 它工作在 TCP/IP参考模型的网际互联层&#xff0c;该层与 OSI参考模型的网络层相对应。 网络层提供了无连接数据传输服务&#xff0c;即网络在发送分组时不需要先建立连…

算法设计与分析(超详解!) 第一节 算法概述

1.算法的定义 算法的非形式化定义&#xff1a;算法是规则的有限集合&#xff0c;是为解决特定问题而规定的一系列操作。 可以理解为&#xff1a;算法&#xff08;algorithm&#xff09;是指在解决问题时&#xff0c;按照某种机械的步骤一定可以得到问题的结果&#xff08;有的…

数学建模-动态规划(美赛运用)

动态规划模型的要素是对问题解决的抽象&#xff0c;其可分为&#xff1a; 阶段。指对问题进行解决的自然划分。例如&#xff1a;在最短线路问题中&#xff0c;每进行走一步的决策就是一个阶段。 状态。指一个阶段开始时的自然状况。例如&#xff1a;在最短线路问题中&#xff…

嵌入式Qt 制作一个登录对话框

一.登录对话框需求分析 二.代码实现 main.c&#xff1a; #include <QtGui/QApplication> #include "widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }Widget.h&#xff1a; #ifndef _WIDGET_H_…

EDA软件

EDA软件 EDA概念IC类EDA&#xff08;芯片EDA软件&#xff09;数字芯片和模拟芯片的区别模拟芯片产品种类IC设计类数字电路设计模拟电路设计 IC制造类IC封装类 PCB类EDA&#xff08;板级EDA软件&#xff09;Mentor公司板级EDACadence公司板级EDAAltium公司&#xff08;已被日本瑞…

bug_java

文章目录 1.创建Maven时&#xff1a; idea报错为&#xff1a;java&#xff1a;错误&#xff1a;不支持发行版本52. Springbot启动报错-类文件具有错误的版本 61.0, 应为 52.0 1.创建Maven时&#xff1a; idea报错为&#xff1a;java&#xff1a;错误&#xff1a;不支持发行版本…

贪吃蛇(C语言实现)

贪食蛇&#xff08;也叫贪吃蛇&#xff09;是一款经典的小游戏。 —————————————————————— 本博客实现使用C语言在Windows环境的控制台中模拟实现贪吃蛇小游戏。 实行的基本功能&#xff1a; • 贪吃蛇地图的绘制 • 蛇吃食物的功能&#xff08;上、…

【重新定义matlab强大系列十七】Matlab深入浅出长短期记忆神经网络LSTM

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

Netty Review - 探究Netty服务端主程序无异常退出的背后机制

文章目录 概述故障场景尝试改进问题分析铺垫&#xff1a; Daemon线程Netty服务端启动源码分析逻辑分析 如何避免Netty服务端意外退出最佳实践 概述 在使用Netty进行服务端程序开发时&#xff0c;初学者可能会遇到各种问题&#xff0c;其中之一就是服务端意外退出的问题。这种问…

基于机器学习的工业用电量预测完整代码数据

视频讲解: 毕业设计:算法+系统基于机器学习的工业用电量预测完整代码数据_哔哩哔哩_bilibili 界面展示: 结果分析与展示: 代码: from sklearn import preprocessing import random from sklearn.model_selection import train_test_split from sklearn.preprocessing…

oracle基础-多表关联查询 备份

一、概述 在实际应用系统开发中会设计多个数据表&#xff0c;每个表的信息不是独立存在的&#xff0c;而是若干个表之间的信息存在一定的关系&#xff0c;当用户查询某一个表的信息时&#xff0c;很可能需要查询关联数据表的信息&#xff0c;这就是多表关联查询。SELECT语句自身…

【NR技术】 3GPP支持无人机服务的关键性能指标

1 性能指标概述 5G系统传输的数据包括安装在无人机上的硬件设备(如摄像头)收集的数据&#xff0c;例如图片、视频和文件。也可以传输一些软件计算或统计数据&#xff0c;例如无人机管理数据。5G系统传输的业务控制数据可基于应用触发&#xff0c;如无人机上设备的开关、旋转、升…

数字化解决方案的设计与实现:提升业务效率与用户体验

摘要&#xff1a;随着数字化时代的到来&#xff0c;越来越多的企业和组织开始寻求数字化解决方案来提升业务效率和改善用户体验。本文将探讨数字化解决方案的设计与实现过程&#xff0c;并介绍一些关键的技术和策略。 ## 引言 在当今竞争激烈的商业环境中&#xff0c;企业和组…

深度学习图像算法工程师--面试准备(2)

深度学习面试准备 深度学习图像算法工程师–面试准备&#xff08;1&#xff09; 深度学习图像算法工程师–面试准备&#xff08;2&#xff09; 文章目录 深度学习面试准备前言一、Batch Normalization(批归一化)1.1 具体步骤1.2 BN一般用在网络的哪个部分 二、Layer Normaliza…

个人健康管理系统|基于微信小程序的个人健康管理系统设计与实现(源码+数据库+文档)

个人健康管理小程序目录 目录 基于微信小程序的个人健康管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、用户信息管理 2 运动教程管理 3、公告信息管理 4、论坛信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设…