sever如何避免2MSL

一、

根据TCP协议,主动发起关闭的一方,会进入TIME_WAIT状态,持续2MSL,RFC 793建议MSL设置为两分钟。


为什么time_wait需要2*MSL等待时间?

MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。

假设最终的 ACK 丢失 , server 将重发 FIN , client 必须维护 TCP 状态信息以便可以重发最终的 ACK ,否则会发送RST ,结果 server 认为发生错误。 
若要TCP可靠地终止连接的两个方向 ( 全双工关闭 ) , client 必须进 TIME_WAIT状态。
现在我们考虑终止连接时的被动方发送了一个FIN,然后主动方回复了一个ACK,然而这个ACK可能会丢失,这会造成被动方重发FIN,这个FIN可能会在互联网上存活MSL。
如果没有TIME_WAIT的话,假设连接1已经断开,然而其被动方最后重发的那个FIN(或者FIN之前发送的任何TCP分段)还在网络上,然而连接2被建立起来,使用的IP地址与端口与先前的完全相同,后建立的连接又称作是原先连接的一个化身。原先的连接中有数据报(FIN)残存于网络之中,这样新的连接收到的数据报中有可能是先前连接的数据报。为了防止这一点,TCP不允许从处于TIME_WAIT状态的socket建立一个连接。处于TIME_WAIT状态的socket在等待两倍的MSL时间以后,将会转变为CLOSED状态。这就意味着,一个成功建立的连接,必然使得先前网络中残余的数据报都丢失了。

对于基于TCP的HTTP协议,如果关闭TCP连接的是Server端,这样,Server端会进入TIME_WAIT状态,对于访问量大的Web Server,会存在大量的TIME_WAIT状态,假如server一秒钟接收1000个请求,那么就会积压240*1000=240000个TIME_WAIT的记录,维护这些状态给Server带来很大的负担,并且由于TIME_WAIT

状态占用的一些端口由于还没有被释放可能还会导致服务器端口不够用。当然现代操作系统都会用快速

的查找算法来管理这些TIME_WAIT,所以对于新的TCP连接请求,判断系统中是否有一个TIME_WAIT不会太费时间,但是有这么多状态要维护总是不好。

TIME_WAIT 状态到底会占用什么?

被占用的是一个五元组:(协议,本地IP,本地端口,远程IP,远程端口)。对于 Web 服务器,协议是 TCP,本地 IP 通常也只有一个,本地端口默认的 80 或者 443。只剩下远程 IP 和远程端口可以变了。如果远程 IP 是相同的话,就只有远程端口可以变了。这个只有几万个,所以当同一客户端向服务器建立了大量连接之后,会耗尽可用的五元组导致问题。

在高并发短连接的server端,当server处理完client的请求后立刻close socket此时会出现TIME_WAIT状

态然后如果client再并发2000个连接,此时部分连接就连接不上了。

如何消除大量TCP短连接引发的TIME_WAIT?

1)可以改为长连接,但代价较大,长连接太多会导致服务器性能问题,而且PHP等脚本语言,需要通过proxy之类的软件才能实现长连接;
2)修改ipv4.ip_local_port_range,增大可用端口范围,但只能缓解问题,不能根本解决问题;
3)客户端程序中设置socket的SO_LINGER选项;
4)客户端机器打开tcp_tw_recycle和tcp_timestamps选项;
5)客户端机器打开tcp_tw_reuse和tcp_timestamps选项;
6)客户端机器设置tcp_max_tw_buckets为一个很小的值

So_linger的作用
struct linger {
     int l_onoff; /* 0 = off, nozero = on */
     int l_linger; /* linger time */
};
其取值和处理如下:

1、设置 l_onoff为0,则该选项关闭,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据;
2、设置 l_onoff !=0 && l_linger = 0,则套接口关闭时TCP将断开连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;
3、设置 l_onoff != 0 && l_linger != 0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。

1、 若设置了SO_LINGER(亦即linger结构中的l_onoff域设为非零),并设置了零超时间隔,则closesocket()不被阻塞立即执行,不论是否有排队数据未发送或未被确认。这种关闭方式称为 “强制”或“失效”关闭 ,因为套接口的虚电路立即被复位,且丢失了未发送的数据。在远端的recv()调用将以WSAECONNRESET出错。 
2、 若设置了SO_LINGER并确定了非零的超时间隔,则closesocket()调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为 “优雅”或“从容”关闭 。请注意如果套接口置为非阻塞且SO_LINGER设为非零超时,则closesocket()调用将以WSAEWOULDBLOCK错误返回。 
3、 若在一个流类套接口上设置了SO_DONTLINGER(也就是说将linger结构的l_onoff域设为零),则closesocket()调用立即返回。但是,如果可能,排队的数据将在套接口关闭前发送。请注意,在这种情况下WINDOWS套接口实现将在一段不确定的时间内保留套接口以及其他资源,这对于想用所以套接口的应用程序来说有一定影响。

TCP要保证在所有可能的情况下使得所有的数据都能够被投递。当你关闭一个socket时,主动关闭一端的socket将进入TIME_WAIT状态,而被动关闭一方则转入CLOSED状态,这的确能够保证所有的数据都被传输。当一个socket关闭的时候,是通过两端互发信息的四次握手过程完成的,当一端调用close()时,就说明本端没有数据再要发送了。这好似看来在握手完成以后,socket就都应该处于关闭CLOSED状态了。但这有两个问题,首先,我们没有任何机制保证最后的一个ACK能够正常传输,第二,网络上仍然有可能有残余的数据包(wandering duplicates),我们也必须能够正常处理。

