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

Boost.Asio 同步读写及客户端 - 服务器实现详解

Boost.Asio 同步读写及客户端 - 服务器实现详解

参考文献

  1. Boost.Asio 官方文档
  2. 学习资料来源: 参考网址

一、引言

Boost.Asio作为一个强大的跨平台网络编程库,为开发者提供了丰富的网络操作接口。在之前的学习中,我们已接触到其同步读写的API函数,本文将在此基础上,深入探讨如何运用这些API构建一个完整且能实际运行的客户端与服务器示例,且双方均采用阻塞式的同步读写方式来实现通信。

二、客户端设计

  1. 设计思路
    • 首要任务是依据服务器的IP地址与端口号构建一个 endpoint,这是后续连接的目标定位信息。
    • 借助 socket 对象,向已确定的 endpoint 发起连接请求,尝试与服务器建立通信链路。
    • 成功连接后,运用同步读写机制,实现向服务器发送数据以及接收服务器响应数据的功能。
  2. 代码剖析
#include <iostream>
#include <boost/asio.hpp>
using namespace std;
using namespace boost::asio::ip;
const int MAX_LENGTH = 1024;int main() {try {// 1. 初始化Boost.Asio的核心对象io_context,它为后续的网络操作提供运行环境boost::asio::io_context ioc;// 2. 构建远程服务器的endpoint,明确通信目标的IP与端口,这里以本地回环地址127.0.0.1及端口10086为例tcp::endpoint remote_ep(address::from_string("127.0.0.1"), 10086);// 3. 创建用于网络通信的socket对象,绑定到之前创建的io_contexttcp::socket sock(ioc);// 4. 向服务器发起连接请求,并通过error_code检查连接结果boost::system::error_code error = boost::asio::error::host_not_found;sock.connect(remote_ep, error);// 若连接失败,输出错误详情并终止程序if (error) {cout << "连接失败,错误代码: " << error.value() << " 错误信息: " << error.message() << endl;return 0;}// 5. 提示用户输入要发送给服务器的消息std::cout << "请输入消息: ";char request[MAX_LENGTH];std::cin.getline(request, MAX_LENGTH);// 6. 计算输入消息的长度,并通过Boost.Asio的write函数将消息发送至服务器size_t request_length = strlen(request);boost::asio::write(sock, boost::asio::buffer(request, request_length));// 7. 准备接收服务器的回复,利用read函数从socket读取数据至reply缓冲区char reply[MAX_LENGTH];size_t reply_length = boost::asio::read(sock,boost::asio::buffer(reply, request_length));// 8. 输出服务器的回复内容std::cout << "服务器回复: ";std::cout.write(reply, reply_length);std::cout << "\n";}catch (std::exception& e) {// 捕获并处理任何可能出现的异常,输出错误信息std::cerr << "发生异常: " << e.what() << endl;}return 0;
}

三、服务器设计

服务器端的设计相对复杂,主要由两个关键函数协同完成工作。

  1. session 函数
    • 功能定位:此函数专门负责处理单个客户端的连接请求。每当服务器监听到有新客户端接入时,便会立即调用该函数,对客户端的数据交互进行管理。
    • 实现逻辑:采用循环结构,持续监听客户端发送的数据。一旦接收到数据,首先检查错误状态,若客户端正常关闭连接,函数能及时察觉并结束循环;若出现其他错误,则抛出异常。对于接收到的有效数据,不仅会在服务器端打印出来源客户端的IP地址以及消息内容,还会将数据原封不动地回传给客户端,实现简单的“echo”功能。
    • 代码详情
void session(std::shared_ptr<tcp::socket> sock) {try {for (;;) {char data[MAX_LENGTH];memset(data, '\0', MAX_LENGTH); // 初始化缓冲区,确保数据干净// 从客户端socket读取数据,同时关注可能出现的错误boost::system::error_code error;size_t length = sock->read_some(boost::asio::buffer(data, MAX_LENGTH), error);// 根据不同的错误情况进行相应处理if (error == boost::asio::error::eof) {std::cout << "连接被客户端关闭" << endl;break;} else if (error) {throw boost::system::system_error(error);}// 打印客户端连接信息及发送的消息std::cout << "收到来自 " << sock->remote_endpoint().address().to_string() << " 的消息" << endl;std::cout << "消息内容: " << data << endl;// 将接收到的消息原样回传给客户端boost::asio::write(*sock, boost::asio::buffer(data, length));}}catch (std::exception& e) {// 捕获并处理线程内出现的异常,输出错误详情std::cerr << "线程中发生异常: " << e.what() << "\n" << std::endl;}
}
  1. server 函数
    • 功能定位:作为服务器的启动与管理核心,负责创建服务器的监听机制,并协调客户端连接的处理流程。
    • 实现逻辑:首先创建一个 acceptor 对象,绑定到指定的IP地址与端口,开始监听客户端的连接请求。进入无限循环后,每当有新客户端连接到来,便创建一个新的 socket 对象用于与该客户端通信,并立即启动一个独立的线程,在线程中调用 session 函数处理与该客户端的交互,同时将线程分离,使其能够独立运行,避免主线程阻塞。
    • 代码详情
void server(boost::asio::io_context& io_context, unsigned short port) {// 创建acceptor,用于监听指定端口的客户端连接tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));for (;;) {// 为新连接创建socket对象std::shared_ptr<tcp::socket> socket(new tcp::socket(io_context));acceptor.accept(*socket); // 接受客户端连接// 为每个连接创建独立线程处理通信,分离线程以独立运行auto t = std::make_shared<std::thread>(session, socket);t->detach(); }
}
  1. 多线程处理优势:通过为每个客户端连接分配独立的线程,并在其中进行读写操作,确保了服务器的 acceptor 能够持续监听新连接,不会因某个连接的阻塞读写操作而陷入停滞,有效提升了服务器的并发处理能力。

四、同步读写的特性剖析

  1. 优点
    • 编程简易性:同步读写模式下,代码逻辑呈现顺序执行的特点,开发者无需处理复杂的异步回调嵌套,编写过程清晰明了,对于初学者或是处理简单网络场景的项目而言,上手难度较低,易于快速实现功能。
    • 维护便利性:由于代码按照线性顺序执行,没有异步操作带来的回调函数分散在各处的问题,程序的逻辑流易于追踪与理解,后续的代码维护与调试工作相对轻松。
  2. 缺点
    • 阻塞隐患:在服务器端,若客户端未能及时发送数据, read 操作将会使线程陷入阻塞状态,白白消耗系统资源,直到有数据可读为止,这在高并发场景下极易引发性能瓶颈。
    • 线程资源受限:鉴于每个连接都需要独立的线程来维持同步读写操作,而操作系统对线程数量存在上限限制(例如Linux系统默认2048个线程),当连接数大量增加时,系统可能无法创建足够的线程,导致新连接无法及时处理。
    • 线程切换成本:大量线程的频繁切换会消耗大量的CPU时间用于上下文保存与恢复,使得系统用于实际业务处理的资源被削减,整体性能受到负面影响。
    • 粘包问题未解决:无论是客户端还是服务器端,当前的同步读写实现都没有考虑到TCP协议在数据传输过程中可能出现的粘包现象,这可能导致接收端无法准确识别消息边界,造成数据解析错误。

五、改进方向展望

为克服同步读写的固有缺陷,引入异步读写模式成为必然选择:

  1. 并发性能飞跃:异步操作允许在等待数据读写完成的过程中,CPU能够转而处理其他任务,避免线程阻塞,从而能够在相同硬件资源下承载更多的客户端连接,大幅提升服务器的并发处理能力。
  2. 全双工通信优势:发送与接收数据的过程相互独立,不再受限于同步模式下的先后顺序,能够更好地适应复杂多变的通信需求,例如实时双向数据交互的场景。
  3. 粘包处理机制完善:可以通过在数据传输中添加特定的消息分隔符,或者在数据头部嵌入长度标识符等方式,让接收端能够精准地识别每条消息的边界,确保数据的完整性与准确性,提升系统的可靠性。

相关文章:

Boost.Asio 同步读写及客户端 - 服务器实现详解

Boost.Asio 同步读写及客户端 - 服务器实现详解 参考文献 Boost.Asio 官方文档学习资料来源: 参考网址 一、引言 Boost.Asio作为一个强大的跨平台网络编程库&#xff0c;为开发者提供了丰富的网络操作接口。在之前的学习中&#xff0c;我们已接触到其同步读写的API函数&…...

LeetCode 3019.按键变更的次数:遍历(转小写)

【LetMeFly】3019.按键变更的次数&#xff1a;遍历&#xff08;转小写&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/number-of-changing-keys/ 给你一个下标从 0 开始的字符串 s &#xff0c;该字符串由用户输入。按键变更的定义是&#xff1a;使用与…...

ETCD未授权测试

一、测试环境搭建 首先拉取etcd镜像 docker pull quay.io/coreos/etcd:v3.3.1 # 查看镜像 docker images创建自定义网络 docker network create --driver bridge --subnet172.16.1.0/16 --gateway172.16.1.1 mynet # 查看网络 docker network ls创建etcd节点 节点1: docke…...

【Hystrix-1】Hystrix:构建弹性分布式系统的基石

在分布式系统的广袤星图中&#xff0c;服务间的调用如同星辰间的引力&#xff0c;维系着系统的运转。然而&#xff0c;这种依赖关系也如同达摩克利斯之剑&#xff0c;一旦某个服务出现故障&#xff0c;便可能引发连锁反应&#xff0c;导致整个系统的崩塌。Hystrix&#xff0c;如…...

【超详细】MIT 液态神经网络(LNNs)——深度学习新动向

✅作者简介:双一流博士,人工智能领域学习者,深耕机器学习,交叉学科实践者。已发表SCI1/区top论文10+,授权专利4件,公开10+。可提供专利思路和指导,提供科研小工具,分享科研经验,欢迎交流! 📌个人主页: https://blog.csdn.net/allein_STR?spm=1011.2559.3001.5343…...

Git最便捷的迁移方式

#当公司要求git需要迁移时&#xff0c;你是不是感觉到束手无策。今天带来给大家最快&#xff0c;最便捷的迁移方式 这个命令是用于重命名git仓库中的远程仓库名。在这个命令中&#xff0c;我们将远程仓库的名字从"origin"改为"old-origin"。 git remote …...

2024AAAI SCTNet论文阅读笔记

文章目录 SCTNet: Single-Branch CNN with Transformer Semantic Information for Real-Time Segmentation摘要背景创新点方法Conv-Former Block卷积注意力机制前馈网络FFN 语义信息对齐模块主干特征对齐共享解码头对齐 总体架构backbone解码器头 对齐损失 实验SOTA效果对比Cit…...

Laravel操作ElasticSearch

在Laravel项目中操作ElasticSearch可以通过以下步骤来实现&#xff0c;通常会借助相应的ElasticSearch客户端扩展包。 ### 安装ElasticSearch客户端包 在Laravel项目中&#xff0c;常用的是 elasticsearch/elasticsearch 这个PHP客户端库来与ElasticSearch进行交互&#xff0c…...

江科大STM32入门——SPI通信笔记总结

wx&#xff1a;嵌入式工程师成长日记 &#xff08;一&#xff09;简介 四根通信线&#xff1a;SCK、MOSI、MISO、SS(片选信号) 同步&#xff08;同步通信是一种通信模式&#xff0c;在这种模式下&#xff0c;发送方和接收方在同一时刻进行数据传输。&#xff09;&#xff0c;全…...

微信小程序map组件所有markers展示在视野范围内

注意&#xff1a;使用include-points属性不生效&#xff0c;要通过createMapContext实现 <template><view class"map-box"><map id"map" class"map" :markers"markers" :enable-traffic"true" :enable-poi&…...

深度解析 tanh ⁡ tanh 激活函数

1. 引言 在现代深度学习中&#xff0c;激活函数&#xff08;Activation Function&#xff09;是神经网络的核心组件之一。它的主要作用是引入非线性&#xff0c;从而使神经网络能够学习和表示复杂的非线性关系。如果没有激活函数&#xff0c;神经网络的输出将只是输入的线性组…...

嵌入式入门Day38

C Day1 第一个C程序C中的输入输出输出操作coutcin练习 命名空间使用方法自定义命名空间冲突问题 C对字符串的扩充C风格字符串的使用定义以及初始化C风格字符串与C风格字符串的转换C风格的字符串的关系运算常用的成员变量输入方法 布尔类型C对堆区空间使用的扩充作业 第一个C程序…...

探索Rancher服务发现机制:容器世界的“导航仪”

《探索Rancher服务发现机制&#xff1a;容器世界的“导航仪”》 在当今容器化技术蓬勃发展的时代&#xff0c;容器的大规模部署和微服务架构的广泛应用使得服务之间的相互发现与通信变得至关重要。Rancher作为一款功能强大的容器管理平台&#xff0c;其服务发现机制宛如一座无…...

【ROS2】Qt事件循环和ROS2订阅机制一起使用有什么注意事项?

1、简述 Qt的事件循环和ROS订阅回调函数都可能在阻塞函数中运行, 例如:Qt的QApplication::exec() 和 ROS的rclcpp::spin() 两个阻塞函数不能在同一个线程中使用,如果使用不当,会造成Qt不处理事件或者ROS2不处理订阅的回调函数。 2、多线程 一般 QApplication::exec() 运…...

donet (MVC)webAPI 的接受json 的操作

直接用对象来进行接收&#xff0c;这个方法还不错的。 public class BangdingWeiguiJiluController : ApiController{/// <summary>/// Json数据录入错误信息/// </summary>/// <param name"WeiguiInfos"></param>/// <returns></r…...

Qt 界面外观

一、前言 1、 一个完善的应用程序&#xff0c;不仅应该有实用的功能&#xff0c;还要有一个漂亮的外观&#xff0c;这样才能使应用程序更加友好&#xff0c;更加吸引用户。 2、 作为一个跨平台的UI开发框架&#xff0c;Qt提供了强大而灵活的界面外观设计机制。 3、 本篇会讲解&…...

aws(学习笔记第二十二课) 复杂的lambda应用程序(python zip打包)

aws(学习笔记第二十二课) 开发复杂的lambda应用程序(python的zip包) 学习内容&#xff1a; 练习使用CloudShell开发复杂lambda应用程序(python) 1. 练习使用CloudShell CloudShell使用背景 复杂的python的lambda程序会有许多依赖的包&#xff0c;如果不提前准备好这些python的…...

HTML课堂之搜索工具箱/讲师duluo

目录&#xff1a; 源码在最后 小提示&#xff1a; 1.养成打卡习惯没日多加练习即可提什能力 2.源码在最后&#xff0c;请先看完代码讲解&#xff0c;在尝试自己写&#xff0c;这样容易掌握 3.请勿复制粘贴&#xff0c;因为你没掌握&#xff0c;即使复制粘贴也学不会 课堂重点笔…...

当歌 - RSS 订阅分发平台开发

以下将详细介绍当歌平台的技术架构、功能实现以及相关代码逻辑。 一、项目概述 当歌是一个极简的 RSS 订阅分发平台&#xff0c;旨在为用户提供便捷的 RSS 管理和订阅服务&#xff0c;帮助用户轻松获取和分享最新资讯。 二、技术架构 后端语言&#xff1a;PHP 数据库&#…...

学习threejs,导入wrl格式的模型

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.VRMLLoader wrl模型加…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...