Asio tcp异步例子

本文深入探讨了Asio库的特性和应用,包括其在跨平台网络编程中的优势,如简单易用、支持同步与异步开发。通过具体示例,展示了如何使用Asio实现聊天室功能,涵盖客户端与服务器端的通信流程,以及关键函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是asio?
Asio是一个用于网络底层I / O编程的跨平台C ++开发的网络编程库,支持同步与异步的网络开发。
2.asio有哪些优点?
简单易用、跨平台、可以用于大型项目中。
3.Asio的io_service作用?
io_service实例同底层操作系统的IO服务进行交互,是asio框架中的调度器,所有异步io事件都是通过它来分发处理的。Io_service提供了两个方法post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。Io_service是完全线程安全的队列

4.以下asio常用的函数?
async_connect(endpoint)://这个函数用异步的方式连接到一个地址。
async_accept(socket,accept_handler) //接收新客户端连接。
read(stream, buffer [, extra options])//同步读取方法。
async_read(stream, buffer [, extra options], handler)//异步读取方法。
write(stream, buffer [, extra options]) //同步发送。
async_write(stream, buffer [, extra options], handler) //异步发送。

Asio聊天室例子:
服务器端:

//chat_message.h
#ifndef CHAT_MESSAGE_HPP
#define CHAT_MESSAGE_HPP
#include "Header.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include "stdafx.h"

class chat_message {
public:
  enum { header_length = sizeof(Header) };
  enum { max_body_length = 512 };
  
chat_message(){}
  const char *data() const { return data_; }
  char *data() { return data_; }
  
  std::size_t length() const { return header_length + m_header.bodySize; }
  const char *body() const { return data_ + header_length; }
  char *body() { return data_ + header_length; }
  int type() const { return m_header.type; }

  std::size_t body_length() const { return m_header.bodySize; }
  void setMessage(int messageType, const void *buffer, size_t bufferSize) {
    assert(bufferSize <= max_body_length);
        m_header.bodySize = bufferSize;
        m_header.type = messageType;
        std::memcpy(body(), buffer, bufferSize);
        std::memcpy(data(), &m_header, sizeof(m_header));
  }
  void setMessage(int messageType, const std::string& buffer) {
        setMessage(messageType, buffer.data(), buffer.size());
  }

  bool decode_header() {
    std::memcpy(&m_header, data(), header_length);
    if (m_header.bodySize > max_body_length) {
      std::cout << "body size " << m_header.bodySize << " " << m_header.type
                << std::endl;
      return false;
        }
    return true;
  }
private:
  char data_[header_length + max_body_length];
    Header m_header;
};

#endif 

//Header.h

#ifndef FND_STRUCT_HEADER_H
#define FND_STRUCT_HEADER_H
#include <string>
struct Header{
    int bodySize;
    int type;
};
enum MessageType
{
    MT_BIND_NAME = 1,
    MT_CHAT_INFO = 2, 
    MT_ROOM_INFO = 3, 

};
struct BindName{
    char name[32];
    int nameLen;
};
struct ChatInformation {
   char information[256];
   int infoLen;
};
struct RoomInformation {
    BindName name;
    ChatInformation chat;
};
bool parseMessage(const std::string &input, int *type, std::string &outbuffer);
#endif

//Header.cpp
#include "stdafx.h"
#include "Header.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
bool parseMessage(const std::string &input, int *type, std::string &outbuffer) {
  auto pos = input.find_first_of(" ");
  if (pos == std::string::npos)
    return false;
  if (pos == 0)
    return false;
  auto command = input.substr(0, pos);
  if (command == "BindName") {
    std::string name = input.substr(pos + 1);
    if (name.size() > 32)
      return false;
    if (type)
      *type = MT_BIND_NAME;
    BindName bindInfo;
    bindInfo.nameLen = name.size();
    std::memcpy(&(bindInfo.name), name.data(), name.size());
    auto buffer = reinterpret_cast<const char *>(&bindInfo);
    outbuffer.assign(buffer, buffer + sizeof(bindInfo));
    return true;
  } else if (command == "Chat") {
    std::string chat = input.substr(pos + 1);
    if (chat.size() > 256)
      return false;
    ChatInformation info;
    info.infoLen = chat.size();
    std::memcpy(&(info.information), chat.data(), chat.size());
    auto buffer = reinterpret_cast<const char *>(&info);
    outbuffer.assign(buffer, buffer + sizeof(info));
    if (type)
      *type = MT_CHAT_INFO;
    return true;
  }
  return false;
}
//chat.cpp
#include "chat_message.h"
#include <asio.hpp>
#include <chrono>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <thread>
#include <utility>
#include <mutex>
#include <cstdlib>
#include "stdafx.h"

