TCP协议详解----Linux学习笔记

来源:互联网 发布:java创建服务器 编辑:程序博客网 时间:2024/06/01 07:11

传输层概述

传输层协议主要有两个:TCP协议和UDP协议

TCP服务特点:
TCP协议的特点是:面向连接、字节流和可靠传输。(相对UDP协议而言的)
面向连接:
1.使用TCP协议的双方必须先建立连接,然后才能开始数据的读写。
2.双方都必须为该连接分配必要的内核资源以管理连接的状态和连接上数据的传输。
3.同时TCP协议是全双工的。也就是说双方的数据读写可以通过一个连接进行,完成数据交换之后通讯双方都必须断开连接以释放系统资源。
4.TCP协议的连接时一对一的。所以基于广播和多播的应用程序不能使用TCP服务。然而无连接协议UDP,就非常适合于广播和多播。

字节流:
字节流服务和数据报服务的区别:
对应于实际编程中就是通讯双方是否必须执行相同次数的读写操作。当发送端应用程序连续执行多次写入操作时,TCP模块必须先把这些数据放入TCP发送缓冲区中,当TCP模块真正开始发送数据时,发送缓冲区中这些等待发送的数据才可能封装成一个或多个TCP报文段发出。所以TCP模块发送出来的TCP报文的个数和应用程序执行的写操作次数之间没有固定的数量关系。而且当接收端收到一个或多个TCP报文段后,TCP模块必须把它们携带的应用数据按照TCP报文段的序号依次放入TCP接收缓冲区中,同时通知应用程序读取数据,这样一来,接收端应用程序可以一次性将TCP接收缓冲区中的数据全部读出,也可以分多次读出,这就取决于用户指定的应用程序读缓冲区的大小,因此应用程序执行的读操作次数和TCP模块接收到的TCP报文段个数之间也没有固定的数量关系。
总而言之:发送端执行的写操作次数和接收端执行的读操作次数,这两者之间没有任何数量关系。应用程序对数据的发送和接收是没有边界限制的。然而UDP并不是这样,对于UDP来说,发送端应用程序没执行一次写操作,UDP模块就必须将其封装成一个UDP数据报,并发送这个数据报,到了接收端它必须针对每一个UDP数据报执行读操作,否则就会发生丢包,并且如果用户没有指定足够的应用程序缓冲区来读取UDP数据报,那么UDP数据包就会截断。
可以从下图来区分TCP的字节流服务和UDP的数据报服务的区别:
这里写图片描述
这里写图片描述

可靠:
支撑TCP服务的可靠机制有:
1.TCP协议采用发送应带机制
也就是说发送端发送的每一个TCP报文段都必须得到接收方的应答,才认为这个TCP报文段传输成功
2.TCP协议采用超时重传机制
也就是说发送端在发送出一个TCP报文段之后就启动定时器,如果在定时时间内没有收到应答,那么就会重新发送这个报文段,同时TCP报文段最终是以IP数据报发送的,而IP数据报到达接收方可能乱序、重复。TCP协议同时会对接受的TCP报文段重排整理在交付给应用程序。
然而UDP数据报的服务中提供的是不可靠的服务。它们都需要上层协议来处理数据的确认和超时重传。

