标签:
TCP是TCP/IP体系中非常复杂的一个协议,下面介绍其主要特点:
1. TCP是面向连接的运输层协议。就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在数据传送完毕后,必须释放已经建立的TCP连接。
2. TCP连接只能是点对点的,也就是一对一,不同于UDP的一对多,多对多。
3. TCP是可靠传输,通过TCP传输的数据,无差错、不丢失、不重复、并且按照发送顺序到达。
4. TCP是面向字节流的,不像UDP是面向报文的。TCP把应用程序交下来的数据看成一连串的无结构的字节流。TCP并不知道所传送的字节流的含义。
那么TCP是如何做到可靠的呢?TCP对于发送数据进行跟踪,这种数据管理需要协议有以下两个关键功能:
可靠性:保证数据确实到达目的地。如果未到达,能够发现并重传。
数据流控:管理数据的发送速率,以使接受设备不至于过载。
整个TCP协议的操作是围绕滑动窗口确认机制来进行的,只要理解了滑动窗口,就理解了TCP。
前面提到,TCP将独立的字节数据当做流来处理,一次发送一个字节并接受一次确认是不行的,速度会非常缓慢。为了提高速度,TCP将数据流分成片段,片段内的所有字节都是一起发送和接收的,因此也是一起确认的。假设A和B进行通信,每一条消息都会有一个识别编号,每一条消息都能够被独立地确认,所以同一时刻可以发送多条消息。那么B就会定期给A发送一条限制参数,制约A一次发送的最大消息数量,从而控制A的数据流,这就是TCP的流量控制机制。如果我们将A与B传输过程中的任一时刻进行一次快照,那么该时刻的数据状态可以分为以下四类:
已发送已确认:数据流中已经发送成功并得到确认的数据;
已发送但未确认:已经发送但是未得到确认的字节,发送方在确认之前,不会认为这些数据已经被处理;
未发送但已准备:发送方未将数据发送,但接收方已经确认自己有足够的空间,发送方会立即尝试发送;
未发送也未准备:这部分数据还不允许发送。
这四个状态分别对应下图的四个部分:
已发送已确认字节1至31。
已发送但未确认字节32至45。
未发送但已准备字节46至51。
未发送也未准备字节52至95。
整个传输过程的关键操作在于接收方运行发送方一次能容纳的未确认的字节数,称为发送窗口。该窗口决定了发送方允许传送的字节数,是2类和3类字节数之和。可用窗口和发送窗口不同,可用窗口是发送方仍被允许发送的数据量,也就是3类字节数。如下图:
上图中可用窗口中的字节发送后,状态变为下图:
等待一段时间后,目标设备向发送方传回确认信息,目标设备会发送自上一次成功接收后的最长字节数,为什么目标设备不列出它已经确认的字节呢?因为这样会导致效率的低下。例如,假设已发送未确认字节(32至45)分为4段传输:32-34,35-36,37-41,42-45。第1,2,4已经到达,而3段没有收到。接收方只会发回32-36的确认信息。接收方会保留42-45但不会确认,因为这会表示接收方已经收到了37-41。这是很必要的,因为TCP的确认机制是累计的,只使用一个数字来确认数据。这一数字是自上一次成功接收后的最长字节数。
由于32-36,这5个字节被确认,所以窗口向右滑动5个字节。状态变为如下:
那么37-41怎么办呢?TCP会重传丢失的片段,但是有一个缺陷就是它不会对每一个片段进行确认,这可能导致其他实际上已经接收到的片段被重传,比如本例中的42-45.
下面谈一谈TCP的连接是释放。也接收大名鼎鼎的“三层握手”和“四次挥手”。
TCP连接过程中解决以下三个问题:
1. 要使每一方能够确认对方的存在;
2. 要允许双方协商一些参数,比如最大窗口值,时间戳选项等;
3. 能够对运输实体资源进行分配。
TCP连接的建立采用客户服务器方式,主动发起连接的应用进程叫做客户,被动等待连接建立的应用进程叫做服务器。下图是TCP建立连接的过程:
A主动打开连接,B被动打开连接。B的TCP服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求。然后服务器进程就处于LISTEN状态,等待客户的连接请求。
A的TCP客户进程也是首先创建传输控制模块TCB,然后向B发出连接请求报文段,这时首部中的同步位SYN=1,同时选择一个初始序号seq=x。TCP规定,SYN报文不能携带数据。这时客户进程进入SYN-SENT状态。
B收到连接请求报文后,如果同意建立连接,则向A发送确认,将SYN和ACK位都置为1,确认号是ack=x+1,同时也为自己选择一个初始序号seq=y。这个报文同样不能携带数据。这时服务区进程进入SYN-RCVD状态。
A接收B的确认后,还要向B给出确认,将ACK置为1。该报文可以携带数据。这时A进入ESTABLISHED状态。
B接收A的确认后,也进入ESTABLISHED状态。
这就是三次握手。
那么想想,为什么要第三次握手呢?这是为了防止已经失效的连接请求报文段突然又传送给了B。举一个例子,先说说正常情况下,A发出连接请求,但是由于丢失未收到确认,于是A重传一次连接请求,然后确认,建立连接。数据传输完毕后,就释放连接。A一共发送了两个连接报文,其中第一个丢失,第二个到达了B,没有出现已经失效的连接请求报文段。
再来考虑异常情况,如果A发出的第一个报文没有丢失,而是延时后传到了B,那么B会以为这是A又一次连接请求,于是连接再次建成,而A没有数据传输需求,B的资源就白白浪费了。
下图是TCP连接释放的过程:
数据传输结束后,通信的双方都可以释放连接。现在A与B都处于ESTABLISHED状态。A的应用程序先向其TCP发出连接释放报文,并停止再发送数据,主动关闭TCP连接。A把连接释放报文段首部的FIN置为1,这时A进入FIN-WAIT-1状态。该报文不能携带数据。
B接收到连接释放报文段后发出确认,然后B就进入COLSE-WAIT状态。这个TCP服务进程就通知应用层,A已经没有数据要发送了,但是B如果还要发送数据,A仍然要接收,这时TCP连接处于半关闭状态。
A接收到B的确认后,就进入FIN-WAIT-2状态,等待B发出的连接释放报文。
如果B已经没有数据发给A,就可以通过TCP释放连接了,将FIN置为1,这时B进入LAST-ACK状态,等待A的确认。
A收到B的连接释放报文后,必须对此发出确认,然后进入TIME-WAIT状态。注意,这个时候TCP还没有被释放掉,必须经过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态。时间MSL叫做最长报文段寿命,建议设为2分钟。
这就是大名鼎鼎的四次挥手。
标签:
原文地址:http://blog.csdn.net/mevicky/article/details/46499859