首页 > 其他分享 >asio的同步和异步读写

asio的同步和异步读写

时间:2024-09-22 17:13:16浏览次数:8  
标签:asio 异步 node 读写 send std Session len recv

同步读写的优缺点

缺点:

  • 读写是阻塞的,如果客户端不发送数据的话,服务器就会一直阻塞在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设置为false
    if (_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;    
}

标签:asio,异步,node,读写,send,std,Session,len,recv
From: https://www.cnblogs.com/dwinternet/p/18425532

相关文章

  • C++ 异步 async future 等
    async和future这个和C#的Task有点像。#include<iostream>#include<string>#include<memory>#include<future>#include<thread>usingnamespacestd;intcalculate(){std::this_thread::sleep_for(std::chrono::seconds(2));......
  • 完整的 Redux 工具包 - 异步逻辑(第 -2 部分)
    1。reduxtoolkit中的异步逻辑简介在redux中处理异步逻辑通常涉及大量样板代码,例如创建操作类型、操作创建者和减速器来处理不同的状态(加载、成功、错误)。reduxtoolkit使用createasyncthunk简化了这一过程,它允许您以最少的设置为异步操作定义“thunk”。createasyncthunk......
  • 一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
    前言最近有不少小伙伴在问:.NET有什么值得推荐的网络通信框架?今天大姚给大家分享一个.NET开源、免费(MITLicense)、快速、低延迟的异步套接字服务器和客户端库:NetCoreServer。项目介绍NetCoreServer是一个.NET开源、免费(MITLicense)、快速、低延迟的异步套接字服务器和客户端库。它支......
  • stm32 FLASH闪存(读写内部FLASH&读取芯片ID)
    理论1.FLASH简介STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)(FLASH管理员)可以对程序存储器和选项字节进行擦除和编程读写FLASH的用途:   利用程序存储器的剩余空间来保存掉电不丢失的用户数据    通过在程序中编......
  • 一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
    前言最近有不少小伙伴在问:.NET有什么值得推荐的网络通信框架?今天大姚给大家分享一个.NET开源、免费(MITLicense)、快速、低延迟的异步套接字服务器和客户端库:NetCoreServer。项目介绍NetCoreServer是一个.NET开源、免费(MITLicense)、快速、低延迟的异步套接字服务器和客户端库。......
  • asio的buffer
    ASIO的buffer理解asio的buffer结构任何网络库都有提供buffer的数据结构,这个就是收发数据的缓冲区。asio提供了mutable_buffer和const_buffer这两个结构,他们都是一段连续的空间,首字节存储了后续数据的长度。mutable_buffer用于写服务,const_buffer用于读服务。但是这两个结构都......
  • Java后端中的请求优化:从请求合并到异步处理的实现策略
    Java后端中的请求优化:从请求合并到异步处理的实现策略大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代微服务架构中,后端系统的性能直接影响到用户体验。为了提升系统的响应速度和吞吐量,请求优化成为了重要的关注点。本文将探讨几种常见的请求优......
  • 【Python爬虫系列】_022.异步文件操作aiofiles
    课程推荐我的个人主页:......
  • 为什么 Elixir 在异步处理方面比 Nodejs 更好?
    简单答案:Node.js是单线程的,并拆分该单线程来模拟并发,而Elixir利用Erlang虚拟机BEAM的原生并发和并行性来同时运行进程。下面,我们将更深入地理解这种差异,探索两个关键概念:Node.js事件循环和Elixir的BEAMVM和OTP。这些元素对于理解每种技术如何处理执行异步任务以及这......
  • 10----展讯芯片机型解锁读写分区工具 工具预览与功能解析
         展讯芯片机型工具很少。另外也由于展讯芯片在机型类相对较少。今天的这款工具是展讯芯片专用。工具开发者说明。可以读写分区修改分区   檫除分区等操作。下面我们来看看工具的具体说明与操作解析工具功能选项★★★★★工具开发者说明功能与选项操作与资......