1.序

在TCP/IP中能够实现传输层功能的、具有代表性的协议是TCP和UDP,来一起看看TCP UDP的构造吧。

2.tcp协议:

TCP各个字段意义

2.1源端口和目的端口:

计算机上的进程要和其他进程通信是要通过计算机端口的,而一个计算机端口某个时刻只能被一个进程占用,所以通过指定源端口和目标端口(各占2个字节),就可以知道是哪两个进程需要通信。

源端口、目标端口是用16位表示的,可推算计算机的端口个数为2^16个(65535)。

2.2序列号

TCP 是面向字节流的,在一个 TCP 连接中传输的字节流中的每个字节都按照顺序编号。

序列号(占 4 个字节)表示本报文段所发送数据的第一个字节的编号。在TCP连接中所传送的字节流的每一个字节都会按顺序编号。<mark>由于序列号由32位表示,所以每2^32个字节,就会出现序列号回绕,再次从 0 开始</mark>。

例如 100 kb 的 HTML 文档数据,一共 102400 (100 * 1024) 个字节,那么每一个字节就都有了编号,整个文档的编号的范围是 0 ~ 102399。
序号字段值指的是本报文段所发送的数据的第一个字节的序号。
那么 100 的 HTML 文档分割成四个等分之后,
第一个 TCP 报文段包含的是第一个 25kb 的数据,0 ~ 25599 字节, 该报文的序号的值就是:0
第二个 TCP 报文段包含的是第二个 25kb 的数据,25600 ~ 51199 字节,该报文的序号的值就是:25600

根据 8 位 = 1 字节,那么 4 个字节可以表示的数值范围:[0, 2^32],一共 2^32 (4294967296) 个序号。
序号增加到最大值的时候,下一个序号又回到了 0.
也就是说 TCP 协议可对 4GB 的数据进行编号,在一般情况下可保证当序号重复使用时,旧序号的数据早已经通过网络到达终点或者丢失了。

2.3确认号

TCP 的可靠性是建立在每一个数据报文都需要确认收到的基础之上的。也就是说,通讯的任何一方在收到对方的一个报文之后,都要发送一个相对应的确认报文(确认报文就会包含确认号)来表达确认收到。

确认号(占4个字节,32位):表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。

例如,通讯的一方收到了第一个25kb的报文,该报文的序号值=0,那么就需要回复一个确认报文,其中的确认号 = 25600(0-25599,所以期望收到的是25600).

2.4数据偏移

数据偏移占0.5个字节(4位)指出TCP<mark>报文段的数据起始处</mark>距离TCP<mark>报文段的起始处</mark>有多远。这个字段实际上是指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的,但应注意,“数据偏移”的单位是32位字(即以4字节的字为计算单位)。
由于4位二进制数能表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大字节(即选项长度不能超过40字节,因为除去选项部分TCP首部加起来是20字节)。

2.5保留

占 0.5 个字节 (4 位)。
保留为今后使用,但目前应置为 0。

2.6控制位

占 1 个字节 (8位)

1.紧急URG:

当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。
当URG置为1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。

2.确认ACK:
表示是否前面的确认号字段是否有效。ACK=1,表示有效。只有当ACK=1时,前面的确认号字段才有效。TCP规定,连接建立后,ACK必须为1。
TCP规则除了最初建立时的SYN包之外该为必须设置为1。

3.推送PSH:
当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置为1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程。而不用再等到整个缓存都填满了后再向上交付。

4.复位RST:
只有当RST=1时才有用。如果你收到一个RST=1的报文,说明你与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。或者说明你上次发送给主机的数据有问题,主机拒绝响应。

该位为1时表示TCP连接中出现异常必须强制断开连接。例如,一个没有被使用的端口即使发来连接请求,也无法通行。此时就可以返回一个RST设置为1的包。此外,程序宕掉或切断电源等原因导致主机重启的情况下,由于所有的连接信息将全部被初始化,所以原有的TCP通行也将不能继续进行。这种情况下,如果通信对方发送一个设置为1的RST包,就会使通信强制断开连接。

5.同步SYN:
在建立连接时使用,用来同步序号。当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当SYN=1,ACK=1时,表示对方同意建立连接。SYN=1,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中SYN才置为1。
SYN为1表示希望建立连接,并在其序列号的字段进行序列号初始值的设定。

6.终止FIN:
标记数据是否发送完毕。
该位为1时,表示不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN位置为1的TCP段。每个主机又对对方的FIN包进行确认应答以后就可以断开连接。不过,主机收到FIN设置为1的TCP端以后不必马上回复一个FIN包,而是可以等到缓冲区中所有数据都已成功发送而被自动删除之后再发。

