asio的同步和异步读写

news/2024/9/22 17:13:01/文章来源:https://www.cnblogs.com/dwinternet/p/18425532

同步读写的优缺点

缺点:

  • 读写是阻塞的,如果客户端不发送数据的话,服务器就会一直阻塞在read上,导致服务器一直处于等待状态。
  • 一般是通过开辟一个新的线程来服务客户端的请求,但是一个进程可以开辟的线程数是有限的,大约为2048个,在linux环境下可以通过unlimit增加线程数,但是线程过多也会增加切换消耗的资源。
  • 同步一般为应答模式,实际上我们应该将发送和接收单独分开。

优点:

  • 客户端连接数不多,而且服务器并发性不高的场景,可以使用同步读写的方式。
  • 使用同步读写能简化编码难度。

异步写

class Session{
public:void WriteCallBack(const boost::system::error_code& ec, std::size_t bytes_transferred);void WriteToSocket(const std::string &buf);
private:std::queue<std::shared_ptr<MsgNode>> _send_queue;std::shared_ptr<asio::ip::tcp::socket> _socket;bool _send_pending;
};

我们通过维护一个队列和bool变量(其实用原子可能更好)来保证写的顺序性,bool变量表示当前的发送任务是否全部发送完成。

//不能与async_write_some混合使用
void Session::WriteAllToSocket(const std::string& buf) {//插入发送队列_send_queue.emplace(new MsgNode(buf.c_str(), buf.length()));//pending状态说明上一次有未发送完的数据if (_send_pending) {return;}//异步发送数据,因为异步所以不会一下发送完this->_socket->async_send(asio::buffer(buf), std::bind(&Session::WriteAllCallBack, this,std::placeholders::_1, std::placeholders::_2));_send_pending = true;
}
void Session::WriteAllCallBack(const boost::system::error_code& ec, std::size_t bytes_transferred){if (ec.value() != 0) {std::cout << "Error occured! Error code = "<< ec.value()<< ". Message: " << ec.message();return;}//如果发送完,则pop出队首元素_send_queue.pop();//如果队列为空,则说明所有数据都发送完,将pending设置为falseif (_send_queue.empty()) {_send_pending = false;}//如果队列不是空,则继续将队首元素发送if (!_send_queue.empty()) {auto& send_data = _send_queue.front();this->_socket->async_send(asio::buffer(send_data->_msg + send_data->_cur_len, send_data->_total_len - send_data->_cur_len),std::bind(&Session::WriteAllCallBack,this, std::placeholders::_1, std::placeholders::_2));}
}

异步读

class Session {
public:void ReadFromSocket();void ReadCallBack(const boost::system::error_code& ec, std::size_t bytes_transferred);
private:std::shared_ptr<asio::ip::tcp::socket> _socket;std::shared_ptr<MsgNode> _recv_node;bool _recv_pending;
};

_recv_node用来缓存接收的数据,_recv_pending为true表示节点正在接收数据,还未接受完。

