百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>服务器> 详解TCP连接建立与终止教程
分享文章到:

详解TCP连接建立与终止教程

发布时间:01/15 来源: 浏览: 关键词:
TCP是一个面向连接的协议。在传输数据前必须要建立连接,在停止传输数据后要终止连接释放资源。本教程我们讲讲关于TCP连接建立与终止那点事。

对于这篇文章来说,主要是记录自己遇到对TCP协议的一些问题以及学习到的一些东西。

1. TCP连接的建立

学过计算机网络的都知道TCP连接的建立需要三次握手,当时在大学也这么听着,但是具体怎么三次还是最近补了才知道这么回事。

对于客户端/服务器模型来说:

1. 首先客户端发起连接(发送SYN报文,进入SYN_SENT状态)

2. 服务器接收到SYN,然后响应(发送SYN ACK,进入SYN_RCVD状态,注意这个时候连接并没有建立)

3. 客户端接受到后,发送确认报文(发送ACK,进入Established状态)

4. 服务器收到后才进入链路建立(Established)状态。

如下图(图为百度搜出来的)


2. TCP连接的终止

对于TCP连接的终止来说,却需要四次挥手来完成。

就客户端首先发起调用close关闭来说:

1. 客户端发送FIN(进入FIN_WAIT_1状态)

2. 服务器接收到FIN后对发送ACK确认(此时服务器进入CLOSE_WAIT状态,客户端接受到该ACK后由FIN_WAIT_1 转为FIN_WAIT_2状态)

3. 服务器调用close发送FIN(进入LASK_ACK状态)

4. 客户端接收到服务器发送的FIN后发送ACK(进入TIME_WAIT状态)

5. 服务器接收到后结束(LASK_ACK状态转为虚拟的CLOSED,即已经没有状态了)

如下图所示:


3. TCP状态转换

其实如果看懂了上面连接的建立以及终止的话,很容易就可以看懂下面的状态转换图,上面两个就可以看做由它拆解出来的。


4. 遇到CLOSE_WAIT状态的一些情况

前面说了,最近在维护一些历史遗留的项目,那代码简直是叼炸天了,直接使用两个进程共用一个select,在accept前加上文件锁,select只监听服务器端fd,其它fd不监听....(此处省略一千字)。

上面的状态图可以看出,服务器由于接收到客户端发来的FIN,会进入 CLOSE_WAIT,如果此时没有监听该客户端fd并且没有调用close,那么这时会导致占用的FD没有被释放,资源就这么被泄漏掉了,当然 CLOSE_WAIT状态一般来说过个2小时就会消失,但是这样也会导致存在大量的CLOSE_WAIT状态,以至于后续FD消耗完了的时候(一般系统默认1024),accept就会失败。

(注:即使accept失败,但是对于链路来说,还是能建立成功的,因为对于Linux TCP底层实现来说,存在两个队列,一个为半链路队列,另一个为三次握手成功但是没有被服务器accept取走的链接的队列。)

后续对于Linux下的服务器来说一般都是使用epoll来处理,效率比select高。




另外 一篇关于 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。

01.png

TCP 连接建立进程的3个TCP段交换


段一:同步(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能接收和支持此选项。协商好窗口因子后此连接就固定使用直到断开连接
01.png 

一个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包含,此时才会包含。

01.png

一个FTP会话的SYN-ACK段


段3:ACK段
在TCP连接的发起方A收到SYN-ACK后,A再向B发送ACK。ACK中确认被发起方A使用的最终TCP参数,同时向B确认它该使用同样的参数。自此TCP连接建立完成。

01.png

一个FTP会话的SYN-ACK段

2.同时打开

两个应用程序同时执行主动建立TCP的连接的可能性是存在的,此时发送到SYN建立需要交换4个包,如图所示:
01.png  

同时打开报文交换


需要注意的是,即使同时打开仍然只建立一条连接。(但其他的协议不一定)


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就超时了。
01.pngTcpNumConnections


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秒。
01.png

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连接状态中。
01.png


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后关闭该逻辑管道的连接。
01.png
TCP连接终止的4个TCP段交换过程


段1:来自TCP对等端A的FIN-ACK

一个期望终止出站数据流的TCP对等端(A)发送一个不包含任何数据的TCP段,他具有如下特点:

    序列号,和发送带数据TCP段一样设置为出站数据的当前序列号,且当前序列号是最终序列号FSN1,因为马上要关闭了。
    确认序列号 被设为TCP对等端A期望对方发送的下一个字节。对应TCP对等端B当前序列号CSN2。
    设置ACK标志
    设置FIN标志,指示此逻辑管道上没有其他数据需要发送。

01.png 

tp服务器关闭FTP会话的Fin-ack段


段2:来自TCP对等端B的ACK

与SYN类似,FIN包也会占用一个字节的序列空间,并且必须把它当作是一个字节数据来确认。所以B接收到FIN-ACK后必须发送一个ACK,具有如下特点:

    序列号 设为出站数据的当前序列号CSN2
    确认号字段被设为比对端A发送的最终序列号多1的值FSN1+1.
    设置ACK标志。

01.png

ftp服务器关闭FTP会话的Fin-ack段的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标志,指示此逻辑管道上没有其他数据需要发送
01.png 

ftp客户端关闭FTP会话的Fin-ack段


段四:来自TCP对等端A的ACK

同样段三的FIN-ACK包也按占用了一个字节算,并且必须作为一个字节的数据被确认。因此收到FIN-ACK的A必须发送一个ACK。

具有如下特点:

    序列号 设为出站数据的当前序列号FSN1+1
    确认号字段被设为比对端B发送的最终序列号多1的值FSN2+1
    设置ACK标志。

01.png 

ftp客户端关闭FTP会话的Fin-ack段的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连接.
01.png

同时关闭的报文段交换


TCP连接的复位(Reset)

TCP连接终止进程适用于一个TCP连接的两个管道在互相同意的情况下正常关闭。另外一种终止TCP连接的方式是通过TCP连接复位—一个具有RST(Reset)标志的TCP段来完成。

当一个不可调和的入站TCP段的TCP头中存在参数问题时,一个TCP连接复位就会被发送。例如,不恰当的源IP地址、目的IP地址或者TCP端口号都能中断一个建立了的连接。中断的TCP连接将丢失所有的TCP数据,包括正在传送中或者在等待被发送的缓冲区中。

TCP也用来拒绝一个TCP连接企图,以响应对SYN段的接收。最常见的是,SYN段中目的端口与运行在SYN段接收者上的应用层进程相对应。当达到被允许的最大值时,连接企图就会被拒绝。下图显示了TCP连接复位

01.png

一个显示SYN和RST段的TCP连接的复位


注意:当UDP到达一个与应用层进程不对应的目的端口时,会产生一个ICMP,目的不可达-端口不可达的报错发送给UDP数据发送方。

抓包截图显示了在一台运行FTP客户端和一台非FTP服务器主机之间的包交换。帧一是一个到FTP控制端口的SYN段,帧二是连接复位。

01.png

01.png
在连接复位段中:

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已被接收

 
01.png

 TCP状态变迁图


一个TCP对等端经过的连接状态依赖于TCP对等端是TCP连接建立的初始化方还是TCP连接终止的初始化方。
01.png

TCP连接图和终止图

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有6人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板