赞
踩
TCP作为一种面向连接的单播协议,比 UDP复杂得多,必须在检测并修补所有在IP层(或下面的层)产生的数据传输问题,比如丢包、重复以及错误,以及连接何时建立、正常地终止等问题。即TCP需要对连接状态进行管理。
一个TCP连接由一个4元组组成:本端IP、本端端口号、对端IP、对端端口号。
一个典型的TCP连接的建立与关闭过程是通过三次握手与四次挥手完成的:
连接建立的主要步骤有:
1.主动连接方(客户端)发送一个SYN报文(Synchronize,同步标志),并指明自己想要连接的端口号和它的客户端初始序列号(记为ISN©),并且客户端还会发送一个或多个选项。
2.被动连接方(服务器)也发送自己的SYN报文段作为响应,并包含了它的初始序列号(记为ISN©)。
且发送一个ACK报文,数值为客户端ISN©数值加1,以此作为对客户端SYN的确认,因此每发送一个SYN,序列号就会自动加1。这样如果出现丢失的情况,可以根据序列号确定并进行重传。
3.为了确认服务器的SYN,同样地,客户端将ISN(s)的数值加1后作为返回的ACK数值
连接关闭的主要步骤有:
1.连接的主动关闭者发送一个FIN段指明接收者希望看到自己当前的序列号(K),FIN也包含了一个ACK段用于确认对方最近一次发来的数据。
2.连接的被动关闭者将K的数值加1作为响应的ACK值发送,(此时会通知上层的应用发起关闭操作)。此时TCP连接出于半关闭状态,ACK发出之后可能要等待其他操作结束。
接着被动关闭者将身份转变为主动关闭者,发送自己的FIN。
3.开始的主动关闭者发送ACK报文,并进入time_wait状态
当一个连接打开时,TCP报文段在经过网络路由后可能会存在延迟抵达与排序混乱的情况。为了解决这一问题,需要仔细选择初始序列号。
为了防止一个连接与其他连接的序列号重叠的情况,[RFC0793]初始序列号可被视为一个32位的计数器,计数器的数值每4秒加1。
序列号面临的安全问题:如果选择合适的序列号、IP地址以及端口号,那么可以伪造一个TCP报文段,从而打断TCP的正常连接。要抵御这种行为,只能使用更复杂的初始序列号生成方法使其更难以被猜出,或者对其加密。
现代系统通常采用半随机的方法选择初始序列号,linux系统采用基于时钟的方案,并且针对每一个连接为时钟设置随机的偏移量。随机偏移量是在连接标识(即4元组)的基础上利用加密散列函数得到。
TCP状态转换图:
TIME_WAIT状态也称为2MSL等待状态。即在该状态中,TCP将会等待两倍于最大段生存期的时间。它代表任何报文段在被丢弃前在网络中被允许存在的最长时间。
报文的最大生存期MSL是由于TCP报文是以IP数据报的形式传输的,IP数据报拥有TTL字段和跳数限制字段。这两个字段限制了IP数据报的有效生存时间。常见的实现中,MSL一般为30s/1min/2min
TIME_WAIT 等待的原因:
由上可知,TIME_WAIT状态可能产生对内存资源、端口资源的占用。
对于客户端如果我们终止一个客户端后立即重新启动同一客户端,那么新的客户端不能使用相同的本地端口号,一般来说由于客户端使用的是由操作系统随机分配的临时端口号,这种情况不成问题,但是在客户端快速产生大量连接时,可能在临时端口号供应紧张时造成连接建立延迟。
而服务器,通常会使用一些知名的端口,如果我们终止一个已经建立的连接,然后立即尝试重新启动它,服务器不能为该程序分配对应的端口号。(地址已被占用错误)。
避开TIME_WAIT:
如果相信新连接的报文段不会因为序列号、时间戳等问题与之前连接实例的报文相混淆,那么可以进行相关设置以避开 TIME_WAIT状态,主要方法有:
1)设置套接字REUSEADDR选项;
2)通过sysctl命令,将系统tcp_max_tw_buckets值调小,(当处于TIME_WAIT 的连接一旦超过这个值,系统会将所有TIME_WAIT连接状态重置)
静默时间
如果一台与处于TIME_WAIT状态下连接相关联的主机崩溃,然后在MSL内重新启动,并且使用与主机崩溃之前处于TIME_WAIT 状态的连接相同的IP地址与端口号,会怎样处理呢?
在上述情况下,该连接在主机崩溃之前产生的延迟报文段会被认为属于主机重启后创建的新连接,即会发生重叠,这种处理方式将不会考虑在主机重启之后新连接是如何选择初始序列号的。
为了防止上述情况的发生,[RFC0793] 指出在崩溃或者重启后TCP协议应当在创建新的连接之前等待相当于一个MSL的时间,该段时间即被称为静默时间。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。