当前位置: 首页 > news >正文

C++网络编程之IO多路复用(一)

概述

        在C++网络编程中,处理并发连接是一个非常关键的核心问题。为了有效管理来自多个客户端的请求,服务器需要能够同时监听多个套接字上的事件,这通常通过IO多路复用来实现。

        IO多路复用是一种工作机制,它可以让程序监视多个文件描述符(通常是套接字),等待其中一个或多个文件描述符变为就绪状态。一旦某个文件描述符就绪,即该文件描述符上可以进行无阻塞读写操作,操作系统就会通知应用程序。然后,应用程序就可以对该文件描述符进行相应的读写操作。

        使用IO多路复用后,不需要为每个连接创建一个独立的线程,节省了资源。同时,也避免了频繁的上下文切换开销,提高了效率。常见的IO多路复用技术主要有三种,分别为:select、poll、epoll。在本篇中,我们将重点介绍select,后续文章将介绍poll和epoll。

select

        select是最古老的IO多路复用API,几乎支持所有类型的Unix系统(包括:Windows、Linux、Mac等)。它的基本工作原理是:用户态进程将一组文件描述符传递给内核,由内核来检查这些文件描述符的状态变化;当调用返回时,会告诉用户哪些文件描述符已经准备好了读写操作。

        select函数的接口原型如下。

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

        各个参数和返回值的含义如下。

        nfds:指定要监视的最大文件描述符值加1。

        readfds:指向一个集合,该集合包含了想要监视读就绪状态的文件描述符。

        writefds:指向一个集合,该集合包含了想要监视写就绪状态的文件描述符。

        exceptfds:指向一个集合,该集合包含了想要监视异常条件的文件描述符。

        timeout:一个时间结构体,指定了等待超时的时间。如果设置为NULL,则会一直阻塞,直到至少有一个文件描述符准备好。如果设置了具体时间,则在指定时间内没有事件发生将返回0。

        返回值:如果返回正数,这意味着至少有一个文件描述符已经准备好执行请求的操作(读、写或异常条件)。返回的具体数值,表示有多少个文件描述符已就绪。如果返回 0,这意味着在指定的超时时间内没有任何文件描述符准备好,并且超时时间已过。如果返回负数,这意味着调用过程中发生了错误。常见的原因包括传入了无效的参数或者系统本身遇到了问题。

        在Windows系统和Linux系统下使用select函数时,它们之间存在一些细微的差异,具体如下。

        1、头文件和库不同。

        Windows:需要包含winsock2.h头文件,且链接到Winsock库ws2_32.lib。

        Linux:需要包含sys/select.h头文件,不需要链接额外的库,因为select是标准POSIX库的一部分。

        2、类型不同。

        Windows:Socket类型为套接字句柄。

        Linux:Socket类型为文件描述符,这是所有IO操作的基础。

        3、FD_SETSIZE的定义不同。

        Windows:默认的FD_SETSIZE是64。

        Linux:默认的FD_SETSIZE是1024。

        4、错误码不同。

        Windows:返回SOCKET_ERROR,表示发生了错误。可通过WSAGetLastError函数获取更具体的错误值,比如:WSAEINTR(被信号中断)、WSAEINVAL(无效参数)等。

        Linux:返回-1,表示发生了错误。可通过errno获取更具体的错误值,比如:EINTR(被信号中断)、EINVAL(无效参数)等。

        注意:select只能处理有限数量的文件描述符,通常这个数量由上面介绍的FD_SETSIZE定义。当监视大量的文件描述符时,select的性能会显著下降。每次调用select都需要复制所有文件描述符集合到内核空间,然后在内核中进行线性扫描。这种机制对于少量的文件描述符是可行的,但对于大规模并发应用则效率低下。

