1. 程式人生 > >使用boost ASIO庫封裝TCP伺服器類

使用boost ASIO庫封裝TCP伺服器類

使用非同步TCP方式,可在此基礎上增加更多功能。

標頭檔案AsioTcp.h:

#pragma once
#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>

typedef boost::asio::ip::tcp::socket socket_t;
typedef void* socket_handle;

class INetCallback
{
public:
 virtual void OnNewConnection(socket_handle newSocket) = 0;
 virtual void OnRecvData(socket_handle socket, const char* pData, UINT32 nDataSize) = 0;
};

class CTcpSession : public boost::enable_shared_from_this
{
public:
 CTcpSession(boost::asio::io_service& ioService, INetCallback* pINetCallback);
 void   HandleRead(const boost::system::error_code& ec, size_t bytes_transferred);
 void   HandleWrite(const boost::system::error_code& ec);
 void   StartRead();
 void   SendMsg(const char* pData, UINT32 nDataSize);

 socket_t&  GetSocket() { return m_socket; }
private:
 enum { max_length = 1024 };
 char m_dataRecvBuff[max_length];
 socket_t m_socket;
 INetCallback* m_pINetCallback;
};
class CAsioTcp
{
private:
 typedef boost::shared_ptr TcpSessionPtr;
 typedef boost::asio::ip::tcp::acceptor acceptor;
public:
 CAsioTcp(INetCallback* pINetCallback);
 virtual ~CAsioTcp(void);

 void   SendMsg(socket_handle socket, const char* pData, UINT32 nDataSize);
 void   Start();
private:
 void   StartAccept();
 void   AcceptHandler(const boost::system::error_code& ec, TcpSessionPtr pTcpSession);

private:
 boost::asio::io_service m_ioservice;
 boost::shared_ptr m_pAcceptor;
 INetCallback* m_pINetCallback;
};

實現檔案AsioTcp.cpp:

#include "StdAfx.h"
#include "AsioTcp.h"
#include <boost/thread.hpp>

using namespace boost::asio;

CAsioTcp::CAsioTcp(INetCallback* pINetCallback)
 : m_pINetCallback(pINetCallback)
{
 m_pAcceptor = boost::make_shared(m_ioservice, ip::tcp::endpoint(ip::tcp::v4(), 1688));
 StartAccept();
}


CAsioTcp::~CAsioTcp(void)
{
}

void CAsioTcp::StartAccept()
{
 TcpSessionPtr pTcpSession = boost::make_shared(m_ioservice, m_pINetCallback);
 m_pAcceptor->async_accept(pTcpSession->GetSocket(), boost::bind(&CAsioTcp::AcceptHandler, this, boost::asio::placeholders::error, pTcpSession));
}

void CAsioTcp::AcceptHandler( const boost::system::error_code& ec, TcpSessionPtr pTcpSession )
{
 if (ec)
 {
  return;
 }

 if (m_pINetCallback != NULL)
 {
  m_pINetCallback->OnNewConnection(&pTcpSession);
 }

 StartAccept();
 pTcpSession->StartRead();
}

void CAsioTcp::SendMsg( socket_handle socket, const char* pData, UINT32 nDataSize )
{
 TcpSessionPtr* ppTcpSession = reinterpret_cast(socket);
 (*ppTcpSession)->SendMsg(pData, nDataSize);
}

void CAsioTcp::Start()
{
 m_ioservice.run();
}

CTcpSession::CTcpSession(boost::asio::io_service& ioService, INetCallback* pINetCallback)
 : m_socket(ioService)
 , m_pINetCallback(pINetCallback)
{

}

void CTcpSession::HandleRead( const boost::system::error_code& ec, size_t bytes_transferred )
{
 if (!ec)
 {
  if (m_pINetCallback != NULL)
  {
   m_pINetCallback->OnRecvData(this, m_dataRecvBuff, bytes_transferred);
  }
  StartRead();
 }
}

void CTcpSession::StartRead()
{
 m_socket.async_read_some(boost::asio::buffer(m_dataRecvBuff, max_length),
  boost::bind(&CTcpSession::HandleRead, shared_from_this(),
  boost::asio::placeholders::error,
  boost::asio::placeholders::bytes_transferred));
}

void CTcpSession::SendMsg( const char* pData, UINT32 nDataSize )
{
 boost::asio::async_write(m_socket,
  boost::asio::buffer(pData, nDataSize),
  boost::bind(&CTcpSession::HandleWrite, shared_from_this(),
  boost::asio::placeholders::error));

}

void CTcpSession::HandleWrite( const boost::system::error_code& ec )
{

}

這個類使用方法示例:

TestAsioTcpServer.cpp檔案:
#include "stdafx.h"
#include <iostream>
#include "AsioTcp.h"
#include <boost/make_shared.hpp>

class CTestAsioTcpServer : public INetCallback
{

public:
 CTestAsioTcpServer()
 {
  m_pAsioTcp = boost::make_shared(this);
  m_pAsioTcp->Start();
 }
 void Run()
 {
  while (true)
  {
   Sleep(10);
  }
 }
 virtual void OnNewConnection( socket_handle newSocket )
 {
  std::cout << "OnNewConnection" << std::endl;
 }

 virtual void OnRecvData( socket_handle socket, const char* pData, UINT32 nDataSize )
 {
  std::cout << "OnRecvData:" << pData << " size=" << nDataSize << std::endl;

 m_pAsioTcp->SendMsg(socket, "echo", 4);

 }

private:
 boost::shared_ptr m_pAsioTcp;
};

int _tmain(int argc, _TCHAR* argv[])
{
 CTestAsioTcpServer tcpSrv;
 tcpSrv.Run();

 return 0;
}

客戶端程式碼:

TestAsioTcpClient.cpp檔案:

#include "stdafx.h"
#include <boost/asio.hpp>
#include <vector>

using namespace boost::asio;

int _tmain(int argc, _TCHAR* argv[])
{
 io_service ioservice;
 ip::tcp::socket sock(ioservice);
 ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 1688);
 ioservice.run();
 try
 {
  sock.connect(ep);

  while (true)
  {
   char szData[] = "hello";
   std::cout << "send:" << szData << std::endl;
   sock.send(buffer(szData));

   Sleep(1000);
   std::vector<char> str(1024, 0);
   int nSize = sock.read_some(buffer(str));

   std::cout << "Recv from " << sock.remote_endpoint().address() << ":" << &str[0] << " size=" << nSize << std::endl;
  }
 }
 catch (std::exception& e)
 {
  std::cout << e.what() << std::endl;
 }
 


 return 0;
}

以上程式碼在vs2010下編譯通過

demo下載地址