[16 使用C++11开发一个简单的通信程序(Proactor模式)] 16.5 C++11结合asio实现一个简单的客户端程序

客户端的需求:具备读/写能力,能自动重连。

自动重连用一个线程去检测,读/写能力复用RWHandler。

客户端的实现如下:

class Connector
{
public:
    Connector(io_service& ios, const string& strIP, short port) : m_ios(ios), m_socket(ios), m_serverAddr(tcp::endpoint(address::from_string(strIP), port)), m_isConnected(false), m_chkThread(nullptr)
    {
        CreateEventHandler(ios);
    }

    ~Connector()
    {
    }

    bool Start()
    {
        m_eventHandler->GetSocket().async_connect(m_serverAddr, [this](const boost::system::error_code& error){
            if (error) {
                HandleConnectError(error);
                return ;
            }
            cout << "connect ok" << endl;
            m_isConnected = true;
            // 连接成功后发起一个异步读操作
            m_eventHandler->HandleRead();
        });

        boost::this_thread::sleep(boost::posix_time::seconds(1));
        return m_isConnected;
    }

    bool IsConnected() const
    {
        return m_isConnected;
    }

    void Send(char* data, int len)
    {
        if(!m_isConnected) {
            return ;
        }
        // 同步写
        m_eventHandler->HandleWrite(data, len);
    }

private:
    void CreateEventHandler(io_service& ios)
    {
        m_eventHandler = std::make_shared<RWHandler>(ios);
        m_eventHandler->SetCallBackError([this](int connid){
            HandleRWError(connid);
        });
    }

    void HandleRWError(int connid)
    {
        m_isConnected = false;
        CheckConnnect();
    }    

    void HandleConnectError(const boost::system::error_code &error)
    {
        m_isConnected = false;
        cout << error.message() << endl;
        m_eventHandler->CloseSocket();
        CheckConnect();
    }

    void CheckConnect()
    {
        if (m_chkThread != nullptr) {
            return;
        }

        m_chkThread = std::make_shared<std::thread>([this]{
            while(true) {
                if(!IsConnected()) {
                    Start();
                }
                boost::this_thread::sleep(boost::posix_time::seconds(1));
            }
        });
    }

private:
    io_service& m_ios;
    tcp::socket m_socket;
    // 服务端地址
    tcp::endpoint m_serverAddr;
    std::shared_ptr<RWHandler> m_eventHandler;
    bool m_isConnected;
    // 专门检测重连的线程
    std::shared_ptr<std::thread> m_chkThread;
};

连接成功后发起了一个异步读操作,它用来判断连接是否断开,因为当连接断开时,HandleRWError会触发重连操作。

客户端的测试代码如下:

int main()
{
    io_service ios;
    boost::asio::io_service::work work(ios);
    boost::thread thd([&ios]{
        ios.run();
    });

    Connector conn(ios, "127.0.0.1", 9900);
    conn.Start();
    
    istring str;
    if (!conn.IsConnected()) {
        cin >> str;
        return -1;
    }

    const int len = 512;
    char line[len] = "";
    while(cin >> str) {
        char header[HEAD_LEN] = {};
        // str末尾'/0'
        int totalLen = str.length() + 1 + HEAD_LEN;
        std::sprintf(header, "%d", totalLen);
        memcpy(line, header, HEAD_LEN);
        memcpy(line + HEAD_LEN, str.c_str(), str.length() + 1);
        conn.Send(line, totalLen);
    }

    return 0;
}

注意:这里通过boost::asio::io_service::work和单独线程来保证ios::run()不退出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值