Linux--高级IO--poll--0326

1. poll

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

poll只负责等。

参数介绍

fds

是一个结构体类型的地址,相比于select中的fd_set类型,pollfd结构体可以内部封装一些遍历,解决需要关系那些文件描述符,以及哪些文件描述符就绪了。从而解决在select中一直需要重新设定的问题。

nfds

表示fds数组的长度

timeout

单位是毫秒,不再是一个timeval类型的地址,变为了拷贝。所以也就不需要再对timeout重新设定,单位是毫秒。

返回值

返回就绪的文件描述符个数。

1.2 struct pollfd 结构体

struct pollfd
{
    int fd;//文教描述符
    short events;//告诉内核我要你关心哪些事件
    short revents;//告诉用户,内核中这些事件就绪了
};

 events和revents的取值

其中常用的 POLLIN POLLOUT POLLERR就对应着select中的那三个参数

1.3.demo

#include <poll.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
    struct pollfd poll_fd;
    //让poll帮我关心 0号文件描述符 关心事件为输入事件
    poll_fd.fd=0;
    poll_fd.events=POLLIN;
    for(;;)
    {
        int ret=poll(&poll_fd,1,1000);
        if(ret<0)
        {
            perror("poll");
            continue;
        }
        else if(ret==0)
        {
            printf("poll timeout\n");
            continue;
        }
        if(poll_fd.revents==POLLIN)
        {
            printf("poll event already\n");
            char buffer[1024];
            read(0,buffer,sizeof (buffer) -1);
            printf("%s",buffer);
        }
    }
    return 0;
}

 2.基于select测试改写的poll代码

select版本

Linux--高级IO--select--0326_Gosolo!的博客-CSDN博客

 

#pragma once
#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;

class PollServer
{
public:
    static const int nfds=100;
    PollServer(const uint16_t &port=8080)
        :_port(port)
        ,_nfds(nfds)
        ,_timeout(1000)
    {
        _listensock=Sock::Socket();
        Sock::Bind(_listensock,_port);//ip缺省值为 0.0.0.0
        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;

        }
        //做一个规定 _fd_array[0]=_listensock
        _fds[0].fd=_listensock;
        _fds[0].events=POLLIN;

    }
    void Start()
    {
        while(true)
        {
            int n=poll(_fds,_nfds,_timeout);
            switch(n)
            {   
            case 0:
                logMessage(DEBUG,"time out...");
                break;
            case -1:  
                logMessage(WARNING,"poll errno: %d : %s",errno,strerror(errno));
                break;
            default:
                //成功
                HandlerEvent();
                break;  
            }
        }
    }
    ~PollServer()
    {
        if(_listensock>=0) close(_listensock);
        if(_fds) delete[] _fds;
    }

private:
    void HandlerEvent()
    {
        for(int i=0;i<_nfds;i++)
        {
            //没让select关心这个文件
            if(_fds[i].fd==FD_NONE) continue; 

            //让关心了 但是需要知道他是否就绪
            if(_fds[i].revents & POLLIN)
            {
                if(_fds[i].fd==_listensock)
                {
                    Acceptr();
                }
                else
                {
                    Recver(i);
                }
            }
        }
    }
    void Acceptr()
    {
        string clientip;
        uint16_t clientport=0;
        int sock=Sock::Accept(_listensock,&clientip,&clientport);
        if(sock<0)
        {
            logMessage(WARNING,"accept error");
            return;
        }
        logMessage(DEBUG,"get a new link success :[%s:%d] : %d",clientip.c_str(),clientport,sock);

        //找一个位置添加 我刚刚得到的sock套接字 好让select帮我关心
        int pos=1;
        for(;pos<_nfds;pos++)
        {
            if(_fds[pos].fd==FD_NONE) break;
        }
        if(pos==_nfds)
        {
            //也可以在这里扩容
            logMessage(WARNING,"%s:%d","select server already full,close fd: %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].fd);
        // 暂时先不做封装, 此时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. 不要让poll帮我关心当前的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;
        }
    }
private:
    uint16_t _port;
    int _listensock;
    struct pollfd* _fds;
    int _nfds;//最大数量
    int _timeout;


};

#endif

 2.2测试及结果

3.poll的优缺点

优点:

效率高。

适用于有大量连接,但只有少量的是活跃的。节省资源。

输入输出参数分离的,不需要进行大量的重置。