using boost::asio::ip::tcp;
typedef std::deque<chat_message> chat_message_queue;
std::chrono::system_clock::time_point base;
class chat_session;
typedef std::shared_ptr<chat_session> chat_session_ptr;
class chat_room {
public:
    chat_room(boost::asio::io_service& io_service) : m_strand(io_service) {}
public:
    void join(chat_session_ptr);
    void leave(chat_session_ptr);
    void deliver(const chat_message&);
private:
    boost::asio::io_service::strand m_strand;//strand提供串行执行, 能够保证线程安全, 同时被post或dispatch的方法, 不会被并发的执行. 
    
    std::set<chat_session_ptr> participants_;
    enum { max_recent_msgs = 100 };
    chat_message_queue recent_msgs_;
};

class chat_session : public std::enable_shared_from_this<chat_session> {
public:
    chat_session(tcp::socket socket, chat_room &room)
        : socket_(std::move(socket)),room_(room),
          m_strand(socket_.get_io_service()){}

    void start() {
     room_.join(shared_from_this()); //加入房间
     do_read_header();//读取数据包头
    }
    void deliver(const chat_message &msg){
        m_strand.post([this,msg]{
            bool write_in_progress = !write_msgs_.empty();
            write_msgs_.push_back(msg);
            if (!write_in_progress)
            {
                do_write();
            }
        });
    }

private:
    void do_read_header(){
      auto self(shared_from_this());
      boost::asio::async_read(
          socket_,
          boost::asio::buffer(read_msg_.data(),chat_message::header_length), //读取头数据8个字节
          m_strand.wrap(
          [this,self](boost::system::error_code ec, std::size_t){
              if ( !ec && read_msg_.decode_header()){ 
                 do_read_body();//合法的头部的话,进行内容的读取。
              } else {
                  std::cout << "player leave the room\n";
                  room_.leave(shared_from_this());
              }
         }));
    }

    void do_read_body() {
        auto self(shared_from_this());
        boost::asio::async_read(
            socket_,
            boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),//内容的读取,async_read相当于读取缓存数据,按长度一次读取大小多少,直到读取完成。
            m_strand.wrap(
            [this,self](boost::system::error_code ec, std::size_t) {
              if (!ec) {
                handleMessage();
                do_read_header();
              } else {
                  room_.leave(shared_from_this());
              }
            }));
    }

    void handleMessage() {
        auto n = std::chrono::system_clock::now() - base;
        std::cout << "i'm in " << std::this_thread::get_id() << " time "
            << std::chrono::duration_cast<std::chrono::milliseconds>(n).count() << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(3));
    if (read_msg_.type() == MT_BIND_NAME) {//设定昵称
            const BindName* bind = reinterpret_cast<const BindName*>(read_msg_.body());
            m_name.assign(bind->name, bind->name + bind->nameLen);
                
    } else if (read_msg_.type() == MT_CHAT_INFO) {
            const ChatInformation* chat = reinterpret_cast<const ChatInformation*>(read_msg_.body());
            m_chatInformation.assign(chat->information, chat->information + chat->infoLen);
            auto rinfo = buildRoomInfo();
            chat_message msg;
            msg.setMessage(MT_ROOM_INFO,&rinfo, sizeof(rinfo));
            room_.deliver(msg); //对当前房间发送消息

    } else {
 
    }
  }

    void do_write() { //发送数据
    auto self(shared_from_this());
    boost::asio::async_write(
        socket_, boost::asio::buffer(write_msgs_.front().data(),
                                     write_msgs_.front().length()),
                m_strand.wrap(
        [this, self](boost::system::error_code ec, std::size_t) {
          if (!ec) {
            write_msgs_.pop_front();
            if (!write_msgs_.empty()) {
              do_write();
            }
          } else {
            room_.leave(shared_from_this());
          }
        }));
  }

    tcp::socket socket_;
    chat_room &room_;
    chat_message read_msg_;
    chat_message_queue write_msgs_;
    std::string m_name;
    std::string m_chatInformation;
    boost::asio::io_service::strand m_strand;
    RoomInformation buildRoomInfo() const {
        RoomInformation info;
        info.name.nameLen = m_name.size();
        std::memcpy(info.name.name, m_name.data(), m_name.size());
        info.chat.infoLen = m_chatInformation.size();
        std::memcpy(info.chat.information, m_chatInformation.data(),
                m_chatInformation.size());
        return info;
    }
};

