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

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::socket

class 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和异步定时器。

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值