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

Python Socket遇OSError 107异常:nmap扫描致服务器崩溃的处理

问题解决:处理半开/重置连接导致的OSError

你的推测是对的:nmap扫描时可能在三次握手完成后立即发送RST包断开连接,此时服务器accept()已经返回了socket,但该socket实际已处于未连接状态,调用getpeername()就会触发OSError: [Errno 107]。

Python标准库中没有直接的socket.is_connected()方法,因为TCP连接状态是动态变化的,只能通过操作socket并捕获异常来处理这类场景。以下是修复后的代码:

import sys
import socket
import select

def run_server(port):
    listening_socket = socket.socket()
    listening_socket.bind(("", port))
    listening_socket.listen()

    active_sockets = set()
    active_sockets.add(listening_socket)

    while True:
        ready_sockets, _, _ = select.select(active_sockets, {}, {})
        for ready_socket in ready_sockets:

            if ready_socket == listening_socket:
                try:
                    connected_socket, (client, port) = ready_socket.accept()
                    active_sockets.add(connected_socket)
                    print(f"({client}, {port}): connected")
                except OSError:
                    # 处理accept时的异常(比如连接被重置)
                    continue

            else:
                try:
                    client, port = ready_socket.getpeername()
                    received_bytes = ready_socket.recv(4096)
                    received_size = len(received_bytes)

                    if received_size == 0:
                        active_sockets.remove(ready_socket)
                        ready_socket.close()
                        print(f"({client}, {port}): disconnected gracefully")
                    else:
                        print(f"({client}, {port}) {received_size} bytes: {received_bytes}")
                except OSError as e:
                    # 处理连接重置、端点未连接等错误
                    if e.errno == 107 or e.errno == 104:  # 104是Connection reset by peer
                        active_sockets.remove(ready_socket)
                        ready_socket.close()
                        # 尝试获取客户端信息,若失败则显示未知
                        try:
                            client, port = ready_socket.getpeername()
                            print(f"({client}, {port}): connection reset")
                        except:
                            print("(unknown client): connection reset")
                    else:
                        # 其他异常可以根据需要处理或打印
                        print(f"Socket error: {e}")
                        active_sockets.remove(ready_socket)
                        ready_socket.close()


def usage():
    print("usage: select_server.py port", file=sys.stderr)

def main(argv):
    try:
        port = int(argv[1])
    except:
        usage()
        return 1

    run_server(port)

if __name__ == "__main__":
    sys.exit(main(sys.argv))

关键修改点:

  • 在accept()环节添加异常捕获,避免极端情况下accept直接报错崩溃
  • 对非监听socket的操作(getpeername()、recv())包裹try-except块,专门处理Errno 107(端点未连接)和Errno 104(连接被重置)的情况
  • 处理异常时主动关闭socket并从active_sockets集合中移除,避免后续select继续处理无效socket
  • 兼容客户端信息获取失败的情况,避免二次报错

原理说明:

TCP连接状态无法通过单一方法直接判定,必须通过实际的socket操作(如获取对等方信息、收发数据)来验证。当操作失败并抛出特定异常时,即可判定连接已失效,执行清理操作即可。

内容的提问来源于stack exchange,提问作者builtin.ctz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 06:00:02