//加入房间
 void chat_room::join(chat_session_ptr participant) {
        m_strand.post([this, participant]{
                participants_.insert(participant);
                for (const auto& msg : recent_msgs_)
                participant->deliver(msg); //对所有端广播
                });
  }

 //离开房间
  void chat_room::leave(chat_session_ptr participant) {
        m_strand.post([this,participant]{
    participants_.erase(participant);});
  }

  void chat_room::deliver(const chat_message &msg) {
    m_strand.post([this, msg]{
    recent_msgs_.push_back(msg);
    while (recent_msgs_.size() > max_recent_msgs)
      recent_msgs_.pop_front();

    for (auto& participant : participants_)
      participant->deliver(msg);
        });
  }

 class chat_server {
public:
  chat_server(boost::asio::io_service &io_service,
              const tcp::endpoint &endpoint)
      : acceptor_(io_service, endpoint), socket_(io_service), room_(io_service) {
    do_accept();
  }

private:
  void do_accept() {
    acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
      if (!ec) {
        auto session =
            std::make_shared<chat_session>(std::move(socket_), room_);
        session->start();//新客户端开始接收数据包
      }

      do_accept(); //创建新连接进行等待
    });
  }

  tcp::acceptor acceptor_;
  tcp::socket socket_;
  chat_room room_;
};



int _tmain(int argc, char *argv[])
{
    try {

        base = std::chrono::system_clock::now();

        boost::asio::io_service io_service;
        std::list<chat_server> servers;
        tcp::endpoint endpoint(tcp::v4(), 9000);
        servers.emplace_back(io_service, endpoint);
        
        std::vector<std::thread> threadGroup;
        for(int i = 0; i < 5; ++i) {
            threadGroup.emplace_back([&io_service, i]{
                    std::cout << i << " name is " << std::this_thread::get_id() << std::endl;
                    io_service.run();});
        }
        io_service.run();
        for(auto& v : threadGroup) v.join();
  } catch (std::exception &e) {
        std::cout << "Exception: " << e.what();
  }
    return 0;
}

客户端:

//client.cpp

#include "chat_message.h"
#include <asio.hpp>
#include <chrono>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <thread>
#include <utility>
#include <mutex>
#include <cstdlib>
#include "stdafx.h"

using boost::asio::ip::tcp;
typedef std::deque<chat_message> chat_message_queue;
class chat_client {
public:
  chat_client(boost::asio::io_service &io_service,
              tcp::resolver::iterator endpoint_iterator)
      : io_service_(io_service), socket_(io_service) {
    do_connect(endpoint_iterator);
  }

  void write(const chat_message &msg) {
    io_service_.post([this, msg]() {
      bool write_in_progress = !write_msgs_.empty();
      write_msgs_.push_back(msg);
      if (!write_in_progress) {
        do_write();
      }
    });
  }
  void close() {
    io_service_.post([this]() { socket_.close(); });
  }

private:
  void do_connect(tcp::resolver::iterator endpoint_iterator) {
    boost::asio::async_connect(
        socket_, endpoint_iterator,
        [this](boost::system::error_code ec, tcp::resolver::iterator) {
          if (!ec) {
            do_read_header();
          }
        });
  }
  void do_read_header() {
    boost::asio::async_read(
        socket_,
        boost::asio::buffer(read_msg_.data(), chat_message::header_length),
        [this](boost::system::error_code ec, std::size_t /*length*/) {
          if (!ec && read_msg_.decode_header()) {
            do_read_body();
          } else {
            socket_.close();
          }
        });
  }

