Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4230043
  • 博文数量: 473
  • 博客积分: 12019
  • 博客等级: 上将
  • 技术积分: 6515
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-01 16:46
文章分类

全部博文(473)

文章存档

2020年(30)

2019年(4)

2018年(10)

2017年(5)

2016年(2)

2015年(4)

2014年(4)

2013年(16)

2012年(47)

2011年(65)

2010年(46)

2009年(34)

2008年(52)

2007年(52)

2006年(80)

2005年(22)

分类:

2006-11-24 11:05:36

来源:本文出自:http://www.nsfocus.com 维护:小四 (2002-10-28 06:02:00)

8.3 如何避免一个套接字进入TIME_WAIT状态 

Q: 我正在写一个unix server程序,不是daemon,经常需要在命令行上重启它,绝大 
   多数时候工作正常,但是某些时候会报告"bind: address in use",于是重启失 
   败。 

A: Andrew Gierth  
   server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。至于 
   TIME_WAIT状态,你无法避免,那是TCP协议的一部分。 

Q: 如何避免等待60秒之后才能重启服务 

A: Erik Max Francis  

使用setsockopt,比如 

-------------------------------------------------------------------------- 
int option = 1; 

if ( setsockopt ( masterSocket, SOL_SOCKET, SO_REUSEADDR, &option, 
                  sizeof( option ) ) < 0 ) 

    die( "setsockopt" ); 

-------------------------------------------------------------------------- 

Q: 编写 TCP/SOCK_STREAM 服务程序时,SO_REUSEADDR到底什么意思? 

A: 这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用 
   端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息, 
   指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧 
   使用同一端口,此时 SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期 
   望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不 
   可能。 

   一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端 
   口。SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组 
   还是唯一确定的。所以,重启后的服务程序有可能收到非期望数据。必须慎重使 
   用 SO_REUSEADDR 选项。 

Q: 在客户机/服务器编程中(TCP/SOCK_STREAM),如何理解TCP自动机 TIME_WAIT 状 
   态? 

A: W. Richard Stevens <1999年逝世,享年49岁> 

下面我来解释一下 TIME_WAIT 状态,这些在<
中2.6节解释很清楚了。 

MSL(最大分段生存期)指明TCP报文在Internet上最长生存时间,每个具体的TCP实现 
都必须选择一个确定的MSL值。RFC 1122建议是2分钟,但BSD传统实现采用了30秒。 

TIME_WAIT 状态最大保持时间是2 * MSL,也就是1-4分钟。 

IP头部有一个TTL,最大值255。尽管TTL的单位不是秒(根本和时间无关),我们仍需 
假设,TTL为255的TCP报文在Internet上生存时间不能超过MSL。 

TCP报文在传送过程中可能因为路由故障被迫缓冲延迟、选择非最优路径等等,结果 
发送方TCP机制开始超时重传。前一个TCP报文可以称为"漫游TCP重复报文",后一个 
TCP报文可以称为"超时重传TCP重复报文",作为面向连接的可靠协议,TCP实现必须 
正确处理这种重复报文,因为二者可能最终都到达。 

一个通常的TCP连接终止可以用图描述如下: 

client                     server 
           FIN M 
close  ----------------->  (被动关闭) 
           ACK M+1 
       <----------------- 
           FIN N 
       <-----------------  close 
           ACK N+1 
       -----------------> 

为什么需要 TIME_WAIT 状态? 

假设最终的ACK丢失,server将重发FIN,client必须维护TCP状态信息以便可以重发 
最终的ACK,否则会发送RST,结果server认为发生错误。TCP实现必须可靠地终止连 
接的两个方向(全双工关闭),client必须进入 TIME_WAIT 状态,因为client可能面 
临重发最终ACK的情形。 


scz 2001-08-31 13:28 

先调用close()的一方会进入TIME_WAIT状态 


此外,考虑一种情况,TCP实现可能面临先后两个同样的相关五元组。如果前一个连 
接处在 TIME_WAIT 状态,而允许另一个拥有相同相关五元组的连接出现,可能处理 
TCP报文时,两个连接互相干扰。使用 SO_REUSEADDR 选项就需要考虑这种情况。 

为什么 TIME_WAIT 状态需要保持 2MSL 这么长的时间? 

如果 TIME_WAIT 状态保持时间不足够长(比如小于2MSL),第一个连接就正常终止了。 
第二个拥有相同相关五元组的连接出现,而第一个连接的重复报文到达,干扰了第二 
个连接。TCP实现必须防止某个连接的重复报文在连接终止后出现,所以让TIME_WAIT 
状态保持时间足够长(2MSL),连接相应方向上的TCP报文要么完全响应完毕,要么被 
丢弃。建立第二个连接的时候,不会混淆。 

A: 小四  

在Solaris 7下有内核参数对应 TIME_WAIT 状态保持时间 

# ndd -get /dev/tcp tcp_time_wait_interval 
240000 
# ndd -set /dev/tcp tcp_time_wait_interval 1000 

缺省设置是240000ms,也就是4分钟。如果用ndd修改这个值,最小只能设置到1000ms, 
也就是1秒。显然内核做了限制,需要Kernel Hacking。 

# echo "tcp_param_arr/W 0t0" | adb -kw /dev/ksyms /dev/mem 
physmem 3b72 
tcp_param_arr:  0x3e8           =       0x0 
# ndd -set /dev/tcp tcp_time_wait_interval 0 

我不知道这样做有什么灾难性后果,参看<>的声明。 

Q: TIME_WAIT 
阅读(2180) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~