资源简介
本文主要介绍了网络协议的拆包与封包过程,如:rtp,udp等等协议的拆包与封包,不管是什么协议原理都是一样的,如果深入掌握了其中的一个,那么在以后网络协议方面的分析就变得更加得心应手了。从中介绍了大小端问题以及位段操作等等。
网终协议的封包与拆包方法 BitFEDCBA9876513210 -------MSB LSB- Wa110001011|10001010 Ox8A Ox8B 因此、现在就存在个如何处理网络字节序的问题?稍微处理不正确那么就会出现错误, 如上面的0x0800很有可能处理成0x0008了。 位段 信息的存取一般以字节为单位,如上所示,如果是一个字节那么就不存在字节序,即大 小端问题。而实际上,我们有时候存储个信息不必要用个或者多个字节序,例如:“真” 或“假”用0或1表小,只需要1位即可。因此,以下就来看看在一个byte中如何处理不 同的bit,这在网络协议中应用是非常广的。如RTP协议就存在着不同的bit代码不同的意 思,那么我们应该如何处理这些bit呢? 0 01234567890123456789012345678901 =2Px CC MFI sequence number timestamp synchronization source (SSRC) identifier contributing source (CSRc) identifiers 处理一个字节的不同bit有以下两种方法: 第一、人为的将一个byte变量data分为几部分 如读取data的第4biL的C操作方法data(0x1<4),此种操作方法是不是在单片机操 作中很熟悉呢?我们在操作某位gpio口的时候就经常采用此和方法 第二、利用位段 C语言允许在一个结构体中以位为单位来指定其成员所占内存的长度,这种以位为单位 的成员称为“位段”或称为“位域”( bit field)。利用位段能够用较少的位数存储数据 如 packed-data所示 struct packed-data unsigned a unsigned b: 6 unsigned C: 4 unsigned d: 4 int 1: i data C y人人 32 第3页/共10页 网终协议的封包与拆包方法 因此,接下来你或许会发现以下一个问题,在位段中仍然存在着字节序的问题,如下:0x8B 大端 小 01234567 76543210 MSB- MSB--- LSB 10001010 10001010 Ox8B 所为,我们发现,如果同一byte里面区分了不同的bit的时候,此时就会存在大小端问题 此时,我们用位段去处理的时候只需要记住以卜要点:如果本地的内存存储方式是小端格 式,那么在处理大端格式的时候就需要人为的将位段处理结构体变化成大端格式;如果本 地的内存存储是大端格式,那么无需变化。 、协议的封包与拆包 我们在了解了上面的基础知识以后,或许还不是特别理解,并且我们会考虑如何应用到 实际情况昵?卜面我们通过例举实际情况以加深理解 例子1、UDP协议的拆包 首先、 google输入 udp rfc,可以查看到UDP的 header format,如下所示: 78 1516 232431 Source Destination Port + + Leng th Checksum 可以看出udp的四部分: Source port, Dest port, Length以及 Checksum都是占用了 两个字节,因此,存在着字节序的问题。下面对其进行封装,如下所示: typedef struct Udplleader Tag unsigned short m nSrcPort unsigned short m nDs tPort unsigned short m nLen unsigned short m nCrc J UdpHeade 我们用 wireshark抓包一个udp的包,如下所示 页/共10页 网终协议的封包与拆包方法 E User Datagr am Protocol, src Port: domain (53), Dst Port: 59161 (59161 Source port: domain (53> Destination port: 59161 (59161) Leng g Checksum: 0x02d5 varication disabled] d checksum: Falsel Bad checksum: False」 0000b870f403fc120C02a5420058864110c 0.,d 00100412006900245000067000000004011...1·!E..g..· 00201feca6086210a000070035719009…:·!·5 3031036e65740050010001c00c0c 00500100010c00003c0004b4a913aoc00c0c 00600100010c00003c0004b4a91483c00c0c 00700100010C00003c0004b4a914tb 从中可以看出, source port是53, destination port是59161, lenth是83, checksum 是0x02d5,然后,我们通过接收处理到的 buffer值会是0x00,0x35,0xe7,0x19,0x00,0x53, x02,0xd5,那么我们如何处理这些值?从而止确的分析udp头呢?在程序测试之前,我们 首先来分析内存情况。 如果本地是小端模式,如x86、am系列处理器,那么 buffer在内存中的分布如下 LoW 0x00 src low rc high 0x35 dst low dst high Oxen Tem len h x19 crc 1 crc h 0x00 x53 0x02 High Oxd5 左边为 buffer内存分布示意图,右边为 UdpHeader内存示意图 因此、如 source port在 buffer中存储的大端模式是0x00,0x35,但是到了小端处理器(x86、arm 进行处理的时佚,就会出现 UdpHeader中的 src port为0x3500现象,因此,与实际的 source port为53 完仝不同。测试结果如下所示 c0t35(13568) dest port 19e7(6631> len port 5300(21248> rc port d552(54530> 测试代码: 第5页/共10页 网终协议的封包与拆包方法 typedef struct UdpHeaderTag short m nsi unsigned short m nDstPort d short m nl unsigned short m nCrc J UdpHeader int main (int argc, char *argyI char buffer-{0x00,0x35,0xe7,0x19,0x00,0x53,0x02,0xd5}; UdpHeader =kpUdpHeader =(UdpHeader **)buffer printf( src port %04x(%cd)\n", pLdplleader->m nSrcPort, pUdplleader->m nSrcPort printf( dest port %04x (%d)n", pUdpHeader->m nDstPort, pUdpHeader->m n Ds tPort) printf( len port %04x(ocd)\n, pUdpHcader->m nLen, pUdpHcader->m nLen printf(crc port %04x(cd)\n, pUdpHeader->m nCre, pUdpHeader->m nCrc) 但是,如果将上述代码运行在大端处理器( powerpc),则不会出现以上现象,原因如下 LOW 0x00 Src_high src low 0x35 dst high dst lot Oxel Ten en crc h Crc x19 x00 x53 0x02 High 左边为 buffer内存分布示意图,右边为 UdpHeader内存示意图 因此、当在小端模式(x86、arm)处理器上处理网络协议的时候,则需要注意字节序的问题 如以上修改为如下格式即可了正确解析 udp header了。 #include <stdio. h> #inc lude <winsock. hy 页/共10页 网终协议的封包与拆包方法 typedef struct UdpHeaderTag short m nsi unsigned short m nDstPort unsigned short m nLen gned short m nC J UdpHeader char*argv「 bufferLl-0x00, 0x35 0 UdpHeader =kpUdpHeader =(UdpHeader **)buffer printf("转换前:n"); printf ("src port %04x(ocd)\n, pUdpHcader->m nSrcPort, pUdpHcadcr->m nSrc Port printf( dest port %04x(%d)\n", pUdpHeader-m nDst Port, pUdpHeader->m nDs tOrt) printf(" len port %01x(o%cd)\n, pUdpHeader->m nLen, pUdpHeader->m nLen) printf(crc port %04x(%d)\n", pl. dpHeader->m nCrc, pl dpHeader->m nCrc printf("转换后:\n") printf pUdpHeader->m nSrcPort ntohs(pUdpHeader->m nSrcPort) pUdpHeader->m nlst Port = ntohs(pUdpHeader->m nDstl'ort) pUdpHeader->m nLen ntohs(pUdpHeader->m nLen pUdpHcador->m nCrc-ntohs(pUdpHcadcr->m nCrc) printf( src port %04x(%d)\n, pLdplleader->m nSrcPort, pUdplleader->m nSrc Port) printf("dest port %04x(%d)\n", pUdpHeader->m nDstPort, pUdpHeader->m nDs tPort) printf(len port 9004x(%d)n, pl. dpHeader->m nLen, pU dpHeader->m nL. en) printf( cre port %04x(%d)\n", pUdpHeader->m nCrc, pUdpHeader->m nCrc 协议的封包,同样以 udp header封包为例,如上我们知道了 source port是53, destination port是59161, lenth是83, checksum是0x02d5,然后我们如何封包成网终 码流发送出去呢? 通过了以上对网络数据的拆包详细了解以后,我们知道如果在小端处理器处理接收到的 网络数据,那么则需要将网络数据的网络格式转换成本地格式,即 ntohs、 nohl,那么同 样,如果在小端处理器上发送数据到网络上,那么,则需要首先将本地的数据格式转换成网 终数据格式,即 hons、 htonl,因此,封包过程请读者进行相应测试。 以上都是介绍的是大于一个byte的宁节序问题,可是我们往往一个字节内也分成了不 同的功能作用,而从基础知识中我们发现了如果一个字节內也区分了不同的功能模块,那么 也会存在着字节序的问题。 第7页/共10页 网终协议的封包与拆包方法 例如: NALU Header由三部分组成,如下所示 0112134|567 -+-+-+-+-+-+-+- IF NRI Type 如果,此时该项为0x7C,那么你知道其中F、NRI、Type分别为多少么?其实,大端模 式如上面提到的是最直观的字节序,如卜所示: 0123|4|567 -+-+-+-+-+-+-+- F NRI Type 01111100 因此、其中F为0,NRI为3,Type为0xlc(28),可以我们如何用代码进行区分呢? 此处,就需要用到前面提到的位段模式∫。我们通过位段定了∫NALU结构体,如下所小: typedef struct NALUHcaderTag unsigned char F: 1 unsigned char NrI unsigned char TYPE: 5 LNALUHcadcr 因此,我们编写了如下测试代码,解析 typedef struct NALUHeader ta unsigned char F unsigned char NRI: 2 unsigned char TYle: 5 I NALUHeader int main (int argc, char argv []) unsigned char nal=0x7c: NALUHeader *pnal=(NALUHeader *)&nal printf(F: %d\n", pnal->F) printf( Nri: %d\n, pnal->NRI) printf( TYPe: %d\n, pnal->TYPD) 运行结果如下 页/共10页 网终协议的封包与拆包方法 F:0 NRI: 2 TYPE: 15 我们发现这似乎并不是我们想要的结果?问题出现在哪儿呢? 我们仍然采用前面的方法进行分析,分别绘制出内存分布图,如下所示 011 1100 NRI F 个 L 因此、我们现在就不难发现其中的问题了,此处也是存在着一个对应关系,正如前面我 们处理的方式是进行了转换,即将在小端CPU上处理网络数据的时候,将网络数据转换到本 地的小端格式冉进行处理,如果在小端CP上发送数据到网络上的时候,那么只需要将本地 的小端数据转换成网终格式,即大端格式。 那么,此处我们是否仍然可以采用同样的方法进行呢?然而,我们发现其中的困难了, 其一,以上格式如果进行转換,那么运算起来比较复杂,并且没有标准的转换函数;其二, 以上只是一种bit顺序,如果变化了呢?因此,以下提出一种方法进行处理 我们知道κ络数据是大端格式,那么我们在小端CPU上能否使用大端方式杓造位段结构 体呢?内存分布如下所示: 01111100 NRI丬TYPE H 转换成C格式如下 typedef struct NALUheadertag unsigned char TYPE: 5; unsigned char unsigned char F: 1 3 NALUHeader 运行结果如下: NRI: 3 TYPE: 28 三、总结 第9页/共10页 网终协议的封包与拆包方法 通过以上的分析、学习,我相信在以后的网终协议的分析过程中,基本上不会有在什么 大问题。有的只是需要耐心的理清楚整个内存的分部情况。下面总结以下几点 1、什么时候存在字节序问题? 由两个及两个以上字节组成的选项,则在网终传输,CPU处理的时候存在字节序问题? 参考 UDP Header实例 个字节里面区分了不同的bit位的时候,则存在字节序问题,参考 NAL Header实 例; 2、什么时候需耍处理字节序问题? 记住网终传输采用大端模式,如果处理数据的CPU是小端模式(x86、arm),那么需要 处埋宇节序问题。如果处理数据CPU是大端模式( powerpc),那么不存在宇节序问题。 当需要处理字节序问题时,有以下两种方法: 第 处理两个或者四个字节组成的近项时,采用 tons、 nohl、 hons已经 htonl 进行转换。 第二、处理一个字节内的选项时,则采用位段结构体,即将位段结构体定义为人端 格式 致读者 如果您觉得本文的哪些地方需要改进或是存在一些不明白的地方,请点击这里并留言。 修订历史 修订说明 2013-08-24 新增文档 0页/共10页
代码片段和文件信息
- 上一篇:百度地图城市编码city_code
- 下一篇:单片机原理及其接口技术 胡汉才 答案
相关资源
- 李晓峰通信原理.zip
- 图解西门子S71200PLC入门到实践(清晰
- AI拓客商家联盟V2.1.3前端+后端.rar
- echarts大数据领导仓demo.rar
- [C51单片机开发工具Keil.UV4].Keil.C51.V9
- Deep_Learning_2016.pdf
- zw_Classification1.zip
- Griffiths-IntroductiontoElectrodynamics4thEdit
- ParaViewTutorial.pdf
- xyisv_10236804.zip
- 计算机图形学第4版高清电子书.pdf
- 《多粒度知识获取与不确定性度量》
- 华成英模电课件.zip
- 70d0cd041f738f12db575d3b46e97582.pdf
- OfficeTabEnterprise13.1.zip
- wxu998.rar
- PowerDesigner16.5汉化文件.rar
- jsgis.zip
- PinyinIME(关键代码写了注释).zip
- 锁相环设计、仿真与应用第5版中.pd
- novelOnLine.zip
- SingleSensorImagingMethodsandApplicationsforDi
- ControlSystemsEngineering7th(NormanS.Nise)
- ModernControlSystems13th(RichardC.Dorf).ra
- VectorMagic_1.15pojie.rar
- complexityoflattice__problems.pdf
- xnby_883749.zip
- TOGAF培训讲义-周金根.pdf
- OS12.2驱动,手机虚拟定位软件,Loca
- 大话系列-大话数据结构(pdf高清版)
评论
共有 条评论