简单的协程通信

77 阅读3分钟

服务端:

// Coroutine.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<boost/asio/co_spawn.hpp>//包含启动协程的函数
#include<boost/asio/detached.hpp>//
#include<boost/asio/io_context.hpp>//协程调度需要执行器,这个包含一个执行器
#include<boost/asio/ip/tcp.hpp>
#include<boost/asio/signal_set.hpp>//优雅退出信号
#include<boost/asio/write.hpp>//写数据要用到发送头文件
#include <iostream>

using boost::asio::ip::tcp;
using boost::asio::awaitable;//可等待协程作用域
using boost::asio::co_spawn;//启动协程的关键字
using boost::asio::detached;
using boost::asio::use_awaitable;//使协程可以等待
namespace this_coro = boost::asio::this_coro;//返回当前协程所执行的环境

awaitable<void> echo(tcp::socket socket) {
    try {
        char data[1024];
        for (;;) {
            std::size_t n= co_await socket.async_read_some(boost::asio::buffer(data), use_awaitable);
            
            co_await async_write(socket, boost::asio::buffer(data, n), use_awaitable);
            //让协程等待这个异步函数完成
        }
    }
    catch (std::exception& e) {
        std::cout << "exception is" << e.what() << std::endl;
    }
}
awaitable<void> listener() {//将这个函数设置为可等待,协程就可以直接调用这个函数了
    auto executor = co_await this_coro::executor;
    //通过co_await的方式获取协程的调度器,异步的找这个调度器,如果找不到就把它挂起
    //把使用权交给主线程中其他协程,直到能够捕获再继续往下走
    tcp::acceptor acceptor(executor, { tcp::v4(),10086 });//让接受操作在协程内部执行
    for (;;) {//来一个连接就创建一个连接
        tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
        //参数告诉asio把该异步函数变成协程能够使用的函数并通过co_await用协程的方让协程挂起去等待
        // 没等到连接将资源归还主线程,可能去执行其他协程
        // 等到连接后协程被唤醒,才继续往下走
        co_spawn(executor, echo(std::move(socket)), detached);//在协程里面再启动一个协程,
    }
}


int main()
{
    try {
        boost::asio::io_context io_context(1);
        boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
        //将信号绑定到上下文上,绑定的信号有ctralC,中断等
        signals.async_wait([&](auto, auto) {
            io_context.stop();
            });//lambda表达式用来指示捕获信号后干什么,处理几个信号传几个参数

        co_spawn(io_context, listener(), detached);//通过co_spawn启动一个协程
        //(协程调度器,也就是该协程由谁调度;协程要执行的任务;该协程启动方式:分离主线程
        // 
        //co_spawn(io_context, listener(), detached);先启动上面的协程,如果上面的被挂起就到这个协程
        io_context.run();//iocontext没有绑定任何异步事件的时候run会直接返回
    }
    catch (std::exception& e) {
        std::cout << "exception is" << e.what() << std::endl;
    }
}


客户端

#include <iostream>
#include<boost/asio.hpp>
using namespace std;
using namespace boost::asio::ip;
const int MAX_LENGTH = 1024;


int main()
{
    try {
        boost::asio::io_context ioc;
        tcp::endpoint remote_ep(address::from_string("127.0.0.1"), 10086);
        tcp::socket sock(ioc);
        boost::system::error_code error = boost::asio::error::host_not_found;
        sock.connect(remote_ep, error);
        if (error) {
            cout << "connection failed,code is" << error.value() << "error msg is" << error.message() << std::endl;

            return 0;
        }
        std::cout << "enter message";
        char request[MAX_LENGTH];
        std::cin.getline(request, MAX_LENGTH);
        size_t request_length = strlen(request);
        boost::asio::write(sock, boost::asio::buffer(request, request_length));

        char reply[MAX_LENGTH];
        size_t reply_length = boost::asio::read(sock, boost::asio::buffer(reply, request_length));
        cout << "reply is" << string(reply, reply_length) << endl;
        getchar();

    }
    catch (std::exception& e) {
        std::cerr << "Exception is" << e.what() << std::endl;
    }
}