淘宝开源网络框架tbnet 之packet
来源:互联网 发布:阿里云 华北 华东 华南 编辑:程序博客网 时间:2024/05/18 01:01
接着上篇博文,在上篇博文当中我们一起简要的分析了下tbnet库中的transport类,该类是整个开源库的总起,接下来,我们就来分析下tbnet库中所使用的一些传输数据包的封装,在tbnet中对于传输包定义的比较开放,如果自己想要借用tbnet库时,可以通过继承tbnet库的packet类来定义自己的包结构,一个传输数据包一般的结构分为两个部分:1)包头;2)包体,而包头主要提供了一些包的基本信息以及路由信息,而包体则是包含用户传输的数据,在tbnet库中,首先定义了一个包头结构,代码如下:
class PacketHeader {public: uint32_t _chid; // ͨµÀID int _pcode; // Êý¾Ý°üÀàÐÍ int _dataLen; // Êý¾Ý°übody³¤¶È(³ýÍ·ÐÅÏ¢Íâ)};
在该结构中,包含了三部分内容:channelID、数据包的编码以及包体的长度,在使用tbnet库中,所有的数据包都会定义包头,接下来看看packet的部分定义,代码如下
class Packet { friend class PacketQueue;public:... /* * ×é×° * * @param output: Ä¿±êbuffer * @return ÊÇ·ñ³É¹¦ */ virtual bool encode(DataBuffer *output) = 0; /* * ½â¿ª * * @param input: Ô´buffer * @param header: Êý¾Ý°üheader * @return ÊÇ·ñ³É¹¦ */ virtual bool decode(DataBuffer *input, PacketHeader *header) = 0;...protected: PacketHeader _packetHeader; // Êý¾Ý°üµÄÍ·ÐÅÏ¢ int64_t _expireTime; // µ½ÆÚʱ¼ä Channel *_channel; Packet *_next; // ÓÃÔÚpacketqueueÁ´±í};
在packet类中,我们主需要关注一下其中的两个函数即可,encode函数和decode函数,每个数据包在传输之前都需要经过二进制编码的过程,而在收到数据包时吗,又需要二进制解码过程,所以在packet类中,定义了这两个函数,并且这两函数声明为虚函数,从而使得在继承子类中可以根据需要来自行设计二进制编解码过程,最后来看看其主要的成员变量,包含了一个包头结构,超时时间以及一个Channel指针,这个指针主要的作用就是声明这个数据包的归属问题,接下来,我们来看看在tbnet库中实现的关于httprequestpacke类,这个类是packet的子类,并且主要用于 HTTP协议,首先从该类的成员变量说起,代码如下:
char *_strHeader; // ±£´æÍ·ÄÚÈݵÄbu char *_strQuery; // ²éѯ bool _isKeepAlive; // ÊÇ·ñÖ§³Ökeepal int _method; // get - 1 PSTR_MAP _headerMap; // ÆäËûÍ·ÐÅÏ¢µÄ tbnet::Connection *_connection; // ´æconnecti
在该成员中,主要包含了http协议方面的一些东西,如http包头和http请求结构体,并且还有个connection指针,这个指针的作用主要的作用就是标记这个packet的发送端,这样方便回传response包,接着我们就来看看decode函数,该函数的作用就是解压请求的request包,而在httprequsetpacket里面不会实现encode函数,至于原因想必大家已经很清楚了,因为在http接收端只负责接收请求包,并对请求包进行解压,代码如下:
bool HttpRequestPacket::decode(DataBuffer *input, PacketHeader *header) { int len = header->_dataLen; _strHeader = (char*) malloc(len+1); input->readBytes(_strHeader, len); _strHeader[len] = '\0'; int line = 0; int first = 1; char *p, *name = NULL, *value; p = value = _strHeader; while (*p) { // ÕÒÿһ if (*p == '\r' && *(p+1) == '\n') { if (value == p && line > 0) { // header ½áÊ break; } *p = '\0'; // ȥǰ¿Õ while (*value == ' ') value ++; if (line > 0) { if (strcmp(name, "Connection") == 0 && strcasecmp(value, "Keep-Alive") == 0) { _isKeepAlive = true; } else { _headerMap[name] = value; } } else { _strQuery = value; } value = p + 2; line ++; first = 1; } else if (line == 0 && *p == ' ') { // Ê× if (_method) { *p = '\0'; } else if (strncmp(value, "GET ", 4) == 0) { // ÊÇGET ·½ _method = 1; value = p + 1; } } else if (*p == ':' && first == 1) { *p = '\0'; name = value; value = p + 1; first = 0; } p ++; } return true;}
这段代码其实也没有什么特殊之处,就是针对发送的请求包按照http请求包的格式进行解压而已,在此就不做过多的分析,接下来,我们再来看看httpresponsepacket类,这个类从名字上就可以看出来跟上面说的httprequestpacket相对应
class HttpResponsePacket : public Packet {public:... /* * ×é */ bool encode(DataBuffer *output); /* * ½â */ bool decode(DataBuffer *input, PacketHeader *header);... /* * ÉèÖÃheade */ void setHeader(const char *name, const char *value); /* * ÉèÖÃ× */ void setStatus(bool status, const char *statusMessage = NULL); /* * ÉèÖÃÄÚÈ */ void setBody(const char *body, int len); /* * ÊÇ·ñkeepalive */ void setKeepAlive(bool keepAlive);private: bool _status; // ·µ»ØµÄ״̬, true => 200, false => 404 char *_statusMessage; // ״̬ char *_body; // ·µ»ØµÄÄÚÈÝ int _bodyLen; // ·µ»ØÄÚÈÝÕÒ³¤¶È STRING_MAP _headerMap; // ·µ»ØÆäËûÍ·ÐÅÏ¢ bool _isKeepAlive; // ÊÇ·ñkeepalive}
这个类里面其实内容跟之前说的差不多,数据成员里面包含了http response包的相关结构,在此不作过多地介绍,下面我们花点时间来看看encode这个函数,代码如下:
bool HttpResponsePacket::encode(DataBuffer *output) { if (_statusMessage) { output->writeBytes(_statusMessage, strlen(_statusMessage)); output->writeBytes("\r\n", 2); } else if (_status) { //HTTP/1.1 200 OK output->writeBytes(TBNET_HTTP_STATUS_OK, strlen(TBNET_HTTP_STATUS_OK)); } else { // HTTP/1.1 404 Not Found output->writeBytes(TBNET_HTTP_STATUS_NOTFOUND, strlen(TBNET_HTTP_STATUS_NOTFOUND)); } //¹Ì¶¨ if (_isKeepAlive) { output->writeBytes(TBNET_HTTP_KEEP_ALIVE, strlen(TBNET_HTTP_KEEP_ALIVE)); } else { output->writeBytes(TBNET_HTTP_CONN_CLOSE, strlen(TBNET_HTTP_CONN_CLOSE)); } if (_headerMap.find("Content-Type") == _headerMap.end()) { output->writeBytes(TBNET_HTTP_CONTENT_TYPE, strlen(TBNET_HTTP_CONTENT_TYPE)); } char tmp[64]; int len = sprintf(tmp, TBNET_HTTP_CONTENT_LENGTH, _bodyLen); output->writeBytes(tmp, len); // Óû§×Ô¶¨Òå for (STRING_MAP_ITER it=_headerMap.begin(); it!=_headerMap.end(); it++) { output->writeBytes(it->first.c_str(), strlen(it->first.c_str())); output->writeBytes(": ", 2); output->writeBytes(it->second.c_str(), strlen(it->second.c_str())); output->writeBytes("\r\n", 2); } // ¿Õ output->writeBytes("\r\n", 2); // bodyLen output->writeBytes(_body, _bodyLen); //assert(_packetHeader._dataLen == output->getDataLen()); return true;}
这段代码个人感觉写的比较的漂亮,基本上是按照http回馈包结构填充的,流程十分的清晰,最终会将反馈包写入到输出队列中,而后触发写可用事件,而将数据包发送出去,整个流程就是这样,在tbnet目录下有个test案例里面就用到了这两个包,有时间的话,可以自己在本机上试试,感觉还是蛮好用的,最后在tbnet中,还有一种数据包结构-controlpacket,这个数据包主要适用于服务器端之间的控制信息的发送,实现方式比较的简单,这里就不展开讨论了,本篇到这里就结束了,谢谢
总结
tbnet库里的packet类整体上来讲定义的不错,该有的部分都有,并且其扩展性也使很好的,用户可以根据自己的需要直接从packet类中继承即可,自己私下也定义了几个packet结构体,使用起来很方便,推荐大家不妨一试,谢谢,本篇到此结束,下篇,我们将讨论IOComponent这个东西,也使很不错哦,谢谢。
如果需要,请注明转载,谢谢
- 淘宝开源网络框架tbnet 之packet
- 淘宝开源网络框架tbnet之transport篇
- 淘宝开源网络框架tbnet 之 iocomponent
- 淘宝开源网络框架tbnet之buffer
- 淘宝开源网络框架tbnet之socket
- 淘宝开源网络框架TBNET分析
- 淘宝开源框架tbnet之connection
- 淘宝开源网络框架tbnet之ipacketstreamer,ipackethandler以及iserveradaper
- 分析淘宝网络框架tbnet
- 淘宝网络框架tbnet源码分析
- tbnet 网络框架解析
- 淘宝网络库tbnet安装小记
- 浅析淘宝网络通信库tbnet的实现
- Linux网络应用编程之集线器(Packet Tracer仿真)
- Linux网络应用编程之VLAN(Packet Tracer仿真)
- 开源网络框架
- 淘宝开源缓存框架taobao-pamirs-proxycache源码剖析
- 开源框架之Picasso进行网络图片下载
- 图解linux下top命令的使用
- Eclipse Maven Tomcat的利用配置
- linux 安装jdk
- mysql除法精度
- 定制Ribbon触发工作流
- 淘宝开源网络框架tbnet 之packet
- write to and read from files (读写文件)
- vipca 经典报错 PRKH-1010 : Unable to communicate with CRS services.
- webview的input输入框获取焦点弹出数字键盘
- 云概念下,虚拟主机该何去何从
- gamekit开篇
- Ext,chrome 前端访问互联网接口问题
- linux 学习心得(纯新手)
- Android AlarmManager学习