TCP头部信息:
TCP头部信息出现在每个TCP报文段中,它用于指定通信的原端端口、目标端端口、管理TCP连接等这些任务。下图为TCP的头部结构:
这里写图片描述
包括:20个字节的固定头部结构和40个字节的头部选项字段。
头部信息结构中每个字段的作用说明:
16位原端端口号和16位目的端端口号:
主要作用是告知主机该报文段来自哪里(哪里指的就是原端端口)以及传给哪个上层协议或者应用程序等(指的是目标端端口)。客户端通常使用系统自动选择的临时端口号,而服务器使用的是知名的服务器端口号(在Linux下知名服务器的端口号都定义在/etc/services这个文件中,常用的知名端口:HTTP服务:80、DNS服务:53、FTP服务:21)。
32位序号:
在一次TCP通信中(这里的一次TCP通信是指从TCP建立连接到断开着整个过程中)在某个传输方向上的字节流的每个字节编号就是由这个32位序号来进行确认的。
32位确认号:
对于对另一方发送来的TCP报文段的响应,它的值是收到的TCP报文段的序号值+1。比如:主机A和主机B进行TCP通信,那么A发送出的TCP报文段不仅携带自己的序号而且包含对B发送来的TCP报文段的确认号。反过来说,B发送来的TCP报文段也同时携带自己的序号和对A发送来的报文段的确认号。
4位头部长度:
标识该TCP头部有多少个4字节。其中四位最大值能表示15。所以TCP头部最长也就是60个字节。
6位保留
6位标志:
URG:表示紧急指针是否有效
ACK:表示确认号是否有效,我们称ACK标志的TCP报文段为确认报文段。
PSH:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间,因为应用程序不把接收到的数据读走,那么这些数据就会一直停留在TCP接收缓冲区中,TCP接收缓冲区是存储在内核中的,这样也就会占用很大的内核资源。
RST:表示要求对方重新建立连接。我们称携带RST标志的TCP报文段为复位报文段。
SYN:表示请求建立一个连接。我们称携带SYN标志的TCP报文段为同步报文段。
FIN:表示通知对方本端要关闭连接了。我们称携带FIN标志的TCP报文段为结束报文段。
16为窗口大小:
是TCP流量控制的一个手段,这里说的窗口是接收通告窗口(ReceiverWindow),告诉对方本端的TCP接收缓冲区中还能容纳多少字节数据,这样对方就能够控制发送数据的速度。
16位校验和:
由发送端填充,接收端对TCP报文段执行CRC算法来检验TCP报文段在传输过程中是否损坏。这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的重要保障。
16位紧急指针:
表示最后一个紧急数据的下一字节的序号。
头部选项:
具体如下图所示:
这里写图片描述
Kind:说明选项的类型。有的TCP选项没有后边两个字段,仅包含以字节的Kind字段。
length:指定该选项的总长度
info:是选项的具体信息

常见的TCP选项有七种:
这里写图片描述
kind=0:是选项表结束选项。
kind=1:空操作选项,没有特殊含义
kind=2:表示最大报文段长度选项
TCP连接初始化时,通讯双方使用该选项来协商最大报文段的长度,TCP模块通常把最大报文段长度设置为mtu-40(字节),这40字节就是20字节的TCP头部和20字节的IP头部,这样一来,携带TCP报文段IP数据报的长度就不会超过mtu,这么一说,对于以太网来说,最大报文段长度就是1460字节。
kind=3:窗口扩大因子选项
在TCP连接初始化时,通讯双方使用该选项来协商接收通告窗口的扩大因子,在TCP的头部中接收通告窗口的大小是用16位表示的,所以最大值就是2^16-1(也就是65535个字节)。但实际上TCP模块允许接收最大窗口远不止这个数目,比这个数目大是为了提高TCP通讯的吞吐量,这个窗口扩大因子就解决了这个问题。我们假设TCP头部中的接受通告窗口大小为n,窗口扩大因子是m,那么TCP报文段的实际接收窗口大小是n*2^m,这个字段跟最大报文长度字段一样,窗口扩大因子选项只能出现在同步报文段中,当连接建立好后,每个数据传输方向上的窗口扩大因子就固定不变。
kind=4:选择性确认选项
在TCP通讯时,如果某个TCP报文段丢失,那么TCP模块就会重传最后被确认的TCP报文段后续的所有报文段,这样原先已经正确传输的TCP报文段也可能重复发送,这样就降低了TCP的性能,选择性确认选项的技术正是为了改善这种情况产生的,它让TCP模块只重新发送丢失的TCP报文段,不用发送所有未被确认的TCP报文段。
kind=5:SACK实际工作的选项
这个选项的参数告诉发送方本端已经收到并缓存的不连续的数据块,从而让发送端可以根据此选项并且重新发送丢失的数据块
kind=8:表示时间戳选项
这个选项提供了比较准确的计算通讯双方之间回路时间的方法。

TCP连接状态转移过程

使用TCP连接需要建立连接、数据传输、关闭连接这几个过程。
其实TCP连接的任意一段在任意时刻都处于某种状态,而且当前状态都可以通过netstat命令查看。
下面说明TCP连接从建立到关闭的整个过程中,通信两端状态的变化。

