boost用asio设计TCP服务器中单连接的设计

来源:互联网 发布:nba2010总决赛数据 编辑:程序博客网 时间:2024/06/05 12:01

在boost用asio设计TCP服务器的关键技术中,设计了tcp连接的管理类channel和处理io_service中多线程的工作方法,针对单个tcp连接的处理类session,核心的方法是接收和发送数据。

其中async_read_until与boost::asio::streambuf的组合,据说是可用处理粘包的问题,我打算下一个版本再用,这里用到的接收数据的buffer基于char来构造的。

重点是session类的设计,头文件如下

#pragma once  #include <boost/asio.hpp>  #include <boost/bind.hpp>  #include <boost/shared_ptr.hpp>#include <boost/enable_shared_from_this.hpp>  #include "CircledBuffer.h"//::public boost::asio::ip::tcp::socketclass channel;class session;typedef boost::shared_ptr<session> session_ptr;class session: public boost::enable_shared_from_this<session>   {public:session(boost::asio::io_service &io_service,channel& _channel);~session();bool started_;bool started() const;void start();void stop();void start_send(char* cmd);boost::asio::ip::tcp::socket &socket();std::string getRemoteAddr();int getRemotePort();int getSessionId(){return sessionId;};int heartbeat_count_;static long LastSessionId;private:boost::asio::ip::tcp::socket socket_;boost::asio::streambuf sbuf_;//TODO use circleBuffer instead of them.enum{max_msg=256};unsigned char write_buffer[max_msg];///////////////////////////////////CircledBuffer readBuffer;unsigned int readIndex;int sessionId;channel& p_channel;boost::asio::strand strand_;boost::asio::deadline_timer sessionAliveTimer;///////////////////////////not understand why to use this two.// std::size_t check_frame(const boost::system::error_code &ec, std::size_t bytes_transferred);//check data// void parse_frame(const boost::system::error_code &ec, std::size_t bytes_transferred);//parse data.void receive_handler(const boost::system::error_code &ec, std::size_t bytes_transferred);void send_handler(const boost::system::error_code &ec);void processCmd(std::size_t bytes_transferred);void _processCmd(std::size_t bytes_transferred);void _start();void _stop();void _start_send(char* cmd);void _setTimer(int sec);void _checkHeartBeat(const boost::system::error_code& /*e*/, boost::asio::deadline_timer* t);private:session(const session& other);const session operator=( const session& rhs);};

这里的CmdBuffer的数组CircledBuffer就是我基于char构建的tcp命令的接收缓冲区,首先session进入开始状态。

void session::_start() {started_=true;CmdBuffer* cmd;std::cout<<getRemoteAddr()<<":"<<getRemotePort()<<"is connected \n";cmd= readBuffer.GetLast();readBuffer.MoveNext();_setTimer(2);socket_.async_receive(boost::asio::buffer(cmd->data),    strand_.wrap( boost::bind(&session::receive_handler,    shared_from_this(),    boost::asio::placeholders::error,    boost::asio::placeholders::bytes_transferred)));}

session的开始状态,是以receive开始的。收到数据后,调用receive_handler的函数。

void session::receive_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)   {       if (ec){if (ec.value() == boost::asio::error::eof){stop();}return;}      if (!started())return;processCmd(bytes_transferred);CmdBuffer* cmd;cmd= readBuffer.GetLast();readBuffer.MoveNext();socket_.async_receive(boost::asio::buffer(cmd->data),               strand_.wrap( boost::bind(&session::receive_handler,              shared_from_this(),              boost::asio::placeholders::error,              boost::asio::placeholders::bytes_transferred)));  }  

receive_handler是对收到的数据进行处理,调用processCmd来进行,processCmd仅仅做了printf,由于有buffer缓存,可以根据分隔符来处理命令,处理完数据后,继续接收数据,继续调用async_receive的方法,构成了回调的循环结构。

对于数据的发送,是通过上层函数发起的,session的上层接口是channel,只需要留出发送数据的接口就可以了。

void session::_start_send(char* cmd)  {  char* wBufferPtr = (char*)write_buffer;memset(wBufferPtr,0,max_msg);sprintf(wBufferPtr,"%s\r\n",cmd);socket_.async_send(boost::asio::buffer(write_buffer,strlen(wBufferPtr)),strand_.wrap( boost::bind(&session::send_handler,  shared_from_this(),  boost::asio::placeholders::error)));  }  

对于send_handler,是发送之后做的处理,这里可以为空就可以了。

最后,介绍一下boost在网络编程中,需要用到的endpoint的类,这个类的作用相当于sockaddr_in,提供一些端口,ip等信息。

获取远端的ip和端口的方法:

boost::asio::ip::tcp::endpoint remoteEp =  socket_.remote_endpoint(); ip = remoteEp.address().to_string();port = remoteEp.port()

一会儿,我再整理一下tcp服务器中,比较实用的串行化工具strand和异步定时器。

全部源代码下载连接在这里



原创粉丝点击