实战代码

        在Windows系统下如何使用select进行IO多路复用,可参考下面的TCP服务器的示例代码。

        首先,我们使用WSAStartup初始化Winsock库,并检查是否成功。接着,创建一个监听套接字,将其绑定到指定的端口8888,并调用listen开始监听连接请求。

        然后,我们使用fd_set类型的变量masterSet来存储所有需要监控的套接字,包括:监听套接字、所有已连接的客户端套接字;workingSet则用于临时存储select检查的结果。

        紧接着,在无限循环中,我们使用select函数来等待IO事件的发生。如果select返回新的连接请求,接受新连接,并将新连接的套接字添加到masterSet和activeSockets向量中。对于每个已连接的客户端套接字,检查是否有数据可读。如果有,则读取数据并回显给客户端。如果客户端断开连接,则关闭相应的套接字,并从masterSet和activeSockets中移除该套接字。

        最后,当程序退出时,关闭所有打开的套接字,并清理Winsock库。

#include <iostream>
#include <winsock2.h>
#include <vector>
using namespace std;#pragma comment(lib, "ws2_32.lib")#define TCP_LISTEN_PORT                   8888
#define BUFFER_SIZE                       1024int main()
{// 初始化Winsock库WSADATA wsaData;int result = WSAStartup(MAKEWORD(2, 2), &wsaData);if (result != 0){cout << "WSAStartup failed: " << result << endl;return 1;}SOCKET listenSocket = INVALID_SOCKET;struct sockaddr_in serverAddr;// 创建监听 socketlistenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (listenSocket == INVALID_SOCKET){cout << "Socket creation failed: " << WSAGetLastError() << endl;WSACleanup();return 1;}// 设置服务器地址serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = INADDR_ANY;serverAddr.sin_port = htons(TCP_LISTEN_PORT);if (bind(listenSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR){cout << "Bind failed: " << WSAGetLastError() << endl;closesocket(listenSocket);WSACleanup();return 1;}// 开始监听if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR){cout << "Listen failed: " << WSAGetLastError() << endl;closesocket(listenSocket);WSACleanup();return 1;}cout << "Server listening on port " << TCP_LISTEN_PORT << endl;fd_set masterSet;FD_ZERO(&masterSet);FD_SET(listenSocket, &masterSet);fd_set workingSet;// 存储新连接的套接字句柄vector<SOCKET> activeSockets;activeSockets.push_back(listenSocket);while (true){workingSet = masterSet;// 调用selectint selectResult = select(0, &workingSet, NULL, NULL, NULL);if (selectResult == SOCKET_ERROR){cout << "Select failed: " << WSAGetLastError() << endl;break;}// 检查是否有新的连接请求if (FD_ISSET(listenSocket, &workingSet)){SOCKET clientSocket = accept(listenSocket, NULL, NULL);if (clientSocket == INVALID_SOCKET){cout << "Accept failed: " << WSAGetLastError() << endl;continue;}cout << "New connection: " << clientSocket << endl;FD_SET(clientSocket, &masterSet);activeSockets.push_back(clientSocket);}// 检查其他已连接的客户端是否有数据可读for (const auto &sock : activeSockets){// 跳过监听Socketif (sock == listenSocket){continue;}if (FD_ISSET(sock, &workingSet)){char buffer[BUFFER_SIZE] = { 0 };int bytesReceived = recv(sock, buffer, BUFFER_SIZE, 0);if (bytesReceived > 0){cout << "Received from client " << sock << ": " << buffer << endl;// 回显消息给客户端send(sock, buffer, bytesReceived, 0);}else if (bytesReceived == 0){cout << "Client disconnected: " << sock << endl;closesocket(sock);FD_CLR(sock, &masterSet);// 移除断开的连接auto it = find(activeSockets.begin(), activeSockets.end(), sock);if (it != activeSockets.end()){activeSockets.erase(it);}}else{cout << "Recv failed: " << WSAGetLastError() << endl;closesocket(sock);FD_CLR(sock, &masterSet);// 移除断开的连接auto it = find(activeSockets.begin(), activeSockets.end(), sock);if (it != activeSockets.end()){activeSockets.erase(it);}}}}}// 释放资源for (const auto &sock : activeSockets){closesocket(sock);}closesocket(listenSocket);WSACleanup();return 0;
}