这里写图片描述
上图描绘了所有的TCP状态以及可能的状态转换。
上图中的粗虚线表示典型的服务端状态转移,粗实线表示典型的客户端连接的状态转移。
服务器的典型状态转移过程:(接下来所说的连接状态都是指该连接的服务器的状态)
首先,服务器通过listen程序调用,进入LISTEN状态。进入LISTEN状态后,表示被动打开,被动的等待客户端进行连接,服务器一旦监听到某个连接请求,这个连接请求就是收到的同步报文段,之后就将该连接放入内核等待队列中,并向客户端发送带SYN标志的确认报文段,此时该连接处于SYN RCVD状态。从LISTEN状态到SYN REVD状态,它首先是收到了SYN报文段,紧接着就是发送带有SYN标志的确认报文段,如果服务器成功的接收到客户端发送会的确认报文段(ACK),那么该连接转移到ESTABLISHED状态。这个状态是连接双方能够进行双向数据传输的状态,也就是从这个状态开始,双方能够以TCP的方式传送数据。
服务器关闭时状态转移的过程:当客户端主动关闭数据连接时,客户端主动关闭连接调用的系统调用就是close或者shutdown。服务器收到客户端发送的关闭连接报文段后,通过返回确认报文段,是连接进入close_wait状态,这个状态就是等待服务器应用程序关闭连接,通常服务器检测到客户端关闭连接后也会立即给客户端发送一个结束报文段来关闭连接,给客户端发送一个接收报文段,这样就进入了LAST_ACK状态,接下来就是等待客户端对接受报文段的最后一次确认,也就是等待接收图片右下角的ACK,一旦确认完成,连接就彻底关闭,这种关闭连接的方式也称为被动关闭。
客户端的状态转移过程(接下来说的连接状态都是指客户端的连接状态):
首先,客户端通过connect系统调用,主动与服务器建立连接。connect系统调用会先给服务器发送一个同步报文段,是连接进入SYN_SENT状态,此后connect系统调用可能因为两个原因失败返回,如果connect失败返回,那么该连接又回到最初的CLOSED状态。如果客户端成功接收到服务器发送的同步报文段和确认,那么connect调用成功返回,也就是客户端收到了服务器的同步报文段和确认报文段,说明connect的调用成功返回,连接转移到ESTABLISHED状态。接下来看一下当客户端执行主动关闭时,这个状态转移过程:当客户端进行关闭时,首先发送一个关闭连接报文段,同时连接进入FIN_WAIT_1状态,如果此时客户端收到服务器专门用于确认目的的确认报文段(也就是收到了服务器额ACK回应),那么连接转移到FIN_WAIT_2状态。当客户端处于FIN_WAIT_2状态时,服务器处于CLOSE_WAIT状态,这对状态是可能发生半关闭的状态,此时如果服务器也关闭连接,也就是服务器也发送了结束报文段,也就是客户端在FIN_WAIT_2状态收到了结束报文字段,那么客户端就给予确认,也就是发送一个ACK确认,同时进入TIME_WAIT状态。

TCP建立连接和关闭连接的过程:

三次握手建立连接:

TCP头部中我们知道有6个标志位,其中SYN标志位,这个标志仅在三次握手建立连接时有效,表示一个同步报文段。ACK标志是对TCP请求的确认标志。FIN标志是用来结束一个TCP连接,标识此报文段是一个结束报文段。

这里写图片描述
三次握手建立连接的过程:
第一次握手:客户端发送一个带有SYN标志的TCP报文段给服务器。
图中SYN=1,表示这个字段是一个同步报文段,seq=i(序列号值为i),发送完这个报文段之后,主机A进入SYN SEND状态,等待服务器的确认。
第二次握手:服务器收到同步报文段之后必须确认客户的同步报文段,同时自己也发送一个带有SYN标志的报文段。
图中第二个报文段,SYN=1标志这是一个同步报文段,ACK=1表示这同时也是一个确认报文段。ack=i+1,表示确认序号值为i+1。seq=j,表示序号值为j。
第三次握手:客户端收到服务器的确认报文段之后,向服务器发送确认包。
图中ACK=1,表示是一个确认报文段。ack=j+1,确认序号为j+1。