poll没有fd管理上限。

缺点:

poll依旧需要不少遍历,在用户层检测就绪,与内核检测fd就绪,都是一样。

poll需要内核到用户的拷贝。

poll代码也比较复杂。但比select容易。

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

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

相关文章

ES6新特性保姆级别教程【建议收藏】

文章目录1、ECMAScript 6 简介1.1、ECMAScript 和 JavaScript 的关系1.2、ES6 与 ECMAScript 2015 的关系1.3、ECMAScript 的历史2、let 和 const 命令2.1、let 命令2.1.1、基本用法2.1.2、不存在变量提升2.1.3、不允许重复声明2.1.4、暂时性死区2.2、const 命令2.2.1、基本用法…

cuda学习4-6

4. Hardware Implementation NVIDIA GPU架构是围绕一系列可扩展的多线程流式多处理器&#xff08;SM&#xff09;构建的。当主机CPU上的CUDA程序调用内核网格时&#xff0c;网格的块将被枚举并分配给具有可用执行能力的多处理器。线程块的线程在一个多处理器上并发执行&#x…

C++内存管理详解

大家好&#xff0c;这里是bang_bang&#xff0c;今天来分享下内存管理的知识。 目录 1.C/C内存分布 2.C内存管理方式 2.1new/delete操作内置类型 2.2new/delete操作自定义类型 3.operator new与operator delete函数 3.1operator new 3.2operator delete 4.new和delete的实现…

367. 有效的完全平方数 ——【Leetcode每日一题】

367. 有效的完全平方数 给你一个正整数 num 。如果 num 是一个完全平方数&#xff0c;则返回 tru &#xff0c;否则返回 false 。 完全平方数 是一个可以写成某个整数的平方的整数。换句话说&#xff0c;它可以写成某个整数和自身的乘积。 不能使用任何内置的库函数&#xf…

Mybatis框架源码笔记(九)之反射工具类解析

1 反射工具类 Java中的反射功能虽然强大&#xff0c;但是代码编写起来比较复杂且容易出错。Mybatis框架提供了专门的反射包&#xff0c;对常用的反射操作进行了简化封装&#xff0c;提供了更简单方便的API给调用者进行使用&#xff0c;主要的反射包代码结果如下&#xff1a; …

React 组件的 children 数据使用

children 属性表示该组件的子节点&#xff0c;只要组件内部有子节点&#xff0c;props 就有该属性&#xff0c;是自动带上的&#xff0c;不需要开发者添加。 children 可以是 普通文本、普通标签元素、函数、JSX … 案例一&#xff1a;普通文本 import React from "rea…

奇异值分解(SVD)和图像压缩

在本文中&#xff0c;我将尝试解释 SVD 背后的数学及其几何意义&#xff0c;还有它在数据科学中的最常见的用法&#xff0c;图像压缩。 奇异值分解是一种常见的线性代数技术&#xff0c;可以将任意形状的矩阵分解成三个部分的乘积&#xff1a;U、S、V。原矩阵A可以表示为&#…

数据结构与算法基础(王卓)(21):哈夫曼编码(1):过程

逻辑雏形 根据老师讲解的思路&#xff0c;梳理出程序运行的逻辑雏形如下&#xff1a; 搞一个多维数组HC&#xff0c;用来存储我们这里 n(每) 个节点的哈夫曼编码搞一个数组cd&#xff0c;用来存储我们这里每个节点是前面一位的左子树&#xff08;0&#xff09;还是右子树&…

Spark 基本知识介绍

文章目录1. Spark是什么2. Spark与Hadoop区别3. Spark四大特点3.1 速度快3.2 易于使用3.3 通用性强3.4 运行方式4. Spark整体框架5. Spark运行模式6. Spark架构角色6.1 YARN角色6.2 Spark 角色1. Spark是什么 Spark是用于大规模数据处理的统一分析引擎。 Spark 最早源于一篇论…

Qt5.15.2 for WebAssembly 环境搭建 - Windows篇

Qt系列文章目录 文章目录Qt系列文章目录前言一、准备工作二、操作步骤1.使用cmd工具2.安装Qt for WebAssembly3.创建工程WebAssembly3.创建Qt Assembly工程参考前言 由于前端Canvas绘制图像效率问题&#xff0c;而且实现三维特效也有性能瓶颈&#xff0c;虽然Web 技术突飞猛进…