2.6窗口

占2字节。表示现在允许对方发送的数据量。也就是告诉对方,从本报文段的确认号开始允许对方发送的数据量。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。

2.7检验和

占2字节。提供额外的可靠性。如何校验这里不做过多讲解,之后会写文章描述。
使用校验和的目的是什么?
有噪声干扰的通信途中如果出现位错误,可以由数据链路的FCS检查出来。那么为什么TCP或UDP中也需要校验和呢?

其实,相比检查噪声影响导致的错误,TCP与UDP的校验和更是一种进行路由器内存故障或程序漏洞导致的数据是否被破坏的检查。

有过C语言编程经验的人都知道,如果指针使用不当,极有可能会破坏内存中的数据结构。路由器的程序中也可能会存在漏洞,或程序异常宕掉的可能。 <mark>在互联网中发送数据包要经由好多个路由器,一旦在发送途中的某一个路由器发生故障,经过此路由器的包、协议首部或数据 就极有可能被破坏。即使在这种情况下,TCP或UDP如果能够提供校验和计算,也可以判断协议首部和数据是否被破坏。</mark>

2.8紧急指针

占2字节。标记紧急数据在数据字段中的位置。
<mark>紧急指针仅在URG=1时才有意义</mark>,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。因此,在紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,<mark>即使窗口为0时也可以发送紧急数据</mark>。
如何处理紧急数据属于应用的问题。一般在暂时中断通信,或中断通信的情况下使用。例如在Web浏览器中点击停止按钮,或者使用 TELNET输入Ctrl+C时都会有URG为1的包。此外,紧急指针也用作表示数据流分段的标志。

2.9选项

选项字段用于提高TCP的传输性能,因为根据数据偏移(首部长度)进行控制,其长度最大为40字节。

<mark>类型2</mark>的MSS选项用于在建立连接时决定最大段长度的情况。这选项用于大部分操作系统。
MSS最大报文段长度(Maxium Segment Size):指明数据字段的最大长度,数据字段的长度加上TCP首部的长度才等于整个TCP报文段的长度。MSS值指示自己期望对方发送TCP报文段时那个数据字段的长度。通信双方可以有不同的MSS值。如果未填写,默认采用536字节。MSS只出现在SYN报文中。即:MSS出现在SYN=1的报文段中。

<mark>类型3</mark>的窗口扩大选项(Windows Scaling),是一个用来改善吞吐量的选项。TCP首部中窗口字段只有16位。所以其表示的最大数是65535。因此在TCP包的往返时间(RTT)内,只能发送最大64K字节的数据。如果采用了该选项,窗口的最大值可以扩展到1G字节。由此,即使在一个RTT较长的网络环境中,也能达到较高的吞吐量。随着时延和带宽比较大的通信产生(如卫星通信),需要更大的窗口来满足性能和吞吐率,所以产生了这个窗口扩大选项。

<mark>类型8</mark>时间戳选项(Timestamps),可以用来计算RTT(往返时间),发送方发送TCP报文时,把当前的时间值放入时间戳字段,接收方收到后发送确认报文时,把这个时间戳字段的值复制到确认报文中,当发送方收到确认报文后即可计算出RTT。

用于高速通信中对序列号的管理。若要将几个G的数据高速转发到网络时,32位序列号的值可能会迅速使用完。在传输不稳定的网络环境下,就有可能会在较晚的时间点却收到散布在网络中的一个较早序列号的包。而如果接收端对新老序列号产生混淆就无法实现可靠传输。为了避免这个问题的发生,引入了时间戳这个选项,它可以区分新老序列号。 (也可以用来防止回绕序号PAWS,也可以说可以用来区分相同序列号的不同报文。因为序列号用32为表示,每2^32个序列号就会产生回绕,那么使用时间戳字段就很容易区分相同序列号的不同报文。)

<mark>类型5</mark> SACK选择确认项(Selective Acknowledgements):用来确保只重传缺少的报文段,而不是重传所有报文段。比如主机A发送报文段1、2、3,而主机B仅收到报文段1、3。那么此时就需要使用SACK选项来告诉发送方只发送丢失的数据。那么又如何指明丢失了哪些报文段呢?使用SACK需要两个功能字节。一个表示要使用SACK选项,另一个指明这个选项占用多少字节。描述丢失的报文段2,是通过描述它的左右边界报文段1、3来完成的。而这个1、3实际上是表示序列号,所以描述一个丢失的报文段需要64位即8个字节的空间。那么可以推算整个选项字段最多描述(40-2)/8=4个丢失的报文段。
  
类型1 NOP(NO-Operation):它要求选项部分中的每种选项长度必须是4字节的倍数,不足的则用NOP填充。同时也可以用来分割不同的选项字段。如窗口扩大选项和SACK之间用NOP隔开。

