Cannot assign requested address问题解决

本文探讨了在大量高并发日志传输过程中遇到的TIME_WAIT状态过多问题,深入解析其产生的原因,并提供了一系列可行的解决方案,包括修改系统配置、调整应用逻辑等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TIME_WAIT过多及解决

问题场景

大量高并发日志传输,短连接,每次在传输一定数量的日志后,开始出现以下错误

    Failed to establish a new connection: [Errno 99] Cannot assign requested address

问题原因

通过下述命令可以查看当前端口占用及分类

    netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

    TIME_WAIT        27352
    SYN_SENT         4
    ESTABLISHED      58

  发现端口占用中处于TIME_WAIT状态的有多达20000+,基本占用了全部的端口,要详细了解端口状态,需要从TCP的状态转换说起。

image

  其中TIME_WAIT状态的产生源自于TCP连接的结束,TCP要保证在所有可能的情况下使得所有的数据都能够正确被投递。当关闭一个 socket 连接时,主动关闭一端的 socket 将进入TIME_WAIT状态,而被动关闭一方则转入CLOSED状态。

当一个socket关闭的时候,是通过两端互发信息的四次握手过程完成的,当一端调用close()时,就说明本端没有数据再要发送了。这好似看来在握手完成以后,socket就都应该处于关闭CLOSED状态了。但这有两个问题:
1. 我们没有任何机制保证最后的一个ACK能够正常送达
2. 网络上仍然有可能有残余的数据包(wandering duplicates,或老的重复数据包),我们也必须能够正常处理。

  正常的系统中,可分配的端口号是有限的,但是处于TIME_WAIT状态的连接,虽然已经要确认关闭了,但是仍然占住端口不撒手,一般需要2MSL的时间,现实时长大概在两分钟左右,所以在有限的端口使用完之后,新的请求没有可以安放的地方,便出现了上述错误。

解决方案

  1. 修改sysctl.conf

    vim /etc/sysctl.conf
    
    # 文件中加入
    
    net.ipv4.tcp_tw_reuse = 1 
    net.ipv4.tcp_tw_recycle = 1 
  2. 减少短时间内的请求数
    这一条需要结合具体场景分析,像本例的场景,是一个短时间内高并发,短连接,每次传输的时间较短,所以可以考虑加大每次的请求的数据传输量,总量一定的情况下,请求数下来,端口使用也能得到一定程度的缓解。

  3. 通过直接发送RTS来直接结束本次连接
    这个方法暂时没实践,如果有时间,后期可能补上

Refs

TCP/IP详解–TCP连接中TIME_WAIT状态过多
发现大量的TIME_WAIT解决办法

### 关于 `bind: Cannot assign requested address` 错误的解决方案 #### 一、检查网络接口配置 当遇到 `bind: cannot assign requested address` 的错误时,可能是因为尝试绑定到一个不存在或不可用的 IP 地址。应当确认服务器上的网络接口配置是否正确,确保指定的 IP 地址确实存在于某个活动的网卡上[^2]。 对于 Redis 特定情况下的这个错误,可能是由于在配置文件中指定了一个不属于当前系统的 IP 地址给 `bind` 参数所引起的。此时应通过命令如 `ifconfig` 或者更现代的 `ip addr show` 来获取实际可用的本地 IP 地址列表,并据此调整应用程序(例如Redis)的相关设置[^3]。 #### 二、验证端口号与权限 另一个常见原因是试图使用的端口已经被其他进程占用或者是受限的操作系统保留端口(通常小于1024)。可以通过如下方式排查: - 使用 `netstat -tuln | grep '端口号'` 查看特定端口的状态; - 如果是低编号端口(<1024),则需要以root用户身份运行程序来获得必要的访问权限[^4]。 #### 三、考虑防火墙规则的影响 有时即使上述两点都正常无误,仍然会碰到此类问题,这往往涉及到操作系统层面的安全策略——比如Linux平台下iptables/firewalld等服务可能会阻止对外提供某些服务所需的连接行为。因此建议核查并适当放宽相关限制条件以便允许所需的服务能够顺利启动和工作[^1]。 ```bash sudo iptables -L INPUT -v -n --add-port=6379/tcp --permanent # 添加永久开放端口规则(针对firewalld) ``` #### 四、更改绑定地址为通配符 如果不需要严格限定只接收来自某单一IP的数据流的话,可以将应用软件中的绑定地址设为INADDR_ANY (`0.0.0.0`) 这样就可以监听所有的本地网络接口了。不过需要注意这样做存在一定的安全隐患,在生产环境中需谨慎评估风险后再做决定。 ```c server_addr.sin_addr.s_addr = htonl(INADDR_ANY); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值