编写:Leaf Zhou
EMAIL:leaf_zhou_8@hotmail.com
TCP是英文Transport Control Protocol的缩写。从字面理解,就是传输控制协议。因此,TCP是一种控制协议,他本身不能用来传输数据,它需要通过网络层的IP协议来进行实际数据的传输。这也就是我们常常看到,TCP/IP和TCP/UDP总是同时出现的原因。因此,也可以理解为TCP是很多的不同的协议组成,实际上是一个协议组。提供可靠的主机到主机层数据传输控制协议。这里要先强调一下,传输控制协议是OSI网络的第四层的叫法,TCP传输控制协议是TCP/IP传输的6个基本协议的一种。TCP是一种可靠的面向连接的传送服务。它在
一、TCP概述
TCP是英文Transport Control Protocol的缩写。从字面理解,就是传输控制协议。因此,TCP是一种控制协议,他本身不能用来传输数据,它需要通过网络层的IP协议来进行实际数据的传输。这也就是我们常常看到,TCP/IP和TCP/UDP总是同时出现的原因。因此,也可以理解为TCP是很多的不同的协议组成,实际上是一个协议组。提供可靠的主机到主机层数据传输控制协议。这里要先强调一下,传输控制协议是OSI网络的第四层的叫法,TCP传输控制协议是TCP/IP传输的6个基本协议的一种。TCP是一种可靠的面向连接的传送服务。它在传送数据时是分段进行的,主机交换数据必须先建立一个会话。它用比特流通信,即数据被作为无结构的字节流进行传输,没有数据边界。通过每个TCP传输的字段指定顺序号,以获得可靠性。是在OSI参考模型中的第四层,TCP是使用IP的网间互联功能而提供可靠的数据传输,IP不停的把报文放到网络上,而TCP是负责确信报文到达。在协同IP的操作中TCP负责:握手过程、报文管理、流量控制、错误检测和处理(控制),可以根据一定的编号顺序对非正常顺序的报文给予从新排列顺序。关于TCP的RFC文档有RFC793、RFC791、RFC1700。
二、TCP连接的建立
建立一个TCP连接,需要下面的步骤:
(1)服务器端通过listen来准备接受外来的连接,称为被动打开(passive open)。
(2) 客户端通过connect进行连接服务器,称为主动打开(active open)。在这个操作中,客户端需要发送一个同步数据报(SYN),用来通知服务器端开始发送数据的初始序列号。通常情况下,同步数据报不携带数据,它只包含一个IP头部、一个TCP头部和本次通信所使用的TCP的选项。
(3)服务器端必须对客户端发来的同步数据报SYN进行确认,同时自己也要发送一个同步数据报(SYN),它包含客户端发送数据的初始序列号。服务器端对在同一连接中发送的数据初始序号和对客户端发送的确认信息(ACK),都放在一个数据报中,一起发送给客户端。
(4)客户端也必须发送确认服务器端的同步数据报(SYN)。
由上面的步骤来看,建立一个TCP连接,至少需要服务器端和客户端进行三个分组数据的交换,因此,称之为TCP的三路握手(three-way handshake)。
客户端 服务器端
connect() accept()
---> SYN S ----->
<--- SYN C
,
ACK S+
1
<---
---> ACK C+
1
----->
第一次进行分组数据交换的过程中,分组数据中可能包含着本次通信中可能的TCP选项。这些选项有:
(1) 最大分组(MSS)选项。TCP发送的SYN中带有这个选项,用来告诉对方它的最大分组数据的大小MSS(Maximum Segment Size),即它能接收的每个TCP分组数据中的最大数据量。这个选项可以通过TCP_MAXSEG套接口选项获取与设置这个TCP选项。
(2) 窗口大小选项。这是TCP能提供流量控制的主要手段。TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。TCP双方能够通知对方的最大窗口大小是64K(65535 bytes),因为TCP头部相应的标识字段值只用了16位来表示。每个套接口都有一个发送缓冲区和一个接收缓冲区,接收缓冲区被TCP和UDP用来将接收到的数据一直保存到由应用进程来读取。对于TCP,TCP通告另一端的窗口大小。 TCP套接口接收缓冲区不可能溢出,因为对方不允许发出超过所通告窗口大小的数据。这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它;而对于UDP,当套接口接收缓冲区放不下接收到的数据报时,此数据报就被丢弃。UDP是没有流量控制的,快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报,使数据发生丢失。
(3)时间戳选项。时间戳选项使发送方在每个报文段中放置一个时间戳值。接收方在确认中返回这个数值,从而允许发送方为每一个收到的ACK计算RTT。
三、TCP连接的终止
终止TCP连接
TCP用三个分组数据建立一个连接,但要终止一个连接则通常需要需要四个分组数据。过程如下:
(1)先调用close的进程,称为主动关闭(active close)。这一端的TCP先发送一个FIN分组数据,告诉对方,数据发送完毕。
(2)接收到FIN分组数据的一端执行被动关闭(passive close),同时,发送对这个FIN的确认ACK分组数据给对方。确认序号为收到的序号加1。FIN分组数据的接收意味着在当前的连接上,再也不会收到额外的数据。
(3)接收到FIN分组数据的一端的应用进程,将调用close关闭自己的套接口,同时TCP 会发送一个FIN分组数据给另一端。
(4)收到这个FIN的分组数据,即执行主动关闭的一端对这个FIN分组数据进行确认。发回确认ACK分组数据,并将确认序号设置为收到序号加1
在这个过程中,执行被动关闭的一方可以把确认对方FIN分组数据的ACK分组数据和自己要发送的FIN分组数据可以放到一个分组数据中。TCP的连接终止的过程如下:
客户端 服务器端
close() close()
---> FIN S ----->
<--- ACK S+
1
<---
<--- FIN C <---
---> FIN C+
1
--->
四、TCP连的状态
TCP的连接的建立和终止,基本上已经清楚了,那么在这个过程中,是如何知道这个连接正处在什么状态呢?方法当然是有的,我们先运行如下命令,看看返回的结果:
[root@linux81 leaf]# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:23 0.0.0.0:* LISTEN
tcp 0 0 192.168.253.81:139 192.168.253.35:1201 ESTABLISHED
tcp 0 272 192.168.253.81:22 192.168.253.59:1776 ESTABLISHED
udp 0 0 192.168.253.81:137 0.0.0.0:*
udp 0 0 0.0.0.0:137 0.0.0.0:*
udp 0 0 192.168.253.81:138 0.0.0.0:*
udp 0 0 0.0.0.0:138 0.0.0.0:*
udp 0 0 127.0.0.1:36260 0.0.0.0:*
在上面的返回结果中,State一列,就是说明连接的当前状态。
TCP的连接状态有:
(01)CLOSED
(02)LISTEN 被动打开
(03)SYN_RCVD
(04)SYN_SEND
(05)ESTABLISHED 数据传送状态
(06)CLOSE_WAIT
(07)LAST_ACK 被动关闭
(08)FIN_WAIT_1
(09)FIN_WAIT_2
(10)CLOSING
(11)TIME_WAIT
TCP连接状态转换示意图如下所示:
+---------+ ---------\ active OPEN
| CLOSED | \ -----------
+---------+<---------\ \ create TCB
| ^ \ \ snd SYN
passive OPEN | | CLOSE \ \
------------ | | ---------- \ \
create TCB | | delete TCB \ \
V | \ \
+---------+ CLOSE | \
| LISTEN | ---------- | |
+---------+ delete TCB | |
rcv SYN | | SEND | |
----------- | | ------- | V
+---------+ snd SYN,ACK / \ snd SYN +---------+
| |<----------------- ------------------>| |
| SYN | rcv SYN | SYN |
| RCVD |<-----------------------------------------------| SENT |
| | snd ACK | |
| |------------------ -------------------| |
+---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+
| -------------- | | -----------
| x | | snd ACK
| V V
| CLOSE +---------+
| ------- | ESTAB |
| snd FIN +---------+
| CLOSE | | rcv FIN
V ------- | | -------
+---------+ snd FIN / \ snd ACK +---------+
| FIN |<----------------- ------------------>| CLOSE |
| WAIT-1 |------------------ | WAIT |
+---------+ rcv FIN \ +---------+
| rcv ACK of FIN ------- | CLOSE |
| -------------- snd ACK | ------- |
V x V snd FIN V
+---------+ +---------+ +---------+
|FINWAIT-2| | CLOSING | | LAST-ACK|
+---------+ +---------+ +---------+
| rcv ACK of FIN | rcv ACK of FIN |
| rcv FIN -------------- | Timeout=2MSL -------------- |
| ------- x V ------------ x V
\ snd ACK +---------+delete TCB +---------+
------------------------>|TIME WAIT|------------------>| CLOSED |
+---------+ +---------+
TCP Connection State Diagram
从上面的图表中,可以做出如下总结:
服务器端的正常状态转换过程如下:
CLOSED --> LISTEN --> SYN_RCVD --> ESTABLISHED --> CLOSE_WAIT --> LAST_ACK --> CLOSED
客户端的正常状态转换过程如下:
CLOSED --> SYN_SENT --> ESTABLISHED --> FIN_WAIT_1 --> FIN_WAIT_2 --> TIME_WAIT --> CLOSED
从上面的连接状态转换中可以看出,从ESTABLISHED状态的转换有两种,对于客户端和服务器端来说,是一样的,即当收到FIN数据报之前,主动关闭,则转换成FIN_WAIT_1;如果因为收到FIN数据报,而引起的被动关闭,则转换成CLOSE_WAIT状态。