使用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下載地址