最近在工作中涉及到使用一种4G 的DTU 模块与服务器后台通信。因在部分场景下需要在消息中传输文件(通过base64),因此考虑到以下两个问题:
1) TCP连接 是否保证多次send(发送)的数据与接收数据顺序一致?
2)TCP连接 调用一次send中发送数据,在数据比较大的情况下,是否分为多个tcp包发送?
为方便采用wireshark 分析TCP包,列出TCP协议字段含义如下:
16位源端口号:TCP 发端 端口号(标示发送方计算机上的应用程序收发端口)。
16位目的端口号:TCP 接收端端口号(标示接收方计算机上应用程序收发端口)
32位序号(sequence number):将整个一次TCP 通讯(从三次握手到四次挥手)中传输的发送方发送的数据作为一次流动的字节流,32位序号,它表示在发送的这个报文段第一个字节在整个字节流中所处的字节位置。在tcp中tcp用序号对每个字节进行计数(这个值与发送的帧数没有关系,而是与发送的数据字节数有关系)。
32位确认序号:一次TCP通讯中,发送该报文的发送方,确认收到的另一方发送过来的字节序+1(即所期望收到的下一个序号)。
4位数据偏移:即TCP头大小,指示何处“数据”开始。一般为20字节,实际值为首部长度除以4。
保留(6位):6位值域,这些位必须是0。
URG: 紧急指针( urgent pointer)有效。
ACK: 确认序号有效。
PSH: 接收方应该尽快将这个报文段交给应用层。
RST: 重建连接。
SYN: 同步序号用来发起一个连接。
FIN: 发端完成发送任务。
16位窗口大小:流量控制,用来表示想收到的每个TCP数据段的大小。
16位校验和:检验和覆盖了整个的 TCP报文段(TCP首部和TCP数据),收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段。
16位紧急指针:指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。
选项:长度不定,但长度必须为1个字节。如果没有选项就表示这个1字节的域等于0。
数据:该TCP协议包负载的数据。
- wireshark 分析TCP 协议
- 发送 3个字符串
如上图所示发送“123”,这个字符串。注意此时sequence number 为1, TCP segment data 为3 bytes。 则下一次发送的报文起始字节为【next sequence number:4】。
- 发送长字符串
接着发送1个大小为2523 字节的长字符串。
wireshark捕获到的数据如下:
可以看出: 2523字节长度的数据被分为了len=1452,和len=1071 这2个报文发送。
观察其中的第一个报文,可以发现Sequence number:4。
正好对应了第一次发送3个字节的短字符串【next sequence number:4】。
因此可以得出结论: 多次send之间tcp连接通过字节流序,保证了收发字节顺序的一致。
为什么2523字节长度的数据被分为2个数据包发送1452,1072 2个报文发送?
通过观察整个通讯流程,发现在三次握手时,有mss协商:
。因此可以得出结论:
理论上tcp没有规定1个tcp报文数据长度,但通过三次握手协商了各方最大发送的数据长度。因此超过这个长度的数据将被分包。
- UDP协议分析:
源端口和目的端口:(端口是用来指明数据的来源(应用程序)以及数据发往的目的地(同样是应用程序))字段包含了16比特的UDP协议端口号,它使得多个应用程序可以多路复用同一个传输层协议及UDP协议,仅通过端口号来区分不同的应用程序。
长度(length):字段记录了该UDP数据包的总长度(以字节为单位),包括8字节的UDP头和其后的数据部分。最小值是8(报文头的长度),最大值为65535字节。
UDP校验和(Checksum):的内容超出了UDP数据报文本身的范围,实际上,它的值是通过计算UDP数据报及一个伪包头而得到的。校验和的计算方法与通用的一样,都是累加求和。UDP数据报中实际的有效成分。伪首部并非TCP&UDP数据报中实际的有效成分。伪首部是一个虚拟的数据结构,其中的信息是从数据报所在IP分组头的分组头中提取的,既不向下传送也不向上递交,而仅仅是为计算校验和。这样的校验和,既校验了TCP&UDP用户数据的源端口号和目的端口号以及TCP&UDP用户数据报的数据部分,又检验了IP数据报的源IP地址(数据源设备)和目的地址。伪报头保证TCP&UDP数据单元到达正确的目的地址。
经过试验,无论多大包,从udp协议这一层级来说,并没有分为多个udp包。在试验中: 当包的长度达到10153时,接收端根本无法接收到发送的包(发送发并不能得到是否接收成功的消息)。
建议发送的包长度不超过512 byte。