You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TCP客户端连接报Errno98地址已占用,端口清理后仍未解决

解决TCP客户端连接时的OSError: [Errno 98] Address already in use问题

问题描述

我用单线程TCP客户端/服务器程序实现文件传输,客户端发起连接时触发OSError: [Errno 98] Address already in use错误。已提前清理端口6006,且确认端口在有效范围内。执行命令如下:

  • 服务器端:./info.py -r -p 6006 -
  • 客户端:./info.py -t -p 6006 -ip 127.0.0.1 -

相关代码:

服务器端函数

def ifTcpserver():
    serverIP = "127.0.0.1"
    serverPort = 6006

    serverSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serverAddr = (serverIP,serverPort)
    serverSock.bind(serverAddr)
    serverSock.listen(1)
    print(f"listening on port {serverPort}")

    while True:
        connectSock, addr = serverSock.accept()
        jsonBytes = connectSock.recv(1024)
        print("data:",jsonBytes.decode("UTF-8"))
        ifDic = json.loads(jsonBytes)
        print(ifDic, type(ifDic))      
        connectSock.close()

客户端函数

def ifTcpclient(localInfo):
    serverIP = "127.0.0.1"
    serverPort = 6006

    jsonMessage = localInfo

    clientSocket = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    sockAddr = (serverIP, serverPort)
    clientSocket.connect(sockAddr)
    jsonBytes = jsonMessage.encode("UTF-8")
    clientSocket.send(jsonBytes)
    
    clientSocket.close()

原因分析

  1. TCP端口TIME_WAIT状态:服务器进程退出后,操作系统会保留端口一段时间(通常1-2分钟,即2倍MSL时长),防止残留数据包干扰新连接,此时端口处于TIME_WAIT状态,无法立即复用。
  2. 服务器套接字未正确释放:当前服务器代码未处理进程中断场景(如Ctrl+C),监听套接字serverSock可能未被正确关闭,导致端口被异常占用。
  3. 重复启动服务器进程:可能存在未完全终止的服务器进程,持续占用端口6006。

解决方案

1. 启用端口复用选项

在服务器绑定端口前,添加SO_REUSEADDR套接字选项,允许复用处于TIME_WAIT状态的端口。同时添加中断捕获逻辑,确保监听套接字正常关闭:

def ifTcpserver():
    serverIP = "127.0.0.1"
    serverPort = 6006

    serverSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 允许复用TIME_WAIT状态的端口
    serverSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    serverAddr = (serverIP,serverPort)
    serverSock.bind(serverAddr)
    serverSock.listen(1)
    print(f"listening on port {serverPort}")

    try:
        while True:
            connectSock, addr = serverSock.accept()
            jsonBytes = connectSock.recv(1024)
            print("data:",jsonBytes.decode("UTF-8"))
            ifDic = json.loads(jsonBytes)
            print(ifDic, type(ifDic))      
            connectSock.close()
    except KeyboardInterrupt:
        # 捕获Ctrl+C信号,关闭监听套接字
        serverSock.close()
        print("Server stopped.")

2. 强制终止占用端口的进程

用以下命令定位并终止占用6006端口的进程:

# 查找进程PID
lsof -i :6006
# 或
netstat -tulpn | grep 6006

# 强制终止进程
kill -9 <进程PID>

3. 同步代码与命令行参数

当前代码硬编码了端口6006,建议读取命令行传入的-p参数,避免代码与实际运行参数不一致:

# 服务器端示例:读取命令行端口参数
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--port', type=int, required=True)
args = parser.parse_args()
serverPort = args.port

客户端同理读取-p参数,确保两端端口一致。

4. 客户端添加异常处理

为客户端连接逻辑添加异常捕获,避免直接崩溃:

def ifTcpclient(localInfo):
    serverIP = "127.0.0.1"
    serverPort = 6006

    jsonMessage = localInfo

    clientSocket = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    try:
        sockAddr = (serverIP, serverPort)
        clientSocket.connect(sockAddr)
        jsonBytes = jsonMessage.encode("UTF-8")
        clientSocket.send(jsonBytes)
    except OSError as e:
        print(f"Connection failed: {e}")
    finally:
        clientSocket.close()

内容的提问来源于stack exchange,提问作者Big_Mann_98

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 07:57:16