基于Arm Cortex-M4核心MK60DN256VMD10、MK60DX256VMD10嵌入式微控制器芯片介绍

MK60DN256VMD10&#xff08;MK60DX256VMD10&#xff09;是Kinetis K6x系列32位微控制器&#xff0c;基于ArmCortex-M4核心&#xff0c;是与Kinetis Kx MCU家族兼容的引脚&#xff0c;外设和软件。K6x mcu还集成了10/100Mbps以太网与IEEE1588精确时间协议(PTP)收发器和USB 2.0 (…

【Linux-计算机网络】-TCP协议通信流程

1.TCP协议通信流程图 1.1TCP协议的通讯流程可以分为以下步骤&#xff1a; 应用层&#xff1a;应用程序通过系统调用API&#xff08;如socket&#xff09;创建一个TCP套接字&#xff08;socket&#xff09;&#xff0c;并设置好相关的选项。 传输层&#xff1a;当应用程序调用c…

再学C语言49:C库中的字符串函数

C库提供了很多处理字符串的函数&#xff1b;ANSI C用头文件 string.h 给出这些函数的原型 一、strlen()函数 功能&#xff1a;计算并返回字符串长度 示例代码&#xff1a; /* test strlen() function */ #include <stdio.h> #include <string.h>int main(void)…

数据的存储--->【大小端字节序】(Big Endian)(Little Endian)

⛩️博主主页&#xff1a;威化小餅干&#x1f4dd;系列专栏&#xff1a;【C语言】藏宝图&#x1f38f; ✨绳锯⽊断&#xff0c;⽔滴⽯穿&#xff01;一个编程爱好者的学习记录!✨前言计算机硬件有两种存储数据的方式&#xff1a;大端字节序——Big Endian小端字节序——Little …

【Python】【进阶篇】十、Python爬虫的Requests库

目录十、Python爬虫的Requests库10.1 常用请求方法10.1.1 requests.get()10.1.2 requests.post()10.2 对象属性10.3 Requests库应用十、Python爬虫的Requests库 Python 提供了多个用来编写爬虫程序的库&#xff0c;除了前面已经介绍的 urllib 库之外&#xff0c;还有一个很重的…

vue尚品汇商城项目-day07【44.个人中心二级路由搭建+45.我的订单+46.优化登录跳转+47.独享守卫】

文章目录44.个人中心二级路由搭建45.我的订单46.优化登录跳转47.独享守卫本人其他相关文章链接44.个人中心二级路由搭建 修改代码&#xff1a; 将Center拆分为2个组件MyOrderGroupOrder src/router/routes.js import Center from /pages/Center import GroupOrder from /pages…

QT 常见控件使用

1. QLineEdit 添加控件后&#xff0c;可以编辑控件的名称&#xff0c;然后使用名称获取和设置值 QString qstrValue ui->strName->text(); QMessageBox::information(this, "提示", qstrValue); 2.窗体导航切换 添加新的对话框&#xff0c;然后引入头文件…

游戏安全漏洞一些分享

安全界对漏洞的定义为&#xff1a;在硬件、软件、系统等具体实现或者系统安全策略上存在的缺陷&#xff0c;从而使攻击者能够达到于某种破坏效果。游戏安全漏洞属于常规漏洞的子类&#xff0c;常规漏洞的分类如下图所示&#xff1a; 通过以上的漏洞分类图可知游戏漏洞属于常规…

MATLAB | 如何绘制github同款日历热力图

应粉丝要求&#xff0c;出一个类似于github热图的日历热力图&#xff0c;大概长这样&#xff1a; 依旧工具函数放在文末&#xff0c;如有bug请反馈并去gitee下载更新版。 使用教程 使用方式有以下几种会慢慢讲到&#xff1a; heatmapDT(Year,T,V)heatmapDT(Year,T,V,MonLim)h…

被称为“眼黄金”的叶黄素究竟是什么?叶黄素则能过滤蓝光

人眼视觉依赖于黄斑的中心凹陷。黄斑中含有大量的叶黄素&#xff0c;因此被称为“黄斑”。叶黄素&#xff0c;也被称为“眼黄金”&#xff0c;是人类视网膜中最重要的营养物质。它含有黄斑&#xff08;视觉中心&#xff09;和晶状体&#xff0c;特别是黄斑中含有高浓度的叶黄素…
最新文章