三次握手之后,客户端与服务器开始传输数据。

四次握手关闭连接:
这里写图片描述

第一次握手:客户端发送一个带有FIN标志的结束报文段,用来关闭客户端A和服务器端B的数据传送。
图中FIN=1表示一个结束报文段。seq=i表示序号值为i。
第二次握手:服务端B收到这个结束报文段之后发回一个确认报文段,确认序号就是收到序号的值+1。
图中ACK=1,表示这是一个确认报文段。ack=i+1,标志确认号为i+1。
第三次握手:服务器B关闭与客户端A的连接,发送了一个带有FIN标志的结束报文段。
图中FIN=1表示这是一个结束报文段,seq=j表示这是一个结束报文段。
第四次握手:客户端A发回一个确认报文段,其中确认序号设置为收到的序号+1。
图中ACK=1表示是一个确认报文段,ack=j+1表示确认序号是j+1。

为什么建立连接需要三次握手,而关闭连接需要四次握手?
是因为服务端的Listen状态下的连接当收到同步报文段建立连接请求后,他可以把同步报文段和确认报文段合并成为一个报文段来进行发送,确认报文段起了应答作用,同步报文段起了同步作用,对应于三次握手中也就是第二次握手。但是在关闭连接时在收到客户端的结束通知时,仅仅表示对方没有数据发送给自己了,但未必自己所有的数据都发送给对方了,所以不能马上关闭TCP连接。可能需要在发送一些数据给客户端之后在发送结束报文段给对方,来表示你现在可以关闭连接了。所以这里的确认报文段和同步报文段必须要分开。

为什么建立连接需要三次握手呢?两次握手为什么不行?
如果是两次握手就有可能造成死锁,例如:如果客户端和服务端进行通信,客户端给服务端发送一个同步报文段,服务端收到了这个同步报文段并发送了确认报文段。按照两次握手的规定,服务端就认定这个连接已经建立了,可以开始发送数据了。但是如果第二次握手的确认报文段丢失,那么客户端就不知道服务端是否已经准备好,也不知道服务端建立什么样的序号值,这样服务端就有可能继续发送第二次握手的报文段,但是到了客户端,他可能不识别这个报文段。这样就形成了死锁。

TIME_WAIT状态:

TIME_WAIT状态存在的原因:

  1. 可靠的终止TCP连接
  2. 保证迟来的TCP报文段有足有的时间被识别并丢弃

RST复位报文段:

TCP头部中有6位的标志字段,其中有一位是RST复位标志位。如果TCP报文段中RST=1,就说明这个报文段是RST复位报文段。
在某些情况下,TCP连接的一端会向另一端发送携带RST标志的报文段,用来通知对方关闭连接或者重新建立连接。其实在TCP连接建立时、TCP中间发送数据时、TCP连接关闭时这三个时间段内都有可能发送RST复位报文段。

当连接建立时出现RST回应的情况有:

  1. 向不存在的端口发送数据
  2. 端口未打开
  3. 请求超时
  4. 提前关闭
  5. 在一个已关闭的socket上收到数据
  6. 异常终止一个连接
  7. 向处于listen的端口发送数据

TCP可靠传输机制

TCP超时重传
如果网络出现异常,就有可能出现超时或者丢包,这个时候TCP模块必须重传超时时间内未能收到确认的TCP报文段。为此TCP模块为每个TCP报文段维护一个重传定时器。该定时器在TCP报文段第一次被发送时启动,如果超时时间内未能收到接收方的应答,TCP模块将重传TCP报文段,并重置定时器。
TCP的超时重换为TCP的可靠传输奠定了一定的基础。

TCP拥塞控制的过程
TCP模块还有一个重要的任务就是:提高网络利用率、降低丢包率、拥塞控制。
其中拥塞控制和流量控制都是为TCP的可靠传输而设计的。
拥塞控制的任务是:确保子网能够承载所到达的流量,这是一个全局性问题,涉及到各方面的行为,包括所有的主机、所有的路由器、路由器内的存储转发过程。

1 0
原创粉丝点击