  void do_read_body() {
    boost::asio::async_read(
        socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
        [this](boost::system::error_code ec, std::size_t /*length*/) {
          if (!ec) {
            if (read_msg_.body_length() == sizeof(RoomInformation) &&
                            read_msg_.type() == MT_ROOM_INFO) {
              const RoomInformation *info =
                  reinterpret_cast<const RoomInformation *>(read_msg_.body());
              std::cout << "client: '";
                            assert(info->name.nameLen <= sizeof(info->name.name));
              std::cout.write(info->name.name, info->name.nameLen);
              std::cout << "' says '";
                            assert(info->chat.infoLen <= sizeof(info->chat.information));
              std::cout.write(info->chat.information, info->chat.infoLen);
              std::cout << "'\n";
            }
            do_read_header();
          } else {
            socket_.close();
          }
        });
  }

  void do_write() {
    boost::asio::async_write(
        socket_, boost::asio::buffer(write_msgs_.front().data(),
                                     write_msgs_.front().length()),
        [this](boost::system::error_code ec, std::size_t /*length*/) {
          if (!ec) {
            write_msgs_.pop_front();
            if (!write_msgs_.empty()) {
              do_write();
            }
          } else {
            socket_.close();
          }
        });
  }

private:
  boost::asio::io_service &io_service_;
  tcp::socket socket_;
  chat_message read_msg_;
  chat_message_queue write_msgs_;
};
int _tmain(int argc, char* argv[])
{
try {
  
    boost::asio::io_service io_service;
    tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::resolver::query query("localhost", "9000");
    auto endpoint_iterator = resolver.resolve(query);
    chat_client c(io_service, endpoint_iterator);

    std::thread t([&io_service]() { io_service.run(); });

    char line[chat_message::max_body_length + 1];
        // ctrl-d
    while (std::cin.getline(line, chat_message::max_body_length + 1)) {
      chat_message msg;
            auto type = 0;
            std::string input(line, line + std::strlen(line));
            std::string output;
            if(parseMessage(input, &type, output)) {
                msg.setMessage(type, output.data(), output.size());
                c.write(msg);
                std::cout << "write message for server " << output.size() << std::endl;
            }
    }

    c.close();
    t.join();
  } catch (std::exception &e) {
    std::cerr << "Exception: " << e.what() << "\n";
  }
    return 0;
}

运行结果:

 

4121383-19c8107568900429.png

QQ图片20181127135440.png

参考链接
http://www.cnblogs.com/zhiranok/archive/2011/09/04/boost_asio_io_service_CPP.html

