TIME_WAIT状态下的连接“搞怪“

一个常见的初学者问题:
kill一个进程后,再次启用该程序总是受到"Address already in use"的问题困扰。

这里通常有一个前提条件,即该进程上至少有一个连接仍然存活

问题复现

使用以下程序结合telnet可以简洁复现这个问题。

from socket import *
from struct import pack

PORT    = 9000
LISTENQ = 5

# creat a socket
sock = socket(AF_INET, SOCK_STREAM)
sock.bind((inet_ntop(AF_INET, pack('i', INADDR_ANY)), PORT))
sock.listen(LISTENQ)

# blocking...
sock.accept()

# blocking...
sock.accept()

在进程第一次被阻塞时,通过telnet localhost 9000建立一个连接。
在进程第二次被阻塞时,kill一下该程序相应的进程
然后,再次执行该程序。烦人的警告"Address already in use"再次出现.

为什么会出现这个问题?

  • 我们做了什么?
    向维持一个TCP连接通信的进程发送终止信号(kill), 进程执行缺省动作,被内核终结(terminate) ——— 相当于服务端主动关闭tcp连接。

  • 主动关闭tcp连接会发生什么?
    主动关闭方的套接字将转换为TIME_WAIT状态, 以确保安全处理处于终结阶段tcp连接的"后事"

  • 验证
    根据UNP1所述, TIME_WAIT状态一般持续2MSL的时间长度。
    因此,趁着机会,瞥一眼这个连接的套接字状态, 向shell输入netstat -an | grep 9000

    不出所料, 将会显示以下结果:
    tcp 0 0 127.0.0.1:9000 127.0.0.1:48428 TIME_WAIT

  • 后话
    既然是主动关闭连接就能复现该问题,何必使用kill呢? 连接一旦建立直接exit不就好了。将上述代码段略作修改。

    from socket import *
    from struct import pack
    
    PORT    = 9000
    LISTENQ = 5
    
    # creat a socket
    sock = socket(AF_INET, SOCK_STREAM)
    sock.bind((inet_ntop(AF_INET, pack('i', INADDR_ANY)), PORT))
    sock.listen(LISTENQ)
    
    # blocking...
    sock.accept()
    
    # blocking...
    # sock.accept()
    

    执行该程序,随后使用telnet建立一个连接。
    再次执行此程序时,出现同样的问题。
    可以使用netstat作进一步验证。

怎么解决这个问题?

更确切地说,怎么优雅地结束这个进程,使得再次启动时不再需要等待一段时间。

UNP上给了我们答复,使用套接字中的SO_ADDRREUSE选项。


  1. UNIX网络编程 卷1:套接字联网API(第3版) ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值