//不考虑粘包情况, 先用固定的字节接收
void Session::ReadFromSocket() {if (_recv_pending) {return;}//可以调用构造函数直接构造,但不可用已经构造好的智能指针赋值/*auto _recv_nodez = std::make_unique<MsgNode>(RECVSIZE);_recv_node = _recv_nodez;*/_recv_node = std::make_shared<MsgNode>(RECVSIZE);_socket->async_read_some(asio::buffer(_recv_node->_msg, _recv_node->_total_len), std::bind(&Session::ReadCallBack, this,std::placeholders::_1, std::placeholders::_2));_recv_pending = true;
}
void Session::ReadCallBack(const boost::system::error_code& ec, std::size_t bytes_transferred){_recv_node->_cur_len += bytes_transferred;//没读完继续读if (_recv_node->_cur_len < _recv_node->_total_len) {_socket->async_read_some(asio::buffer(_recv_node->_msg+_recv_node->_cur_len,_recv_node->_total_len - _recv_node->_cur_len), std::bind(&Session::ReadCallBack, this,std::placeholders::_1, std::placeholders::_2));return;}//将数据投递到队列里交给逻辑线程处理,此处略去//如果读完了则将标记置为false_recv_pending = false;//指针置空_recv_node = nullptr;    
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSP2024-24

2A 题意:给定长度为 \(n\) 的非负整数数组 \(a\),求最小的 \(r−l+1\) 满足 \(l≤r,\sum_{i = l}^ra_i\) 是合数。 考虑全是正数的情况,答案一定 \(\le 4\),考虑一下每个数的奇偶性即可。 那么就把所有正数及其位置存下来,使得 \(b_i = a_{p_i}\),暴力检查 \(b\) 中长度为…

放开那代码让我来!——Cursor帮你写代码的奇妙之旅

让我们开门见山:编程很酷,但也很折磨人。那些长时间盯着屏幕,debug无休止的日子,只有程序员懂得它的酸爽。而就在这个编程焦虑的世界中,Cursor横空出世,带着一系列魔法功能,如同你手中的一根智能魔杖,让写代码变得像煮速冻面一样简单。 Cursor,一款基于AI的编程助手,…

Mathtype公式相关:在mathtype中添加任意维数矩阵的方法以及矩阵中省略号的问题;输入空格;输入花体字母;输入空心字母;输入空心数字

一、在mathtype中添加任意维数矩阵的方法以及矩阵中省略号的问题 使用mathtype创建任意维数的矩阵: 打开mathtype后可点击矩阵工具栏,再点击右下角的图形,具体情况如下图所示。点击之后会弹出一个对话框如下图所示,可在行列处输入自己想要的行数和列数。使用此方法创建的矩…

GIS转码的秋招历程与踩坑经历

本文介绍地理信息科学(GIS)专业的2024届应届生,在研三上学期期间,寻找后端研发、软件开发等IT方向工作的非科班转码秋招情况~本文介绍地理信息科学(GIS)专业的2024届应届生,在研三上学期期间,寻找后端研发、软件开发等IT方向工作的非科班转码秋招情况。首先,这篇文章一…

树状数组浅谈

什么是树状数组 树状数组是一种码量小,常数小,支持单点修改和区间查询的数据结构。 树状数组维护的信息和运算需要满足结合律并且可差分 注意gcd和max操作虽然满足结合律,但不可差分,因此不能使用树状数组维护 其实,树状数组能做的,线段树都能做,线段树能做的,树状数组…

Filebeat

Filebeat 简介 Filebeat用于转发和集中日志数据的轻量级传送程序。作为服务器上的代理安装,Filebeat监视指定的位置文件或位置,收集日志事件,并将他们转发到Elasticsearch 或Logstash进行索引。 架构图安装Filebeat 下载并安装 wget https://artifacts.elastic.co/download…

Tarjan算法及其应用 总结+详细讲解+详细代码注释

\(\text{Tarjan}\) 1.引入概念 1.强连通分量 1.定义 在有向图 \(G\) 中,强连通分量就是满足以下条件的 \(G\) 的子图:从任意一点出发,都有到达另一个点的路径。 不存在一个或者几个点,使得这个子图加入这些点后,这个子图还满足上一个性质。为什么要限定”在有向图中“而不…

三级数据库技术笔记

数据库应用系统开发方法 数据库应用系统生命周期 软件工程与软件开发方法 瀑布模型 快速原型模型 螺旋模型 DBAS生命周期 DBAS生命周期:项目规划、需求分析、系统设计、实现与部署、运行与维护 规划与分析 可行性分析:经济可行性、技术可行性、操作可行性、开发方案选择 需求…

洛谷P5683 [CSP-J2019 江西] 道路拆除

立下flag:今天一定AC这道题! 题目意思: 思路: 然而并没有分。。 输出-1,祈求CCF的施舍( 30% 的数据,有 \(s_1 = s_2\) 求 1 号点到 \(s_1\) 最短路,再计算不需要的路径。 SPFA,启动! #include<bits/stdc++.h>using namespace std;const int maxn=3010; const i…

golang 项目引入私有仓库包

场景: 当你多个项目,都需要使用一个或者多个方法,那么可以将公共方法,抽成一个包,进行管理(类似Log模块等)。这时候可以将你的包上传到私有的仓库,其他项目引入该包即可。下面来介绍下,如何引用私有仓库的包。 1. 创建一个新的 Git 标签 假设你已经在你的私有 GitLab …

设计模式之——装饰者模式

前言: 装饰者模式是结构性设计模式之一,其在不必改变类文件及不适用继承的情况下,动态的扩展一个对象的功能。它通过创建一个包装对象(即装饰)来包裹真实的对象。 一.定义 动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。 装饰者模式的…

解决vsc中文乱码

关于vs code使用code runner运行python代码出现中文乱码的解决办法_code runner 运行乱码-CSDN博客 Code Runner插件设置 "set PYTHONIOENCODING=utf8 && python -u"