Web

TCP详解

Posted by ShiYu on 2017-12-11

TCP协议结构

首先了解一下TCP报头结构:

TCP协议结构

  • **16位源端口(Source Port)和16位目的端口(Destination Port)**分别表示发送地址和目的地址的端口号,或许有人不理解为什么没有发送主机的ip和目的主机的ip,那是ip协议层的事情,和tcp协议无关

  • 32位序列号和32位确认序列号:序列号是用来标记包的顺序的,假设有一段需要传输的内容大小有9000字节,按照1460字节一个包的大小,假设初始序号为10000,那么我们就把这段内容分为10000-11460, 11460-12920,… 18760-19000 一共7个包。网络包由于网络问题,可能并不是顺序到达接收端的,那么接收端可以按照序列号来重新组装这段内容。

  • 4位数据偏移(Data Offset):4位包括TCP头大小,指示何处数据开始。

  • 6位保留字段(Reserved):6位值域,这些位必须是0。为了将来定义新的用途而保留。

  • 标志(Tag):就是上图中的URG,ACK,PSH,RST,SYN,FIN位,每个位置一表示的意思是:

    1. URG:紧急位,RFC已经建议废弃
    2. ACK:说明这个包中带有回复信息
    3. PSH:推标志。该标志置位时,说明这个包中有传输数据,接收端不将该数据进行队列处理,而是尽可能快地将数据转由应用处理。在处理Telnet或rlogin等交互模式的连接时,该标志总是置位的。
    4. RST:重置位,说明这个包是用来要对方重置连接
    5. SYN:建立连接,说明发送方向另一方发送建立连接的请求
    6. FIN:结束位,说明发送一方告知另外一方,要请求中断连接
  • 16位窗口大小(Window):用来表示想收到的每个TCP数据段的大小。TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个16字节字段,因而窗口大小最大为65535字节。

  • 16位校验和(Check Sum):16位TCP头。源机器基于数据内容和tcp头部计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。

  • 16位紧急指针(Urgent Pointer):指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。但是在RFC6093中已经明确,紧急数据已经是废弃功能了。不建议使用。只为旧程序兼容而使用。所以,对于Urgent Porinter和tag中的URG标示就不要使用了。

  • 选项和填充(option和padding):options字段相当于扩展使用的,RFC有哪些信息要传输,而头部没有安排的字段,就可以放在options中进行传输。padding是为了对齐字节位。

握手与挥手

著名的三次握手四次挥手

TCP三次握手与4次挥手

上图中client和server分别代表发送方和接收方,3次握手的过程为:首先client向server发送一个SYN请求建立连接,server返回一个ACK确认收到请求,并携带SYN请求建立双向连接,client再返回一个ACK个server确认,这就是著名的3次握手。

4次挥手的过程为:首先client发送一个FIN给server主动请求断开连接,server返回一个ACK确认,接着server再向client发送一个FIN请求断开连接,client收到后返回一个ACK确认,这个时候连接就终端了。

为什么需要3次握手

TCP建立连接采用3次握手的目的是为了防止已经失效的连接请求报文段突然又传送到服务端,因而产生错误,假设client发出的一个报文没有丢失,而是在某个网络节点长时间滞留了,导致在延误了很长时间后才到达server,而这个时候这个报文早已失效了。server收到这个报文后,就会认为是一个新的请求,向client发送ACK,同意建立连接,如果不采用3次握手,那么这个时候连接就已经建立完毕了,由于client并没有向server请求连接,client便不会理睬server的确认,但server却认为连接已经建立并一直等待client发送数据,这就造成了server资源的浪费,采用3次握手可以解决上述情况。

为什么需要4次挥手

在tcp连接握手时为何ACK是和SYN一起发送,这里ACK却没有和FIN一起发送呢?原因是因为tcp是全双工模式,接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据。所以收到断开连接的请求后,server获取还有要发送的数据没有发送,等发送完毕后才会向client发送FIN请求断开连接。