基於libevent的tcp拆包分包庫
TCP/IP協議雖然方便,但是由於是基於流的傳輸(UDP是基於數據報的傳輸),無論什麽項目,總少不了解決拆包分包問題。
以前的項目總是每個程序員自己寫一套拆包分包邏輯,實現的方法與穩定性都不太一致。終於有了做基線的機會,自己寫了一個基於libevent的拆包分包庫。
本文檔黏貼一些核心的內容。
//回調接口
class ITcpPacketNotify { public: virtual void OnConnected(int fd) = 0; virtual void OnDisConnected(int fd) = 0; virtual void OnTimeOutError(int fd) = 0; virtual void OnBuffOverFlow(int fd) = 0; //提取包,需要業務層返回解析出包的長度,或者舍棄一些不合格的包,成功解析出包返回true virtual bool OnAnalyzePacket(int fd,const char* buff,int bufflen,int& packetlen,int &ignore) = 0; //業務層處理包回調,如果需要返回包,可以直接在respond參數和respondlen參數返回,長度不得超過40960 virtual void OnPacketArrived(int fd,const char* packet,int packetlen,char* respond,int& respondlen) = 0; }; |
提供了兩種錯誤情況的通知,跟別的庫不太一樣的地方是,需要業務層實現拆包邏輯,畢竟每個項目的協議不一樣。然後就會收到packet的通知。
//提取包,需要業務層返回解析出包的長度,或者舍棄一些不合格的包,成功解析出包返回true virtual bool OnAnalyzePacket(int fd, const char* buff, int bufflen,int& packetlen, int &ignore) //數據長度 packetlen = length + 12; |
上面是某種協議的拆包例子。
typedef struct _TcpPacketConfig _TcpPacketConfig() } TcpPacketConfig; class ITcpPacketManager TCPPACKET_API ITcpPacketManager* CreateTcpPacketManager(); TCPPACKET_API void DestroyTcpPacketManager(ITcpPacketManager* manager); |
對外的接口方法。
bool CTcpPacketImp::Start(_TcpPacketConfig & config, ITcpPacketNotify* notify) void CTcpPacketImp::Stop() bool CTcpPacketImp::SendPacket(int fd, const char* packet, int packetlen) |
轉移到m_libEvent實現。
最核心的功能代碼如下。
一些數據定義:
#include <event2/bufferevent.h>
struct _Conn; //服務器屬性封裝對象 typedef struct _Server Server; |
頭文件:
class CLibEvent static ITcpPacketNotify * m_notify; |
cpp:
#include "StdAfx.h" #include <string> #include <assert.h> #include <WinSock2.h>
CLibEvent::~CLibEvent(void) bool CLibEvent::StartServer(int port, short workernum, unsigned int connnum, int read_timeout, int write_timeout,ITcpPacketNotify* notify) void CLibEvent::StopServer() void CLibEvent::DoRead(struct bufferevent *bev, void *ctx) //拷貝緩沖池的內存到Conn,最大緩沖不超過emMaxBuffLen } } void CLibEvent::CloseConn(Conn *pConn) void CLibEvent::DoError(struct bufferevent *bev, short error, void *ctx) void CLibEvent::DoAccept(struct evconnlistener *listener, evutil_socket_t fd,struct sockaddr *sa, int socklen, void *user_data) DWORD WINAPI CLibEvent::ThreadServer(LPVOID lPVOID) DWORD WINAPI CLibEvent::ThreadWorkers(LPVOID lPVOID) bool CLibEvent::SendPacket(int fd, const char* packet, int packetlen) return true; ITcpPacketNotify * CLibEvent::m_notify=NULL; |
基於libevent的tcp拆包分包庫