您当前的位置: 首页 > 

phymat.nico

暂无认证

  • 1浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

boost asio 异步实现tcp通讯

phymat.nico 发布时间:2017-12-13 23:42:54 ,浏览量:1

一、前言

boost asio可算是一个简单易用,功能又强大可跨平台的C++通讯库,效率也表现的不错,linux环境是epoll实现的,而windows环境是iocp实现的。而tcp通讯是项目当中经常用到通讯方式之一,实现的方法有各式各样,因此总结一套适用于自己项目的方法是很有必要,很可能下一个项目直接套上去就可以用了。

二、实现思路 1.通讯包数据结构

Tag:检查数据包是否合法,具体会在下面讲解;

Length:描述Body的长度;

Command:表示数据包的类型,0表示心跳包(长连接需要心跳来检测连接是否正常),1表示注册包(客户端连接上服务器之后要将相关信息注册给服务器),2表示业务消息包;

business_type:业务消息包类型,服务器会根据业务消息包类型将数据路由到对应的客户端(客户端是有业务类型分类的);

app_id:客户端唯一标识符;

Data:消息数据;

2.连接对象

客户端连接上服务器之后,双方都会产生一个socket连接对象,通过这个对象可以收发数据,因此我定义为socket_session。

//socket_session.h

[cpp] view plain copy
  1. #pragma once  
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15.   
  16. using boost::asio::ip::tcp;  
  17.   
  18. namespace firebird{  
  19.     enum command{ heartbeat = 0, regist, normal};  
  20.   
  21.     const std::string tag = "KDS";  
  22.   
  23.     class FIREBIRD_DECL socket_session;  
  24.     typedef boost::shared_ptr socket_session_ptr;  
  25.   
  26.     class FIREBIRD_DECL socket_session:  
  27.         public boost::enable_shared_from_this,  
  28.         private boost::noncopyable  
  29.     {  
  30.     public:  
  31.         typedef boost::function close_callback;  
  32.         typedef boost::function read_data_callback;  
  33.   
  34.         socket_session(boost::asio::io_service& io_service);  
  35.         ~socket_session(void);  
  36.   
  37.         DWORD id() { return m_id; }  
  38.         WORD get_business_type(){ return m_business_type; }  
  39.         void set_business_type(WORD type) { m_business_type = type; }  
  40.         DWORD get_app_id(){ return m_app_id; }  
  41.         void set_app_id(DWORD app_id) { m_app_id = app_id; }  
  42.         std::string& get_remote_addr() { return m_name; }  
  43.         void set_remote_addr(std::string& name) { m_name = name; }  
  44.         tcp::socket& socket() { return m_socket; }  
  45.   
  46.         void installCloseCallBack(close_callback cb){ close_cb = cb; }  
  47.         void installReadDataCallBack(read_data_callback cb) { read_data_cb = cb; }  
  48.   
  49.         void start();  
  50.         void close();  
  51.         void async_write(const std::string& sMsg);  
  52.         void async_write(message& msg);  
  53.   
  54.         bool is_timeout();  
  55.         void set_op_time(){std::time(&m_last_op_time);}  
  56.   
  57.     private:  
  58.         static boost::detail::atomic_count m_last_id;  
  59.   
  60.         DWORD m_id;  
  61.         WORD  m_business_type;  
  62.         DWORD m_app_id;  
  63.         std::string m_name;  
  64.         boost::array sHeader;  
  65.         std::string sBody;  
  66.   
  67.         tcp::socket m_socket;  
  68.         boost::asio::io_service& m_io_service;  
  69.   
  70.         std::time_t m_last_op_time;  
  71.   
  72.         close_callback close_cb;  
  73.         read_data_callback read_data_cb;  
  74.   
  75.         //发送消息  
  76.         void handle_write(const boost::system::error_code& e,   
  77.             std::size_t bytes_transferred, std::string* pmsg);  
  78.   
  79.         //读消息头  
  80.         void handle_read_header(const boost::system::error_code& error);  
  81.         //读消息体  
  82.         void handle_read_body(const boost::system::error_code& error);  
  83.   
  84.         void handle_close();  
  85.     };  
  86. }  
这里注意的是,定义了一个tag="KDS",目的是为了检查收到的数据包是否有效,每一个数据包前3个字节不为“KDS”,那么就认为是非法的请求包,你也可以定义tag等于其它字符串,只要按协议发包就正常,当然这是比较简单的数据包检查方法了。比较严谨的方法是双方使用哈希算法来检查的,怎么做,这里先不做详解。

//socket_session.cpp

[cpp] view plain copy
  1. #include "socket_session.h"  
  2.   
  3. namespace firebird{  
  4.     boost::detail::atomic_count socket_session::m_last_id(0);  
  5.   
  6.     socket_session::socket_session(boost::asio::io_service& io_srv)  
  7.         :m_io_service(io_srv), m_socket(io_srv),   
  8.         m_business_type(0), m_app_id(0)  
  9.     {  
  10.         m_id = ++socket_session::m_last_id;  
  11.     }  
  12.   
  13.     socket_session::~socket_session(void)  
  14.     {  
  15.         m_socket.close();  
  16.     }  
  17.   
  18.     void socket_session::start()  
  19.     {  
  20.         m_socket.set_option(boost::asio::ip::tcp::acceptor::linger(true, 0));  
  21.         m_socket.set_option(boost::asio::socket_base::keep_alive(true));  
  22.         std::time(&m_last_op_time);  
  23.         const boost::system::error_code error;  
  24.         handle_read_header(error);  
  25.     }  
  26.   
  27.     void socket_session::handle_close()  
  28.     {  
  29.         try{  
  30.             m_socket.close();  
  31.             close_cb(shared_from_this());  
  32.         }  
  33.         catch(std::exception& e)  
  34.         {  
  35.             LOG4CXX_ERROR(firebird_log, KDS_CODE_INFO 
关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0470s