通过正确的状态机,我们知道双方的关闭过程如下

假设最后一个ACK丢失了,服务器会重发它发送的最后一个FIN,所以客户端必须维持一个状态信息,以便能够重发ACK;如果不维持这种状态,客户端在接收到FIN后将会响应一个RST,服务器端接收到RST后会认为这是一个错误。如果TCP协议能够正常完成必要的操作而终止双方的数据流传输,就必须完全正确的传输四次握手的四个节,不能有任何的丢失。这就是为什么socket在关闭后,仍然处于 TIME_WAIT状态,因为他要等待以便重发ACK。

时间: 2024-10-20 07:11:11

sever如何避免2MSL的相关文章

Windows Sever 2012的安装教程(图文)

转自脚本之家 Windows Sever 2012的安装教程(图文) 作者:佚名 来源:互联网 最近微软先行放出发布了下一代Windows服务器版本windows server 2012,笔者下载下来测试安装了,相对于windows server 2008,确实有许多细节方面的改进. 我是通过vmware workstation 8来安装windows server 2012的,由于安装的时候无法选择2012只好选择windows server 2008 64位版本的. 启动界面,由前一个版本的

1-01Sql Sever 2008的安装

Sql Sever 2008对计算机的配置要求: 1:处理器:最低1.4Ghz的处理器,建议使用2.0GHz或更高的处理器  . 2:内存:最小512MB, 建议使用1GB或更高的处理器. 3:磁盘容量:最少有2GB的可内存. 4:操作系统:不同的版本安装支持不同安装系统.

Windows sever 2008 R2 ---虚拟机安装

Windows sever 2008 系统安装 步骤一.新建一个虚拟机,选择自定义模式.(图1) 图 1 步骤二.默认即可.(图2) 图 2 步骤三.选择稍后安装操作系统.(图3) 图 3 步骤四.选择客户机操作系统为microsoft windows,然后选择版本为windows sever 2008.(图4) 图 4 步骤五.更改虚拟机名称和位置.(图5) 图 5 步骤六.默认即可.(图6) 图 6 步骤七.内存默认即可.(图7) 图 7 步骤八.选择使用网络地址转换.(图8) 图 8 步骤

sql sever 的两种写法

事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位. 通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性. 在sql server+ .net 开发环境下,有两种方法能够完成事务的操作,保持数据库的数据完整性: 一个就是用sql存储过程,另一个就是在ADO.NET中一种简单的事务处理: 现在通过一个典型的银行转账的例子来说明一下这两个例子的用法 我们先来看看sql存储过程是如何来

数据库操作----找了MySQL和SQL Sever两个的基础语句

这是MySQL的基本操作: 1 登入数据库:mysql -uroot -p+密码 (SQL Sever登入: osql -U 用户名 -P 密码) 2 显示已存在的数据库:show databases; 3 使用某个数据库:use+数据库名; 4 显示某个数据库下已存在的关系表:show tables; 5 6 查看某个关系表所有数据:select * from tableName; 7 查看某个关系表部分字段数据:select 字段1,字段2,...,字段n from tableName; 8

如何让server服务器避免2MSL

一.TIME_WAIT状态带来的一些问题 根据TCP协议,主动发起关闭的一方会进入TIME_WAIT状态,持续2MSL(每个TCP报文在网络内的最长时间,称为MSL ).如果关闭TCP连接的server端,这样server端就会进入TIME_WAIT状态,倘若server端关闭了大量的连接,就会存在大量的TIME_WAIT状态,维护这些状态会给server带来很大的负担,并且由于TIME_WAIT状态占用的一些端口号由于还没有被释放,导致服务器的端口不够用. 在高并发短连接的server端,当s

链接Eclipse和SQL SEVER

一.本文内容 讲诉使用JDBC建立Eclipse和Sql sever的桥梁的过程与其中可能遇见的问题. 二.详细内容 1.JDBC驱动的下载 建议一定要上与SQL SEVER相关的微软官网下载,以便找到最适合自己手中sql的版本驱动 本文我使用的是windows.10操作系统,SQL SEVER 2014 EXPRESS(设置了管理员登陆密码),Eclipse(已配置好JDK) 截至至(2015年11月11日) 最新的驱动微软下载地址为:https://www.microsoft.com/zh-

sql sever获取数据库还原时间语句

--只获取数据库名称和最后的还原时间 SELECT sdb.Name AS DatabaseName , COALESCE(CONVERT(VARCHAR(12), MAX(bus.backup_finish_date), 101), '-') AS LastBackUpTime FROM sys.sysdatabases sdb LEFT OUTER JOIN msdb.dbo.backupset bus ON bus.database_name = sdb.name GROUP BY sdb

sql sever 字符串函数

SQL Server之字符串函数 以下所有例子均Studnet表为例:  计算字符串长度len()用来计算字符串的长度 select sname ,len(sname) from student 字符串转换为大.小写lower() 用来将一个字符串转换为小写,upper() 用来将一个字符串转换为大写 select lower('I AM A STUDENT !')select upper('i am a student !') 截去字符串左.右侧空格