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
相关产品推荐
相关产品推荐

