Source Code:
引言:
出于学习目的我编写了xzben框架,它是我一边学习一边写的,所以可能存在各种bug,如果你发现了bug可以在本博文留言,我一定会尽力解决。另外本框架注重在于网络通信的通行层,也就是说框架只是将网络通信中的数据包发送过程封装,可以让用户在不关心如何发送数据,只是关心通信协议层面上思考问题。所以请不要站在协议层上来看本框架,我并不关心协议是如何。我只关心如何高效的将数据发送出去,并在收到数据时告诉你让你拿数据去处理,仅此而已。
主要对象:
1、NetHost 对象代表一个网络主机对象,你只要给它装配好:IO驱动器(IODriver)、协议数据处理器(NetProtocol)然后启动服务,然后开始监听感兴趣的TCP/UDP端口(ListenTcpPort/ListenUdpPort),就已经安装好一个网络通信主机了。
2、IODriver 对象代表一个IO处理器对象基类,使用时应该使用具体的IODriver子类(由框架提供),比如目前提供的window下的IOCP模式(IOCPDriver)。
3、NetProtocol 对象代表一个协议数据处理器基类,用户需要自定实现一个具体的子类来处理数据实现自己的协议。
4、ShareNetSocketPtr 对象其实就代表一个NetSocket指针的代理器,由ShareNetSocketPtr代理NetSocket指针主要出于指针的保护。ShareNetSocketPtr本身就是一个智能指针对象,通过引用计数来控制对象的delete,当引用计数为零时NetSocket对象就会被delete,否则不会。所以在使用ShareNetSocketPtr时只要将其看成一个NetSocket指针就行。
5、NetSocket对象代表一个通信链路(TCP/UDP链路),它本身有自己链路的数据buffer所以,链路中的通信数据可以直接从它来获取(ReadMsg ),也可以直接用它来发送数据。
除了上面的五个类,其它的类你完全可以不关心,除非有bug的时候你才有必要去看。
使用步骤:
1、定义自己的通信协议类,主要实现
/*
* OnConnect接口在一个 TCP 连接建立时触发,可以在此接口中实现对连接到网络主机的Socket进行信息采集
* @para pNetSocket: 一个连接到主机的Socket连接封装类。可以在其中获取连接的通信数据,连接对象的地址信息也可以用它直接给通信对法发送数据。
*
*/
virtual bool OnConnect(ShareNetSocketPtr& pNetSocket) =0;
/*
* OnDisconnect接口在一个TCP连接断开时触发,可以在此接口中采集与主机断开连接的的socket信息
* @para pNetSocket: 同OnConnect
*/
virtual bool OnDisconnect(ShareNetSocketPtr& pNetSocket)=0;
/*
* OnMsg 接口在接收到一个TCP/UDP 数据包是触发,要注意的是如果是TCP这里的触发次数不一定和发送端发送次数一致。
* 所以你要自己通过数据内容中的协议判断数据是否发送结束,不能假设一定一次触发就是一个完整的数据包。
* @para pNetSocket: 同OnConnect
*/
virtual bool OnMsg(ShareNetSocketPtr& pNetSocket) =0;
example:
class TestProtocol : public NetProtocol
{
private:
bool OnConnect(ShareNetSocketPtr& pNetSocket)
{
std::string strIp; uint16 nPort;
pNetSocket->GetPeertAddr(strIp, nPort);
Print(GlobalFunction::Format("Connect Ip: %s --- Port: %d", strIp.c_str(), nPort));
return true;
}
bool OnDisconnect(ShareNetSocketPtr& pNetSocket)
{
std::string strIp; uint16 nPort;
pNetSocket->GetPeertAddr(strIp, nPort);
Print(GlobalFunction::Format("Disconnect Ip: %s --- Port: %d", strIp.c_str(), nPort));
return true;
}
bool OnMsg(ShareNetSocketPtr& pNetSocket)
{
char buffer[1024];
static int nTimes = 1;
int nDataSize = pNetSocket->GetDataSize();
int nReadSize;
if( (nReadSize = pNetSocket->ReadMsg(buffer, 1024)) > 0 )
{
buffer[nReadSize] = '\0';
Print(GlobalFunction::Format("%d: OnMsg DataSize :%d Content: %s",nTimes++, nDataSize, buffer));
pNetSocket->SendMessage(buffer, nReadSize);
}
return true;
}
private:
void Print(std::string strMsg)
{
AutoLock lock(&m_mutex);
printf("%s\n", strMsg.c_str());
}
Mutex m_mutex;
};
2、实例化一个NetHost对象,选择一个IODriver 子类作为其IO驱动器,将上面实现的协议类对象作为协议数据处理器。
3、启动服务,开始监听指定端口。
综合实例:
服务器Code:
#include <Socket/NetHost.h>
#include <Socket/IOCPDriver.h>
#include <Socket/NetProtocol.h>
#include <base/Lock.h>
#include <string>
using namespace XZBEN;
class TestProtocol : public NetProtocol
{
private:
bool OnConnect(ShareNetSocketPtr& pNetSocket)
{
std::string strIp; uint16 nPort;
pNetSocket->GetPeertAddr(strIp, nPort);
Print(GlobalFunction::Format("Connect Ip: %s --- Port: %d", strIp.c_str(), nPort));
return true;
}
bool OnDisconnect(ShareNetSocketPtr& pNetSocket)
{
std::string strIp; uint16 nPort;
pNetSocket->GetPeertAddr(strIp, nPort);
Print(GlobalFunction::Format("Disconnect Ip: %s --- Port: %d", strIp.c_str(), nPort));
return true;
}
bool OnMsg(ShareNetSocketPtr& pNetSocket)
{
char buffer[1024];
static int nTimes = 1;
int nDataSize = pNetSocket->GetDataSize();
int nReadSize;
if( (nReadSize = pNetSocket->ReadMsg(buffer, 1024)) > 0 )
{
buffer[nReadSize] = '\0';
Print(GlobalFunction::Format("%d: OnMsg DataSize :%d Content: %s",nTimes++, nDataSize, buffer));
pNetSocket->SendMessage(buffer, nReadSize);
}
return true;
}
private:
void Print(std::string strMsg)
{
AutoLock lock(&m_mutex);
printf("%s\n", strMsg.c_str());
}
Mutex m_mutex;
};
int main()
{
NetHost *pHost = new NetHost(new IOCPDriver, new TestProtocol);
pHost->StartServer();
pHost->ListenTcpPort(6000);
pHost->ThreadLoop();
return 0;
}
客户端Code:
#include <Socket/NetHost.h>
#include <Socket/IOCPDriver.h>
#include <Socket/NetProtocol.h>
using namespace XZBEN;
class ClientProtocol : public NetProtocol
{
private:
bool OnConnect(ShareNetSocketPtr& pNetSocket)
{
std::string strIp; uint16 nPort;
pNetSocket->GetPeertAddr(strIp, nPort);
Print(GlobalFunction::Format("Connect Ip: %s --- Port: %d", strIp.c_str(), nPort));
return true;
}
bool OnDisconnect(ShareNetSocketPtr& pNetSocket)
{
std::string strIp; uint16 nPort;
pNetSocket->GetPeertAddr(strIp, nPort);
Print(GlobalFunction::Format("Disconnect Ip: %s --- Port: %d", strIp.c_str(), nPort));
return true;
}
bool OnMsg(ShareNetSocketPtr& pNetSocket)
{
char buffer[1024];
static int nTimes = 1;
int nDataSize = pNetSocket->GetDataSize();
int nReadSize;
if( (nReadSize = pNetSocket->ReadMsg(buffer, 1024)) > 0 )
{
buffer[nReadSize] = '\0';
Print(GlobalFunction::Format("%d: OnMsg DataSize :%d Content: %s",nTimes++, nDataSize, buffer));
pNetSocket->SendMessage("TestBuffer", strlen("TestBuffer")+1);
}
return true;
}
private:
void Print(std::string strMsg)
{
AutoLock lock(&m_mutex);
printf("%s\n", strMsg.c_str());
}
Mutex m_mutex;
};
int main()
{
NetHost host;
host.SetupDriver(new IOCPDriver);
host.SetupProtocol(new ClientProtocol);
host.StartServer(1);
SOCKET hSocket = host.Connect("127.0.0.1", 6000);
host.SendTcpMsg(hSocket, "TestBuffer", strlen("TestBuffer")+1);
host.ThreadLoop();
return 0;
}