Boost.asio 网络通信之异步TCP通信

时间:2022-09-08 22:11:57

服务端

  server.h

#pragma once
#include <iostream>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
using namespace boost::asio;


class server
{
public:
    virtual ~server();

    typedef server this_type;
    typedef ip::tcp::acceptor acceptor_type;
    typedef ip::tcp::endpoint endpoint_type;
    typedef ip::tcp::socket socket_type;
    typedef std::shared_ptr<socket_type> sock_ptr;

private:
    io_service m_io;
    acceptor_type m_acceptor;

public:
    server() : m_acceptor(m_io, endpoint_type(ip::tcp::v4(), 6688))
    {
        accept1();
    }

    void run()
    {
        m_io.run();
    }

    void accept()
    {
        sock_ptr sock(new socket_type(m_io));
        m_acceptor.async_accept(*sock, 
            bind(&this_type::accept_handler, this, 
                boost::asio::placeholders::error, sock));    
    }

    //通过lambda表达式来实现bind
    void accept1();

    void accept_handler(const boost::system::error_code& ec, sock_ptr sock);

    void write_handler(const boost::system::error_code& ec)
    {
        std::cout << "send msg complete." << std::endl;
    }

    //未调用
    void write_handler2(const boost::system::error_code& ec, std::size_t n)
    {
        std::cout << "send msg " << n << std::endl;
    }
};

  server.cpp

#include "pch.h"
#include "server.h"


server::~server()
{
}

void server::accept_handler(const boost::system::error_code& ec, sock_ptr sock)
{
    if (ec)
    {
        return;
    }

    std::cout << "client:";
    std::cout << sock->remote_endpoint().address() << std::endl;

    sock->async_write_some(buffer("hello, client. it's from server send you."),
        bind(&this_type::write_handler, this, 
            boost::asio::placeholders::error));

    accept();
}

void server::accept1()
{
    sock_ptr sock(new socket_type(m_io));

    m_acceptor.async_accept(*sock,
        [this, sock](const boost::system::error_code& ec)
    {
        if (ec)
        {
            return;
        }

        sock->async_send(buffer("hello client, this msg generate function using lambda expression."),
            [](const boost::system::error_code&, std::size_t)
        {
            std::cout << "send msg complete." << std::endl;
        }
        );
        accept1();
    }
    );
}

  调用

// TcpSynServer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>

#include "server.h"

int main()
{
    try
    {
        std::cout << "server start." << std::endl;
        server svr;
        svr.run();
    }
    catch (const std::exception& ec)
    {
        std::cout << ec.what() << std::endl;
    }
    getchar();

    std::cout << "Hello World!\n"; 
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门提示: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

客户端

  client.h

#pragma once
#include <iostream>
#include <memory>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/bind.hpp>
using namespace boost::asio;

class client
{
public:
    virtual ~client();

    typedef client this_type;
    typedef ip::tcp::endpoint endpoint_type;
    typedef ip::address address_type;
    typedef ip::tcp::socket socket_type;
    typedef std::shared_ptr<socket_type> sock_ptr;
    typedef std::vector<char> buffer_type;

private:
    io_service m_io;
    buffer_type m_buf;
    endpoint_type m_ep;

public:
    client() : m_buf(100, 0), m_ep(address_type::from_string("127.0.0.1"), 6688)
    {
        start1();
    }

    void run()
    {
        m_io.run();
    }

    void start()
    {
        sock_ptr sock(new socket_type(m_io));
        sock->async_connect(m_ep,
            bind(&this_type::conn_handler, this,
                boost::asio::placeholders::error, sock));
    }

    //使用lambda表达式实现bind
    void start1();


    void conn_handler(const boost::system::error_code& ec, sock_ptr sock);

    void read_handler(const boost::system::error_code& ec, sock_ptr sock)
    {
        if (ec)
        {
            return;
        }
        std::cout << &m_buf[0] << std::endl;

        sock->async_read_some(buffer(m_buf),
            bind(&client::read_handler, this,
                boost::asio::placeholders::error, sock));
    }
};

  client.cpp

#include "pch.h"
#include "client.h"



client::~client()
{
}

void client::conn_handler(const boost::system::error_code& ec, sock_ptr sock)
{
    if(ec)
    {
        return;
    }
    std::cout << "receive from server :" << sock->remote_endpoint().address() << std::endl;

    sock->async_read_some(buffer(m_buf),
        bind(&client::read_handler, this,
            boost::asio::placeholders::error, sock));
}

void client::start1()
{
    sock_ptr sock(new socket_type(m_io));

    sock->async_connect(m_ep, 
        [this, sock](const boost::system::error_code& ec)
    {
        if (ec)
        {
            return;
        }
        sock->async_read_some(buffer(m_buf), 
            [this, sock](const boost::system::error_code& ec, std::size_t)
        {
            read_handler(ec, sock);
        }
        );
    }
    );
}

  调用

// TcpSynClient.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include "client.h"

int main()
{
    try
    {
        std::cout << "client start." << std::endl;
        client cl;
        cl.run();
    }
    catch (const std::exception& ec)
    {
        std::cout << ec.what() << std::endl;
    }
    getchar();
    std::cout << "Hello World!\n"; 
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门提示: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

note:

  1. bind.hpp不能忘记添加
  2. bind实现函数到handler的适配
  3. lambda表达式的使用