<think>我们正在讨论Boost.AsioTCP异步通信实现。根据引用[2],Boost.Asio实现异步TCP/IP通信的核心是io_service和异步操作的回调机制。用户提供的引用[1]是一个同步TCP客户端的例子,但用户明确询问的是异步通信的实现方法。因此,我们需要展示一个异步TCP服务器和客户端的实现框架。关键点包括:1.使用io_context(io_service的新名称)作为I/O执行上下文。2.定义异步操作(如异步连接、异步读写)并使用回调函数处理完成事件。3.调用io_context::run()来启动事件循环。我们将分别实现一个异步TCP服务器和一个异步TCP客户端。注意:由于代码较长,我们将展示关键部分,并尽量保持简洁。异步TCP服务器:-监听连接-接受连接(异步)-在连接接受后,异步读取客户端数据-异步写入数据异步TCP客户端:-异步连接-连接成功后异步写入数据-然后异步读取响应步骤:服务器端:1.创建acceptor对象来监听连接。2.定义一个处理新连接的函数(start_accept),并在其中异步等待连接(async_accept)。3.当有新连接时,创建一个会话(例如,一个负责该连接通信的类)并开始异步读取。4.在会话类中,实现异步读写操作链。客户端端:1.创建socket并异步连接。2.在连接回调中启动异步写操作。3.在写操作回调中启动异步读操作。由于代码较长,我们将展示关键部分。注意:在实际应用中,需要管理对象的生命周期(例如,使用shared_from_this()如果使用shared_ptr管理会话)。下面是一个简化的异步TCP服务器实现:</think>### Boost.Asio TCP 异步通信实现方法 Boost.Asio异步通信核心是**非阻塞I/O + 回调机制**,通过 `io_context` 事件循环驱动,实现高性能网络通信。以下是关键实现步骤和代码示例: #### 一、异步通信架构 ```mermaid graph LR A[应用程序] -->|发起异步操作| B(io_context) B -->|委托操作系统| C[内核I/O] C -->|操作完成通知| B B -->|回调队列| D[回调函数] D -->|处理结果| A ``` #### 二、异步服务器实现 ```cpp #include <boost/asio.hpp> using namespace boost::asio; class AsyncServer { public: AsyncServer(io_context& io, short port) : acceptor_(io, ip::tcp::endpoint(ip::tcp::v4(), port)) { start_accept(); } private: void start_accept() { // 创建新socket并异步等待连接 auto new_sock = std::make_shared<ip::tcp::socket>(acceptor_.get_executor()); acceptor_.async_accept(*new_sock, [this, new_sock](const boost::system::error_code& ec) { if (!ec) { // 连接建立后启动会话 start_session(new_sock); } start_accept(); // 继续监听新连接 }); } void start_session(std::shared_ptr<ip::tcp::socket> sock) { auto buf = std::make_shared<std::array<char, 1024>>(); // 异步读取数据 sock->async_read_some(boost::asio::buffer(*buf), [this, sock, buf](const boost::system::error_code& ec, size_t len) { if (!ec) { // 处理数据(示例:原样回传) async_write(*sock, boost::asio::buffer(buf->data(), len), [sock](auto ec, auto) { if(ec) sock->close(); }); } start_session(sock); // 继续读取下一轮数据 }); } ip::tcp::acceptor acceptor_; }; int main() { io_context io; AsyncServer server(io, 56789); io.run(); // 启动事件循环[^2] } ``` #### 三、异步客户端实现 ```cpp void async_client() { io_context io; ip::tcp::socket sock(io); ip::tcp::endpoint ed(ip::address::from_string("127.0.0.1"), 56789); // 异步连接 sock.async_connect(ed, [&](const boost::system::error_code& ec) { if (!ec) { auto buf = std::make_shared<std::string>("Hello Server"); // 异步发送数据 async_write(sock, boost::asio::buffer(*buf), [buf](auto ec, auto) {}); // 异步接收响应 auto recv_buf = std::make_shared<std::array<char, 1024>>(); sock.async_read_some(boost::asio::buffer(*recv_buf), [recv_buf](auto ec, size_t len) { std::cout << "Received: " << std::string(recv_buf->data(), len); }); } }); io.run(); } ``` #### 四、关键机制解析 1. **异步操作链** - 每个异步操作触发回调,回调中启动下一个操作 - 示例:`async_connect → async_write → async_read_some` 2. **生命周期管理** - 使用 `shared_ptr` 管理 socket 和缓冲区 - 确保对象在回调期间保持有效 3. **事件循环** - `io_context::run()` 阻塞等待所有异步操作完成 - 单线程可处理数千并发连接(通过 `io_context::poll()` 实现非阻塞轮询) 4. **错误处理** ```cpp sock.async_read_some(..., [](const boost::system::error_code& ec, ...) { if (ec == boost::asio::error::eof) { // 连接正常关闭 } else if (ec) { // 错误处理 } }); ``` #### 五、性能优化技巧 1. **多线程运行io_context** ```cpp io_context io; // 创建4个工作线程 std::vector<std::thread> threads; for(int i=0; i<4; ++i) threads.emplace_back([&] { io.run(); }); ``` 2. **内存池管理** - 预分配缓冲区减少动态内存分配 3. **零拷贝技术** - 使用 `boost::asio::const_buffer` 避免数据复制 > **注意**:异步编程需遵循**禁止阻塞原则**,所有耗时操作必须异步化,否则会阻塞事件循环[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值