相关文章:

C++网络编程之IO多路复用(一)

概述 在C网络编程中&#xff0c;处理并发连接是一个非常关键的核心问题。为了有效管理来自多个客户端的请求&#xff0c;服务器需要能够同时监听多个套接字上的事件&#xff0c;这通常通过IO多路复用来实现。 IO多路复用是一种工作机制&#xff0c;它可以让程序监视多个文件描述…...

vscode在windows和linux如何使用cmake构建项目并make生成可执行文件,两者有什么区别

vscode在windows和linux如何使用cmake构建项目并make生成可执行文件&#xff0c;两者有什么区别 windows默认使用的是最新的visual studio&#xff0c;而linux默认就是cmake 文章目录 vscode在windows和linux如何使用cmake构建项目并make生成可执行文件&#xff0c;两者有什么…...

Antd Vue中使用table组件把相同名称的合并单元格---只需两步

当前效果&#xff1a; 想要的效果&#xff1a; 第一步&#xff1a;在获取table数据的地方处理数据 function getTableList () {getDataList().then(res > {if (res.code 200 && res.data) {const list res.datalet columnIndex 0 //第一条数据let rowSpan …...

cmake中execute_process详解

execute_process 是 CMake 中一个非常强大的命令&#xff0c;用于在构建过程中执行外部程序或脚本。它提供了丰富的选项来控制执行过程&#xff0c;并可以捕获输出、错误和返回码。以下是 execute_process 的详细解析&#xff1a; 基本语法 execute_process(COMMAND <comm…...

搜维尔科技:使用Sensglove Nova2触觉反馈手套遥操作机器人操作

使用Sensglove Nova2触觉反馈手套遥操作机器人操作 搜维尔科技&#xff1a;使用Sensglove Nova2触觉反馈手套遥操作机器人操作...

企业HR如何选对一款智能招聘软件?

随着招聘市场的竞争加剧和求职者期望的提升&#xff0c;传统的招聘方式已经难以满足企业的需求。智能招聘软件应运而生&#xff0c;成为企业HR提升招聘效率、优化招聘流程、增强雇主品牌吸引力的关键工具。然而&#xff0c;市场上的智能招聘软件琳琅满目&#xff0c;如何选择一…...

任务中心全新升级,新增分享接口文档功能,MeterSphere开源持续测试工具v3.4版本发布

2024年11月5日&#xff0c;MeterSphere开源持续测试工具正式发布v3.4版本。 在这一版本中&#xff0c;系统设置方面&#xff0c;任务中心支持实时查看系统即时任务与系统后台任务&#xff1b;接口测试方面&#xff0c;新增接口文档分享功能、接口场景导入导出功能&#xff0c;…...

书生大模型第三关Git 基础知识

关卡编号&#xff1a;L0G3000 任务一 破冰行动 fork仓库&#xff0c;注意这里不要勾选Copy branch Only!!!&#xff0c;因为后面课程中会使用到class分支&#xff1a; 克隆仓库&#xff1a; 移动分支&#xff1a; 创建自己的分支&#xff1a; 创建id.md文档&#xff0c;…...

WordPress 中最佳的维护服务:入门级用户指南

如果你是WordPress网站管理员&#xff0c;一定知道网站维护既耗时又复杂。然而&#xff0c;保持网站的正常运行和安全却至关重要。为了让你轻松应对这个挑战&#xff0c;我们总结了一些适合新手和小型网站的维护服务。本文将介绍两款适合初学者的维护服务&#xff1a;FixMySite…...

前端使用Luckysheet把返回的base64或二进制文件流格式,实现xlsx文件预览

