1. 程式人生 > >boost庫在工作(36)網路服務端之六

boost庫在工作(36)網路服務端之六

在上面介紹了管理所有連線的類,這個類主要就是新增新的連線,或者刪除不需要的連線。但是管理的類CAllConnect是沒有辦法知道什麼時候新增,什麼時候刪除的,它需要從接收到連線類裡獲取得到新的連線,從連線類裡獲得刪除的事件。如下面的程式碼:

//封裝一個服務端類來處理網路。
//軟體開發人員: 蔡軍生  2013-07-28
//
class CConnect : 
	public boost::enable_shared_from_this< CConnect >
{
	static const int MAX_BUFSIZE = 1024;
public:
	CConnect(boost::asio::io_service& ioService, CAllConnect& allConnect)
		:m_Socket(ioService),
		m_rAllConnect(allConnect),
		m_strHit("\r\nResp: ")
	{
	}

	boost::asio::ip::tcp::socket& GetSocket(void)
	{
		return m_Socket;
	}

	//傳送的訊息。
	void PushMsg(const std::string& strMsg)
	{
		m_QueueMsg.push_back(strMsg);
		//
		std::vector< boost::asio::const_buffer > vSendBuf;
		vSendBuf.push_back(boost::asio::buffer(m_strHit));

		if (!m_QueueMsg.empty())
		{
			vSendBuf.push_back(boost::asio::buffer(m_QueueMsg.front()));
		}
		boost::asio::async_write(m_Socket,
			vSendBuf,
			boost::bind(&CConnect::HandleWrite, shared_from_this(),
			boost::asio::placeholders::error));
	}

	void Start(void)
	{
		//新增管理連線集合。
		m_rAllConnect.Add(shared_from_this());

		m_Socket.async_read_some(boost::asio::buffer(m_chBuffer, MAX_BUFSIZE),
			boost::bind(&CConnect::HandleRead, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
	}

	void HandleRead(const boost::system::error_code& error,
		size_t bytes_transferred)
	{
		if (!error)
		{
			std::vector< boost::asio::const_buffer > vSendBuf;
			vSendBuf.push_back(boost::asio::buffer(m_strHit));
						
			if (!m_QueueMsg.empty())
			{
				vSendBuf.push_back(boost::asio::buffer(m_QueueMsg.front()));
			}
			vSendBuf.push_back(boost::asio::buffer(m_chBuffer, bytes_transferred));
			boost::asio::async_write(m_Socket,
				vSendBuf,
				boost::bind(&CConnect::HandleWrite, shared_from_this(),
				boost::asio::placeholders::error));
		}
		else
		{
			//從連線集合裡刪除自己的連線。
			m_rAllConnect.Delete(shared_from_this());
		}
	}

	void HandleWrite(const boost::system::error_code& error)
	{
		if (!error)
		{
			if (!m_QueueMsg.empty())
			{
				m_QueueMsg.pop_front();
			}

			m_Socket.async_read_some(boost::asio::buffer(m_chBuffer, MAX_BUFSIZE),
				boost::bind(&CConnect::HandleRead, shared_from_this(),
				boost::asio::placeholders::error,
				boost::asio::placeholders::bytes_transferred));
		}
		else
		{
			//從連線集合裡刪除自己的連線。
			m_rAllConnect.Delete(shared_from_this());
		}
	}
private:
	//
	boost::asio::ip::tcp::socket m_Socket;

	//
	boost::array<char, MAX_BUFSIZE> m_chBuffer;
	std::string m_strHit;
	std::deque< std::string > m_QueueMsg;
	//儲存所有連線集合。
	CAllConnect& m_rAllConnect;
};

//伺服器,主要接收新連線,並啟動新連線接收資料。
//軟體開發人員: 蔡軍生  2013-07-28
class CServer
{
public:
	//建構函式,主要提供IO服務和埠。
	CServer(boost::asio::io_service& ioService, short sPort)
		:m_ioService(ioService), 
		m_acceptor(ioService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), sPort))
	{
		//建立一個新連線,用來接收連線進來的客戶端表示。
		boost::shared_ptr< CConnect > pConnect(new CConnect(m_ioService, m_allConnect));
		//做連線準備。
		m_acceptor.async_accept(pConnect->GetSocket(),
			boost::bind(&CServer::HandleAccept, this, pConnect,
			boost::asio::placeholders::error));	
	}

	//收到客戶端連線進來事件響應。
	void HandleAccept(boost::shared_ptr< CConnect > pNewConnect,
		const boost::system::error_code& error)
	{
		if (!error)
		{
			//在這裡可以通知別的連線有新連線進來。
			std::set< boost::shared_ptr< CConnect > >& rAll = m_allConnect.GetAllConnect();
			std::for_each(rAll.begin(), rAll.end(),
				[&](boost::shared_ptr< CConnect > pOther)
				{
					pOther->PushMsg("Hello!");
			});

			//如果沒有錯誤,對連線進來的連線收發資料。
			pNewConnect->Start();

			//建立新的連線,以備下一個客戶端連線進來。
			pNewConnect.reset(new CConnect(m_ioService, m_allConnect));
			//做連線準備。
			m_acceptor.async_accept(pNewConnect->GetSocket(),
				boost::bind(&CServer::HandleAccept, this, pNewConnect,
				boost::asio::placeholders::error));
		}
	}

private:
	//IO服務
	boost::asio::io_service& m_ioService;
	//接收器,用來接收新連線進來。
	boost::asio::ip::tcp::acceptor m_acceptor;

	//管理所有連線。
	CAllConnect m_allConnect;
};

//
int _tmain(int argc, _TCHAR* argv[])
{
	//建立一個IO服務
	boost::asio::io_service ioService;	
	//建立伺服器,埠為9001。
	CServer server(ioService, 9001);

	//響應IO服務
	ioService.run();

	return 0;
}

在類CServer裡的函式HandleAccept通知所有其它連線一個訊息,如下程式碼:

std::set< boost::shared_ptr< CConnect > >& rAll =m_allConnect.GetAllConnect();

         std::for_each(rAll.begin(),rAll.end(),

             [&](boost::shared_ptr<CConnect > pOther)

             {

                 pOther->PushMsg("Hello!");

         });

這裡使用了一個C11的特性lambda表示式,達到最清楚化的表示。

然後在類CConnect裡函式Start裡呼叫管理類新增的函式,在函式HandleRead和HandleWrite呼叫刪除的函式,這樣就達到連線在管理類裡新增和刪除的響應。通過這樣一個集合,就可以管理所有連線,跟所有連線進行通訊,或者刪除某一個連線。