2.10填充

如同 IP 封包需要有固定的 32bits 表头一样, Options 由于字段为非固定, 所以也需要 Padding 字段来加以补齐才行。同样也是 32 bits 的整数。
这是为了使整个首部长度是4字节的整数倍。

3.UDP协议:

3.1源端口号:

表示发送端端口号,字段长16位。该字段是可选项,有时可能不会设置源端口号。没有源端口号的时候该字段的设置为0。可用于不需要返回的通信中。

3.2目标端口号:

表示接收端端口,字段长度16位。

3.3包长度:

该字段保存了UDP首部的长度跟数据的长度之和。单位为字节。

3.4校验和:

校验和是为了提供可靠的UDP首部和数据而设计的。

1.使用校验和的目的是什么?

有噪声干扰的通信途中如果出现位错误,可以由数据链路的FCS检查出来。那么为什么TCP或UDP中也需要校验和呢?

其实,相比检查噪声影响导致的错误,TCP与UDP的校验和更是一种进行路由器内存故障或程序漏洞导致的数据是否被破坏的检查。有过C语言编程经验的人都知道,如果指针使用不当,极有可能会破坏内存中的数据结构。路由器的程序中也可能会存在漏洞,或程序异常宕掉的可能。在互联网中发送数据包要经由好多个路由器,一旦在发送途中的某一个路由器发生故障,经过此路由器的包、协议首部或数据就极有可能被破坏。即使在这种情况下,TCP或UDP如果能够提供校验和计算,也可以判断协议首部和数据是否被破坏。

2.如何校验?

和计算IP数据报首部检验和方法相似,但UDP把首部和数据部分一起检验,该方法检错能力不强,但简单快。
(1) 发送方:首先把全0放入检验和字段,再把伪首部及UDP数据报看为16位字节串联,若UDP数据报数据部分为奇数则要填入一个全零字节(该字节不发送),按二进制反码计算出这些16位字节的和,然后写入检验和字段,发送该UDP数据报。
(2) 接收方:把收到的数据报连同伪首部按二进制反码求和,当无差错结果全为1,否则丢弃该数据。

<mark>另外,UDP中也有可能不用校验和。此时,校验和字段中填入0。这种情况下,由于不进行校验和计算,协议处理的开销就会降低,从而可以提高数据转发的速度。然而,如果UDP首部的端口号或是IP首部的IP地址遇到损坏,那么可能会对其他通信造成不好的影响。因此,在互联网中比较推荐使用校验和检查</mark>。

3.校验和为什么需要UDP伪首部?

为什么在进行校验和计算时,也要计算UDP伪首部呢?TCP/IP中识别一个进行通信的应用需要5大要素,它们分别为“源IP地址”、“目标IP地址”、“源端口”、“目标端口”、“协议号”。然而,在UDP的首部中只包含它们当中的两项(源端口和目标端口),余下的3项都包含在IP首部里。

假定其他3项的信息被破坏会产生什么样的后果呢?很显然,这极有可能会导致应该收包的应用收不到包,不该收到包的应用却收到了包。为了避免这类问题,有必要验证一个通信中必要的5项识别码是否正确。为此,在校验和的计算中就引入了伪首部的概念。

此外,IPv6中的IP首部没有校验和字段。TCP或UDP通过伪首部,得以对5项数字进行校验,从而实现即使在IP首部并不可靠的情况下仍然能够提供可靠的通信传输。

4.UDP是不可靠传输,为什么需要校验和?

UDP之所以不可靠是因为:
不保证消息交付:不确认,不重传,无超时
不保证交付顺序:不设置包序号,不重排,不会发生队首阻塞
不跟踪连接状态: 不必建立连接或重启状态机
不需要拥塞控制: 不内置客户端或网络反馈机制

UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。但是,对于每个数据报,还是要求尽可能提高传输可靠性。UDP中的“检查和”是为了尽可能提高<mark>本数据报</mark>的可靠性手段

4.参考连接

https://www.cnblogs.com/fantastic123/p/8968132.html
https://blog.csdn.net/weixin_41563161/article/details/104229761
《图解TCP/IP》

优质文章推荐

1.计算机网络----三次握手四次挥手
2.一篇让你彻底了解http请求报文和响应报文的结构
3.梦想成真-----项目自我介绍
4.一篇让你彻底了解HTTP 的前世今生
5.一篇让你彻底搞定HTTP方法与状态码
6.你们要的设计模式来了
7.震惊!来看《这份程序员面试手册》!!!
8.一字一句教你面试“个人简介”
9.接近30场面试分享