xlsx文件预览 Luckysheet是什么&#xff1f;代码实现xlsx文件预览引入luckysheet的相关依赖安装luckyexcel指定一个表格容器实现逻辑 Luckysheet是什么&#xff1f; Luckysheet &#xff0c;一款纯前端类似excel的在线表格&#xff0c;功能强大、配置简单、完全开源。 Luckys…...

腾讯混元宣布大语言模型和3D模型正式开源

腾讯混元大模型正在加快开源步伐。 11月5日&#xff0c;腾讯混元宣布最新的MoE模型“混元Large“以及混元3D生成大模型“ Hunyuan3D-1.0”正式开源&#xff0c;支持企业及开发者精调、部署等不同场景的使用需求&#xff0c;可在HuggingFace、Github等技术社区直接下载&#xff…...

提示工程指南 笔记

诸神缄默不语-个人CSDN博文目录 课程网站&#xff1a;提示工程指南 | Prompt Engineering Guide 原版是英文&#xff1a;https://www.promptingguide.ai/ 特别基础的内容我就不写了&#xff0c;只写一些值得记录的内容。 文章目录 1. 常用术语&#xff08;LLM特供版&#xff…...

WordPress站点网站名称、logo设置

WordPress网站名称设置 后台打开查看站点自定义设置 点击网站名称修改 上传logo和站点图标...

本地缓存与 Redis:为什么我们仍然需要本地缓存?

文章目录 本地缓存与 Redis&#xff1a;为何仍需本地缓存&#xff1f;为什么需要本地缓存&#xff1f;多级缓存架构多级缓存的实现 本地缓存的实现方式使用 cachetools 实现 LRUCache使用 diskcache 实现持久化缓存 缓存装饰器实现进一步优化&#xff1a;缓存失效与更新 小结 好…...

要在微信小程序中让一个 `view` 元素内部的文字水平垂直居中,可以使用 Flexbox 布局

文章目录 主要特点&#xff1a;基本用法&#xff1a;常用属性&#xff1a; 要在微信小程序中让一个 view 元素内部的文字水平垂直居中&#xff0c;可以使用 Flexbox 布局。以下是如何设置样式的示例&#xff1a; .scan-button {display: flex; /* 启用 Flexbox 布局 */justify…...

图像超分辨率、DPSRGAN

图像超分辨率&#xff08;Image Super-Resolution, ISR&#xff09;是一种通过增加图像的分辨率来提高其细节和清晰度的技术。这项技术在多个领域都有广泛的应用&#xff0c;比如视频监控、医学诊断、遥感应用等。根据搜索结果&#xff0c;图像超分辨率算法主要可以分为以下几类…...

124.WEB渗透测试-信息收集-ARL(15)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;123.WEB渗透测试-信息收集-ARL&#xff08;14&#xff09; 点击fofa任务下发&#xff08…...

@Async注解提升Spring Boot项目中API接口并发能力

文章目录 同步调用异步调用1: 启用异步支持2: 修改 Task 类异步回调基本概念使用 Future<String>使用 CompletableFuture<String>Future<String> 和 CompletableFuture<String>区别1. 基本概念2. 主要区别同步调用 同步调用是最直接的调用方式,调用方…...

SpringBoot集成Flink-CDC

Flink CDC CDC相关介绍 CDC是什么? CDC是Change Data Capture(变更数据获取)的简称。核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数据表的插入、更新以及删除等&#xff09;&#xff0c;将这些变更按发生的顺序完整记录下来&#xff0c;写入到MQ以…...

SQL报错注入检测方法与攻击方法

报错注入 即是注入检测方法&#xff0c;又是注入读取数据的方法 攻击者在判断一个参数是否存在SQL注入漏洞时&#xff0c;会拼接单引号&#xff0c;反斜杠字符&#xff0c;如果显示语法报错&#xff0c;证明这个位置具有SQL注入漏洞&#xff0c;也可以通过整数溢出来判断&…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...