转自:http://www.blogjava.net/jasmine214–love/archive/2010/12/15/340680.html?opt=admin
TCP是一个面向连接的协议。在传输数据前必须要建立连接,在停止传输数据后要终止连接释放资源。
一.TCP连接建立
TCP连接是在IP网络中两个进程间(应用层协议)的双向、全双工的逻辑回路。由节点的IP地址和端口将连接双方对应起来。
1.TCP连接特点:
- 通过一个握手进程建立起来;
- 通过一个周期性保持进程来保持,保证两个TCP节点间处于激活状态;
- 通过一个握手进程来终止,释放资源。
- TCP连接也被连接中的任意一端重置。
1.TCP连接的建立
为了建立连接TCP连接双方必须从对方了解下面的信息:
- 1.对方数据发送的开始序列号;
- 2.对方在出站管道上发送数据的缓冲区大小;
- 3.能被接收的最大段MSS;
- 4.被支持的TCP选项;
通 过3个TCP段的交换来了解这些信息,就是常说的TCP 握手的3个包。一般在客户端访问TCP服务器的时候,在客户端初始化一个TCP连接,服务器端打开一个特殊端口等待传入的请求。客户端主动发起第一个 SYN置位的包开始协商TCP连接。服务器接收后向客户端回ACK,最后客户端在向服务器回复ACK后连接建立。
下面我们用TCP连接的两个对等端A和B来详细介绍握手过程,其中发起方是A。
- 段一:同步(SYN)段
TCP连接的发起方A向B发送第一个TCP同步段(SYN).在TCP头部的选项中会包含一些选项与对端协商。
TCP 头部包含如下字段:
目的端口 TCP连接对端B被动打开的TCP端口数
源端口 TCP连接发起方A主动打开的端口,大多数是一个随机一个端口。
序列号 SYN的序列号ISN1可以看作是一个32位的计数器,由发起方A产生,具有一定的随机性。Windows 2003和XP根据派生启动(startup-derived)、2048位的随机密钥和一个基于RC4的随机数来计算ISN,从而减少下一TCP连接的 ISN被预测的可能性。
确认号 设置为0.SYN握手第一个包的ACK字段不重要,此时刚发起连接没有数据报需要确认。但后续的ACK是重要的。
SYN标志 置1.
窗口 设置为默认值,指示本地TCP接收缓冲区大小的初始值。
MSS TCP选项中的MSS 指示发起方A接收的最大的TCP段。
选择性确认(SACK) –TCP选项 如果包含这个字段,可以指示发起方A 的TCP能接收和解释此选项。
窗口缩放选项 如果包含,指示出发起方A的TCP能接收和支持此选项。协商好窗口因子后此连接就固定使用直到断开连接
一个FTP会话的SYN段 - 段二:SYN-ACK段
在B收到SYN包后,B将发SYN-ACK,TCP选项仅包含发起方A发送的SYN包中的的选项。
目的端口 设置为A的源端口
源端口 设置为B端口
序列号 B产生自己的序列号ISN2。和A发送的SYN中的ISN没有关系,仅产生的方法一样。
确认号 期望收到的对端的下一个字节ISN1+1.
SYN标志 置1.
ACK标志 置1,必须有此标志,除了SYN中置0外,SYN之后的所有报文(包括SYN-ACK和实际数据包都会带ACK的标志)。
窗口 设置B可以接收的最大窗口值,一般根据应用程序或者操作系统默认指定。
MSS TCP选项 设为B能接收的最大长度的TCP段;
SACK-许可 如果A发送的SYN包含此选项时才使用此选项,表示B的TCP能接收和解释SACK选项。
窗口缩放选项 如果SYN包含,此时才会包含。
一个FTP会话的SYN-ACK段 - 段3:ACK段
在TCP连接的发起方A收到SYN-ACK后,A再向B发送ACK。ACK中确认被发起方A使用的最终TCP参数,同时向B确认它该使用同样的参数。自此TCP连接建立完成。
一个FTP会话的SYN-ACK段
2.同时打开
两个应用程序同时执行主动建立TCP的连接的可能性是存在的,此时发送到SYN建立需要交换4个包,如图所示:
需要注意的是,即使同时打开仍然只建立一条连接。(但其他的协议不一定)
3.TCP 连接的结果
- 1.每一个TCP对等端知道连接上对方将被发送的第一个字节的序列号(发给对方的确认号,A发给B的确认号就是B将发送的序列号,同样B也是。)
- 2.每一个TCP对等端知道连接上能发送的MSS。选取握手阶段SYN和SYN+ACK包中MSS选项中较小的值。以此值开始进行PMTU的发现机制。
- 3.知道连接对端接收缓冲区大小,即窗口大小。
- 4.每个对等端知道对方能否使用SACK,窗口缩放等选项。
4.Windows控制TCP建立连接进程的注册表:
TcpMaxConnectRetransmissions
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:0~255
Default value:2
Present by default:No
设定当试图建立一个TCP连接时,会重传多少次SYN。每次间隔时间加倍。初始的RTO为3秒,并且默认值为2,这样第一次SYN等待3秒后重传第一次,在等待6秒后重传第二次,在等待12秒没有SYN+ACK就超时了。
TcpNumConnections
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:0~0xFFFFFF
Default value:0xFFFFFF
Present by default:No
设定能打开的TCP最大数。默认能打开16777214(0xFFFFFF)个连接。
5.TCP半开连接
TCP 半开连接是未完成的连接建立的进程的一个TCP连接,收到一个SYN包,并且一个SYN-ACK已经发送,但是最后的ACK没有收到。前面知道XP默认设 置情况下在发送2个重传SYN-ACK后等待12秒后放弃连接,并释放内存和连接的内部表项,从收到SYN到释放总共会花费21秒。
SYN-ACK重传输的一个半开连接
- SYN攻击
SYN攻击就是利用这种方法,使用伪装的IP地址和TCP端口,在短时间内制造大量的半开连接来耗尽资源,造成拒绝服务攻击。大量的半开连接能做如下事情:
1.使用所有可用的内存,
2.使用在TCP传输控制模块(TCB)中所有可能的项,这是一个用来跟踪TCP连接的内部表,一旦半开连接使用完所有的项,就用一个TCP连接复位来响应下一个连接企图。
3.使用所有可能的半开连接,此后用一个TCP连接复位响应下一个连接企图。
可以使用netstat -n -p tcp 查看TCP连接状态,包括半开连接。如果state出现大量的SYN-RECEIVED就该受到SYN攻击了。
Windows xp和2003 在检测和防护SYN攻击方面的注册表:
TcpMaxConnectResponseRetransmissions
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:0~255
Default value:2
Present by default:No
设定针对半开连接的一个AYN-ACK的重传数目,对于大于1的值使用SYN攻击防护机制。
SynAttackProtect
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:0~1
Default value:0
Present by default:No
设置为0禁用SYN攻击防护,1启用SYN攻击防护。被启用时,检测到SYN攻击,则半开连接的超时会更快些。
TcpMaxHalfOpen
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:100~65535
Default value:100 for windows xp 和Windows 2003 web版及标准版,500 for Windows 2003 企业版和数据中心版
Present by default:No
在SYN攻击防护起作用前,此键值设定了在SYN-RECEIVED状态中的TCP链接最大数。
TcpMaxHalfOpenRetried
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:80~65535
Default value:80 for windows xp 和Windows 2003 web版及标准版,400 for Windows 2003 企业版和数据中心版
Present by default:No
在SYN-RECEIVED状态中设定TCP连接的最大数并且在SYN攻击防护起作用前至少发送过一个重传。
6.TCP连接的维持
在 建立TCP连接后,必须有一些机制维持TCP连接。如果TCP建立连接后不传输任何数据也没有应用级别的保活机制时,那么TCP连接一直存在,数天,数月 会一直存在。中间的路由器可能重启,崩溃,TCP连接的双方无从知道,许多时候一个服务器希望知道客户主机是否崩溃并关机或者崩溃又重新启动。许多实现提 供的保活定时器可以提供这种能力。但这个规范并不推荐,理由如下:
- 在出现短暂差错的情况下,这可能会使一个非常好的连接释放掉;
- 它们耗费不必要的带宽;
- 在按分组计费的情况下会在互联网上花掉更多的钱。
TCP保活定时器(keepalive)
Windows 中TCP通过一个TCP keepalive的周期性交换,能维持一个TCP连接。在keepalive的TCP头部序列号字段被设为比当前出站数据流的序列号小1的值。如果一个 TCP对等端的下一个数据的字节序列号是N,那么keepalive的序列号是N-1.
在接收到keepalive包后,对等端回送一个ACK字段,并将确认号置为下一个期望收到的字节N,这个交换证实了两个对等端仍然处于TCP连接状态中。
Windows 2003 和 XP的TCP/IP在默认情况下禁用TCP的keepalive.启用情况下每2个小时发送一次keepalive。如果其他上层协议的保活机制时间小于keepalive,tcp的keepalive将不会发送。
相关注册表
KeepAliveTime
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:0~0xFFFFFFFF
Default value:0x6DDD00 (2小时)
Present by default:No
如果连接上没有没有数据,并且启用keepalive,此键值在每一个TCP保持活跃包之间设置了毫秒数,默认是2小时。
KeepAliveInterval
Location:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Data Type:REG_DWORD
Valid range:0~0xFFFFFFFF
Default value:0x3E8 (1000毫秒)
Present by default:No
在没有接收到对初始的保持活跃的响应时,此键值设置了重传时间默认是1秒。重传数目受TcpMaxDataRetransmission键值控制,默认是5.此时的重传不会有指数级的回退行为。
如果都启用且是默认,无数据传输的TCP连接在keepalive包发出后2小时6秒收不到ACK就放弃连接。
举例:
另一端崩溃
keepalive机制在重复发送探测包到一定次数后报错,由TCP转换为“连接超时”
另一端崩溃而重启
客户端telnet到服务器后,我们拔掉服务器网线重启服务器,服务器重启好后我们在telnet客户端上输入命令。服务器重启后丢失了以前连接的所有信息,此时服务器收到来着telnet客户端的命令,不知道此连接的信息,于是TCP就以复位作为应答来结束TCP连接。
另外一端不可达
拔掉网线,模拟中间路由器崩溃,keepalive探测的时候会引起ICMP差错“不可达–没有到达主机的路由”反馈给主机。
二.TCP连接的终止
TCP的连接终止需要4个包交换来完成。在两个逻辑管道上每个逻辑管道上发送方发送FIN置位的终止包,然后收到ACK后关闭该逻辑管道的连接。
TCP连接终止的4个TCP段交换过程
段1:来自TCP对等端A的FIN-ACK
一个期望终止出站数据流的TCP对等端(A)发送一个不包含任何数据的TCP段,他具有如下特点:
- 序列号,和发送带数据TCP段一样设置为出站数据的当前序列号,且当前序列号是最终序列号FSN1,因为马上要关闭了。
- 确认序列号 被设为TCP对等端A期望对方发送的下一个字节。对应TCP对等端B当前序列号CSN2。
- 设置ACK标志
- 设置FIN标志,指示此逻辑管道上没有其他数据需要发送。
段2:来自TCP对等端B的ACK
与SYN类似,FIN包也会占用一个字节的序列空间,并且必须把它当作是一个字节数据来确认。所以B接收到FIN-ACK后必须发送一个ACK,具有如下特点:
- 序列号 设为出站数据的当前序列号CSN2
- 确认号字段被设为比对端A发送的最终序列号多1的值FSN1+1.
- 设置ACK标志。
一旦FIN-ACK被确认,发送初始FIN-ACK端A就不能再发送数据了,这仅终止了一个逻辑管道的连接,TCP对等端B发送数据到A的逻辑管道仍然开放,B仍然可以发数据给A。
段三:来自TCP对等端B的FIN-ACK
前面对等端A向B发送数据的逻辑管道被关闭后,如果B向A发送数据的逻辑管道仍然有数据发送,且被对等端A确认,这就是TCP半关闭。TCP对等端B向A发送数据的逻辑管道没有数据发送后,也要B向A发送FIN-ACK来关闭。
特点:
- 序列号,和发送带数据TCP段一样设置为出站数据的当前序列号,且当前序列号最终序列号FSN2,因为马上要关闭了。
- 确认序列号 被设为TCP对等端A期望对方发送的下一个字节。对应TCP对等端A当前序列号FSN1+1。
- 设置ACK标志
- 设置FIN标志,指示此逻辑管道上没有其他数据需要发送
![image image](https://i-blog.csdnimg.cn/blog_migrate/3cf470786bcd52e686f34101aba6eaa4.png)
ftp客户端关闭FTP会话的Fin-ack段
段四:来自TCP对等端A的ACK
同样段三的FIN-ACK包也按占用了一个字节算,并且必须作为一个字节的数据被确认。因此收到FIN-ACK的A必须发送一个ACK。
具有如下特点:
- 序列号 设为出站数据的当前序列号FSN1+1
- 确认号字段被设为比对端B发送的最终序列号多1的值FSN2+1
- 设置ACK标志。
当来自A的ACK被B接收后,TCP连接上的B向A发送数据的逻辑管道就会被关闭,此时经过四次握手后,整个TCP连接才会被完整关闭。
但在有些实现中段二和段段三被合并。其过程就是FIN-ACK/FIN-ACK/ACK,此时中间的FIN-ACK中的ACK是对第一个FIN-ACK的确认。
同时关闭
双方都执行主动关闭也是可能的,TCP协议也允许这样的同时关闭(simultaneous close)。双方各发送一个FIN,两个FIN经过网络传送后分别到达另一端。收到FIN后,两端发送最后的ACK。当收到最后的A C K时,关闭TCP连接.
同时关闭的报文段交换
TCP连接的复位(Reset)
TCP连接终止进程适用于一个TCP连接的两个管道在互相同意的情况下正常关闭。另外一种终止TCP连接的方式是通过TCP连接复位—一个具有RST(Reset)标志的TCP段来完成。
当一个不可调和的入站TCP段的TCP头中存在参数问题时,一个TCP连接复位就会被发送。例如,不恰当的源IP地址、目的IP地址或者TCP端口号都能中断一个建立了的连接。中断的TCP连接将丢失所有的TCP数据,包括正在传送中或者在等待被发送的缓冲区中。
TCP也用来拒绝一个TCP连接企图,以响应对SYN段的接收。最常见的是,SYN段中目的端口与运行在SYN段接收者上的应用层进程相对应。当达到被允许的最大值时,连接企图就会被拒绝。下图显示了TCP连接复位
一个显示SYN和RST段的TCP连接的复位
注意:当UDP到达一个与应用层进程不对应的目的端口时,会产生一个ICMP,目的不可达-端口不可达的报错发送给UDP数据发送方。
抓包截图显示了在一台运行FTP客户端和一台非FTP服务器主机之间的包交换。帧一是一个到FTP控制端口的SYN段,帧二是连接复位。
在连接复位段中:
1.设置了RST和ACK标志
2.序列号为0
3.确认号比SYN段的序列号多1
4.窗口大小是0.
三 TCP连接状态
TCP连接状态和说明:
状态 | 说明 |
CLOSED | 不存在TCP连接 |
LISTEN | 一个应用层协议已经发布了一个被动打开,并且有意接收TCP连接企图 |
SYN SENT | 一个应用层协议已经发布一个主动打开,并且发送一个SYN段 |
SYN RCVD | 一个SYN段被接收,并且一个SYN-ACK被发送 |
ESTABLISHED | 建立TCP连接的3此握手完成。现在数据能双向传输 |
FIN WAIT-1 | 初始的关闭连接段的FIN-ACK被发送 |
FIN WAIT-2 | 响应初始的FIN-ACK的ACK被接收 |
CLOSING | 一个FIN-ACK被接收但ACK不是针对已发送的FIN-ACK的。收到的FIN-ACK中的是针对已发送的FINA-ACK被称为同时关闭,这时两个TCP对等端在相同时刻发送FIN-ACK。 |
TIME WAIT | FIN- ACK已被发送并得到两个对等端的确认,并且TCP连接终止进程完成。一旦到达TIME WAIT状态,在连接的TCP端口能被重新使用前,TCP必须等待的时间是最大生存时间(MSL)的两倍。MSL是在互联网中一个TCP段能存在时间的最 大值,推荐是240秒。这个延迟防止一个使用相同端口的连接的TCP段与旧连接的TCP段的副本相混淆 |
CLOSE WAIT | 一个FIN-ACK被接收,并且一个FIN-ACK被发送 |
LAST ACK | 响应FIN-ACK的ACK已被接收 |
TCP状态变迁图
一个TCP对等端经过的连接状态依赖于TCP对等端是TCP连接建立的初始化方还是TCP连接终止的初始化方。
TCP连接图和终止图