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 测试环境 当前只能用…...
颠覆性创新:为什么Upkie开源轮式双足机器人正在重新定义机器人开发范式
颠覆性创新:为什么Upkie开源轮式双足机器人正在重新定义机器人开发范式 【免费下载链接】upkie Open-source wheeled biped robots 项目地址: https://gitcode.com/gh_mirrors/up/upkie 在传统机器人设计面临轮式与足式两难选择的今天,一个革命性…...
解锁端侧智能:基于BigDL-LLM与Qwen-1.8B-Chat的CPU高效推理实践
1. 为什么要在CPU上部署大模型? 最近两年大模型技术发展迅猛,但大多数应用都依赖昂贵的GPU服务器。我在实际项目中发现,很多中小企业和个人开发者其实更需要能在普通电脑上运行的轻量化方案。这就是为什么基于CPU的大模型部署方案变得越来越…...
终极免费城通网盘直连解析工具:告别下载限速的完整指南
终极免费城通网盘直连解析工具:告别下载限速的完整指南 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 还在为城通网盘下载速度慢、等待时间长而烦恼吗?ctfileGet是一款专为城通…...
告别答辩PPT焦虑:百考通AI智能生成,高效搞定毕业答辩全流程
毕业季悄然来临,随着毕业论文定稿,答辩PPT成了不少同学面临的下一个挑战。不懂设计、不会梳理逻辑、找不到合适的学术模板……许多同学花费大量时间在排版调整、修改打磨上,不仅效率低下,还常常做出结构混乱、风格不统一的PPT&…...
Rulebook-AI:用规则引擎为AI智能体构建可控决策框架
1. 项目概述:一个基于规则的AI智能体框架最近在探索如何让AI智能体(Agent)的行为更可控、更符合业务逻辑时,我遇到了一个挺有意思的开源项目:botingw/rulebook-ai。乍一看这个名字,可能会觉得它又是一个试图…...
基于Claude API构建AI代码生成工具:从API封装到工程化实践
1. 项目概述与核心价值最近在开发者社区里,一个名为ashish200729/claude-code-source-code的项目标题引起了不小的讨论。乍一看,这个标题很容易让人产生误解,以为这是某个知名AI模型的源代码被公开了。但作为一名在软件开发和开源领域摸爬滚打…...
VT.ai:开发者AI工具集实战指南,提升编码效率与调试体验
1. 项目概述:一个面向开发者的AI工具集最近在GitHub上看到一个挺有意思的项目,叫“vinhnx/VT.ai”。乍一看这个标题,可能有点摸不着头脑,但点进去研究一番,你会发现这其实是一个开发者为自己、也为社区打造的一个AI工具…...
构建个人技能库:用GitHub+Markdown打造开发者的第二大脑
1. 项目概述:从“我的Copaw技能”看个人技能库的构建与管理最近在GitHub上看到一个挺有意思的项目,叫“my-copaw-skill”。这个项目名本身就很有故事感,“Copaw”这个词,我猜是“Code”和“Paw”(爪子)的结…...
Claude API钩子框架设计:非侵入式中间件与生命周期管理实践
1. 项目概述与核心价值最近在折腾一些AI应用开发,发现一个挺有意思的现象:很多开发者想给Claude API的调用过程加点“料”,比如在请求发出前或收到响应后,自动执行一些自定义逻辑。可能是为了日志记录、数据清洗、请求重试&#x…...
告别闪烁屏!瑞芯微RK3399开发板Debian系统烧写保姆级教程(含DriverAssistant v5.1.1 + AndroidTool v2.69)
RK3399开发板Debian系统烧写实战:从屏幕闪烁到完美显示的终极解决方案 当你在RK3399开发板上成功烧写Debian系统后,最期待的莫过于看到系统稳定运行的画面。然而,不少开发者却遭遇了屏幕闪烁的困扰——这个问题看似简单,背后却隐藏…...
