C++Linux网络编程:poll模型和简单使用
文章目录
- poll模型
- pollfd结构体
- nfds_t的定义
- 一个简单的poll服务器
- 总结
poll模型
poll模型和select模型类似,都是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者,需要使用头文件poll.h:
#include <poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
在select中使用的是fd_set结构体,而在此处的是pollfd和nfds_t,timeout的作用和select的一样,用于指定poll的超时值:当timeout的值为-1时,poll调用将会永远阻塞,直到某个事件发生;当timeout为0时,poll调用将立即返回。
poll的返回值也和select一致,表示就绪文件描述符的总数。
pollfd结构体
struct pollfd{int fd; // 文件描述符short int events; // 注册的事件short int revents; // 实际发生的事件,由内核填充
};
- fd指定文件描述符
- events成员告诉poll监听fd上的哪些事件,它是一系列事件的按位或
- revents成员由内核修改,以通知应用程序fd上实际发生了哪些事件
poll支持以下事件类型:
| 事件 | 描述 | 是否可作为输入 | 是否可作为输出 |
|---|---|---|---|
| POLLIN | 数据(包括普通数据和优先数据)可读 | 是 | 是 |
| POLLRNDORM | 普通数据可读 | 是 | 是 |
| POLLRDBAND | 优先级带数据可读 | 是 | 是 |
| POLLPRI | 高优先级数据可读,比如TCP带外数据 | 是 | 是 |
| POLLOUT | 数据(包括普通数据和优先数据)可写 | 是 | 是 |
| POLLWRNORM | 普通数据可写 | 是 | 是 |
| POLLWRBAND | 优先级带数据可写 | 是 | 是 |
| POLLRDHUP | TCP连接被对方关闭,或者对方关闭了写操作。它由GNU引入 | 是 | 是 |
| POLLERR | 错误 | 否 | 是 |
| POLLHUP | 挂起。比如管道的写端被关闭后,读端描述符上将收到POLLHUP事件 | 否 | 是 |
| POLLNVAL | 文件描述符没有打开 | 否 | 是 |
在表中提到了很多事件,但是Linux中没有完全支持它们。
通常,应用程序需要根据recv调用的返回值来区分socket上接受到的是有效数据还是对方关闭连接的请求,并做相应的处理。
不过,自Linux内核2.6.17开始,GNU为poll系统调用增加了一个POLLRDHUP事件,它在socket上接收到对方关闭连接的请求后触发。这为我们区分recv接受到的数据是有效数据还是对方关闭连接的请求提供了一种更简单的方式。
但使用POLLRDHUP事件时,我们需要在代码最开始处定义_GNU_SOURCE。
nfds_t的定义
typedef unsigned long int nfds_t;
该参数用来指定被监听事件集合fds的大小。
一个简单的poll服务器
这个服务器是个简单的echo服务器:
#include <iostream>
#include <vector>
#include <sys/socket.h>
#include <poll.h>
#include <algorithm>
#include <arpa/inet.h>
#include <assert.h>
#include <vector>
#include <unistd.h>using namespace std;int main(int argc, char* argv[]){if(argc != 3){cerr << "格式为 ip port" << endl;return 1;}int serverSocket, clientSocket;/*这个头文件在in.h中(实际上我们调用的是inet/in.h而inet/in.h被包含在头文件arpa/inet。h中了*/struct sockaddr_in serverAddr{}, clientAddr{};socklen_t clientAddrLen;// 创建监听套接字serverSocket = socket(AF_INET, SOCK_STREAM, 0);assert(serverSocket != -1);serverAddr.sin_family = AF_INET;/*htons的英文意思是host to network shrot用于将16位无符号短整型(port)的主机字节序转换为网络字节序*/serverAddr.sin_port = htons(stoi(argv[2])); /*在调用 inet_pton 函数时,需要将 &(address.sin_addr) 作为参数传递,而不是 &(address.sin_addr.s_addr)struct sockaddr_in 结构体中的 sin_addr 字段是一个 struct in_addr 类型的结构体它包含了 IP 地址的二进制表示形式。in_addr 结构体中的 s_addr 字段实际上就是一个无符号整数类型(uint32_t)用来存储 IP 地址的二进制形式。*/inet_pton(AF_INET, argv[1], &(serverAddr.sin_addr));// 绑定套接字到地址和端口int ret = bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));assert(ret != -1);ret = listen(serverSocket, 5);assert(ret != -1);// 监听的文件描述符队列/*创建一个pollfd类型的空向量并且将之前创建的serverSocket加入到其中进行监听POLLIN是我们所监视的事件类型,这点笔记中有写为什么需要监视serverSocket?答:这是为了实现服务器的异步IO,通过监视serverSocket及时检测到下面两种情况:1. 当有新的客户端连接请求到达时,我们希望能够立即进行处理。通过监视serverSocket上的POLLIN事件,可以检测到是否有客户端尝试建立连接2. 当serverSocket上出现其他错误情况(如连接断开或发生错误)时,我们也希望能及时进行处理通过监视serverSocket上的激长时间,如POLLHUP或POLLERR,可以检测到这些错误情况*/vector<pollfd> fds;fds.push_back({serverSocket, POLLIN});while(true){int numRead = poll(fds.data(), fds.size(), -1);if(numRead < 0){cerr << "poll error";return 1;}// for(auto &fd : fds){/*确保有新的连接但是不是很理解为什么是一直监听serverSocket*/if(fd.fd == serverSocket && fd.revents & POLLIN){// 有新连接clientAddrLen = sizeof(clientAddr);clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);if(clientSocket < 0){cerr << "Failed to accepted connection" << endl;return 1;}else{cout << "New connection from:" << inet_ntoa(clientAddr.sin_addr) << endl;fds.push_back({clientSocket, POLLIN});}}else if(fd.revents & POLLIN){// 需要读取信息// 此时的不是监听socket,而是客户端的连接socketchar buffer[1024];ssize_t bytesRead = recv(fd.fd, buffer, sizeof(buffer), 0);if(bytesRead <= 0){if(bytesRead < 0){cerr << "Error reading from client." << endl;}else{cout << "Connection clost by client." << endl;}close(fd.fd);// 这个remove_if()不是很熟fds.erase(remove_if(fds.begin(), fds.end(),[&](const pollfd& pfd){ return pfd.fd == fd.fd; }),fds.end());}else{// 处理数据cout << "Received data: " << string(buffer, bytesRead) << endl;// 将收到的数据回发给客户端send(fd.fd, buffer, bytesRead, 0);}}}}// 关闭监听套接字close(serverSocket);return 0;
}
总结
学到这里我就发现:想要真正去理解Linux网络编程,还是要懂Linux内核,比如:套接字和文件描述符的联系?要去了解下select和poll的工作原理,这样才能理解程序为何这么编写。
相关文章:
C++Linux网络编程:poll模型和简单使用
文章目录 poll模型pollfd结构体nfds_t的定义 一个简单的poll服务器总结 poll模型 poll模型和select模型类似,都是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者,需要使用头文件poll.h: #include <poll.h>…...
Excel模板2:进度条甘特图
Excel模板2:进度条甘特图 今天复刻B站up【名字叫麦兜的狗狗】的甘特图:还在买Excel模板吗?自己做漂亮简洁的甘特图吧!_哔哩哔哩_bilibili 阿里网盘永久分享:https://www.alipan.com/s/cXhq1PNJfdm 当前效果&…...
数据结构:4_二叉树
二叉树 一.树概念及结构 1. 树的概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有一个**特殊的…...
设计模式之:状态模式(State Pattern)
状态模式(State Pattern) 状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为。这种模式通过把状态的变化逻辑分布到State的子类之间,减少了相互间的依赖,使得状态的切换更加清晰。 状态模式的…...
【微服安全】API密钥和令牌与微服务安全的关系
什么是 API 密钥和令牌 API 密钥 API 密钥是一串用于识别应用程序或用户的字符串。它通常用于授权应用程序或用户访问 API。API 密钥可以是公开的,也可以是私有的。公开的 API 密钥可供任何人使用,而私有的 API 密钥只能由授权的应用程序或用户使用。 …...
Mock.js
在开发后端的应用中,我们使用postman来测试接口,观察和验证前后端之间的数据传递是否正常。 在开发前端的应用中,我们使用Mock.js来模拟后端服务,以便进行前端业务逻辑的开发和测试。 一般情况下,个人开发或者小团队开…...
【c++】list详细讲解
> 作者简介:დ旧言~,目前大二,现在学习Java,c,c,Python等 > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:熟悉list库 > 毒鸡汤:你的脸上云淡…...
C#面:在.NET中 类 System.Web.UI.Page 可以被继承吗?
可以。 它是 ASP.NET WebForms中的一个重要类,用于表示 Web 页面。通过继承 System.Web.UI.Page 类,可以创建自定义的 Web 页面,并在其中添加自己的逻辑和功能。 继承 System.Web.UI.Page 类的好处是,可以重用和扩展已有的功能。…...
AI:128-基于机器学习的建筑物能源消耗预测
🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…...
php基础学习之可变函数(web渗透测试关键字绕过rce和回调函数)
可变函数 看可变函数的知识点之前,蒟蒻博主建议你先去看看php的可变变量,会更加方便理解,在本篇博客中的第五块知识点->php基础学习之变量-CSDN博客 描述 当一个变量所保存的值刚好是一个函数的名字(由函数命名规则可知该值必…...
MongoDB聚合操作符:$acos
$acos操作符返回一个值的反余弦。从MongoDB4.2版本开始支持。 语法 { $acos: <expression> }$acos接受任何可被解析为值在-1到1之间的表达式,即:-1 < value < 1$acos返回值以弧度为单位,使用$radiansToDegrees操作符可以把输出…...
开源PDF工具 Apache PDFBox 认识及使用(知识点+案例)
文章目录 前言源码获取一、认识PDFBox二、导入依赖三、基础功能demo1:读取pdf所有内容demo2:读取所有页内容(分页)demo3:添加页眉、页脚demo4:添加居中45文字水印demo5:添加图片到右上角 参考文…...
微软.NET6开发的C#特性——委托和事件
我是荔园微风,作为一名在IT界整整25年的老兵,看到不少初学者在学习编程语言的过程中如此的痛苦,我决定做点什么,下面我就重点讲讲微软.NET6开发人员需要知道的C#特性,然后比较其他各种语言进行认识。 C#经历了多年发展…...
卷积神经网络的基本结构
卷积神经网络的基本结构 与传统的全连接神经网络一样,卷积神经网络依然是一个层级网络,只不过层的功能和形式发生了变化。 典型的CNN结构包括: 数据输入层(Input Layer)卷积层(Convolutional Layer&#x…...
python:使用GDAL库读取遥感影像指定行列数/经纬度坐标的像素值
作者:CSDN @ _养乐多_ 本文将介绍如何使用GDAL库来读取单波段遥感影像数据,如何获取指定行列位置的像素的经纬度坐标,并根据像素行列数或者经纬度坐标获取像素值。代码由python实现。 文章目录 一、读取影像二、获取指定行列位置的像素坐标三、根据地理坐标获取像素值四、根…...
Redis篇----第一篇
系列文章目录 文章目录 系列文章目录前言一、什么是 Redis?二、Redis 与其他 key-value 存储有什么不同?三、Redis 的数据类型?四、使用 Redis 有哪些好处?五、Redis 相比 Memcached 有哪些优势?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住…...
C语言-----用二维数组解决菱形的打印问题
1.打印菱形,多组输入,一个整数(2~20),表示输出的行数,也表示组成“X”的反斜线和正斜线的长度。 #include <stdio.h>int main() {int n0;while(scanf("%d",&n)! EOF){int i0;int j0;f…...
.NET Core WebAPI中使用swagger版本控制,添加注释
一、效果 二、实现步骤 在代码中添加注释 在项目属性中生成API文档 在Program中注册Swagger服务并配置文档信息 // 添加swagger注释 builder.Services.AddSwaggerGen(x > {x.SwaggerDoc("v1", new OpenApiInfo { Title "Swagger标题", Version "…...
css篇---移动端适配的方案有哪几种
移动端适配 移动端适配是指同一个页面可以在不同的移动端设备上都有合理的布局。主流实现的方案有 响应式布局通过rem或者vw,vh 等实现不同设备有相同的比例而实现适配 首先需要了解viewport 【视口】 视口代表了一个可看见的多边形区域(通常来说是矩形࿰…...
一、部署Oracle
部署Oracle 一、Docker部署1.Oracle11g1.1 测试环境1.1.1 拉取镜像1.1.2 启动容器1.1.3 配置容器环境变量1.1.4 修改sys、system用户密码1.1.5 创建表空间1.1.6 创建用户并授权1.1.5 使用DBeaver测试连接 二、安装包部署 一、Docker部署 1.Oracle11g 1.1 测试环境 当前只能用…...
5分钟从零到完整:用SongGeneration开启你的AI音乐创作之旅
5分钟从零到完整:用SongGeneration开启你的AI音乐创作之旅 【免费下载链接】SongGeneration 腾讯开源SongGeneration项目,基于LeVo架构实现高品质AI歌曲生成。它采用混合音轨与双轨并行建模技术,既能融合人声与伴奏达到和谐统一,也…...
突破百度网盘限速壁垒:5步实现直链高速下载全攻略
突破百度网盘限速壁垒:5步实现直链高速下载全攻略 【免费下载链接】baiduyun 油猴脚本 - 一个免费开源的网盘下载助手 项目地址: https://gitcode.com/gh_mirrors/ba/baiduyun 你是否经历过这样的场景:加班后想下载公司共享的设计素材包ÿ…...
为什么你的Java车载模块在-40℃冷启动失败?温度敏感型JIT编译失效分析与AOT预编译加固方案(ISO 26262 Part 6实证)
第一章:Java车载系统实时性优化技巧在车载嵌入式环境中,Java虚拟机(JVM)的默认行为往往难以满足毫秒级响应、确定性调度与低抖动等硬实时需求。尽管Java并非传统实时语言,但通过深度配置与架构约束,可显著提…...
SVN检出报错大全:从E170011到E120106的实战解决手册(附cleanup的正确用法)
SVN检出报错实战指南:从E170011到E120106的深度解析与解决方案 引言:SVN检出报错的常见场景与应对思路 在团队协作开发中,版本控制系统扮演着至关重要的角色。作为集中式版本控制的代表,SVN(Subversion)至今…...
AI印象派艺术工坊WebUI定制:前端界面修改实战案例
AI印象派艺术工坊WebUI定制:前端界面修改实战案例 1. 引言 你有没有想过,自己也能像艺术家一样,把随手拍的照片变成一幅幅精美的画作?素描、彩铅、油画、水彩,这些听起来需要多年绘画功底才能完成的作品,…...
如何高效捕获网页媒体资源?猫抓插件让智能嗅探变得如此简单
如何高效捕获网页媒体资源?猫抓插件让智能嗅探变得如此简单 【免费下载链接】cat-catch 猫抓 chrome资源嗅探扩展 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否遇到过想保存网页上的精彩视频却找不到下载按钮的尴尬?是否曾…...
当LLM学会“思考”算法逻辑:拆解EoH如何用“思想+代码”协同进化,碾压传统自动设计
当LLM成为算法设计师:揭秘EoH如何用“思维代码”双螺旋进化重塑自动算法设计 想象一下,你正在指挥一支由建筑师和施工队组成的特殊团队。建筑师负责绘制蓝图,施工队负责将蓝图变为现实。但与传统团队不同,你的建筑师能根据施工反…...
Windows个性化视觉增强:TranslucentTB打造专属任务栏体验
Windows个性化视觉增强:TranslucentTB打造专属任务栏体验 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 您是否曾感到Window…...
Altium Designer新手必看:5分钟搞定PCB封装库创建(附3D模型导入技巧)
Altium Designer新手实战:从零构建PCB封装库与3D模型高效导入 刚接触Altium Designer的工程师常被PCB封装库的创建难住——焊盘尺寸怎么定?丝印如何对齐?3D模型能否可视化验证?这些问题直接关系到后期PCB设计的成功率。本文将用最…...
告别pip安装失败:在Jetson Nano(ARM64)上手动编译PyQt5 5.15.2的完整记录
在Jetson Nano(ARM64)上手动编译PyQt5 5.15.2的完整指南 当你在Jetson Nano这样的ARM64架构设备上尝试用pip安装PyQt5时,很可能会遇到各种兼容性问题。作为一款强大的Python GUI库,PyQt5在嵌入式开发中有着广泛的应用场景&#x…...
