Python Socket运行广播脚本报WinError 10048端口占用错误排查
问题原因
- 报错直接诱因是Python模块导入的执行规则:当你在broadcast.py中执行
from chatServer import broadcast时,Python会完整运行chatServer.py所有顶层作用域的代码,包括创建socket、绑定端口、启动监听、运行接收循环这整套服务端启动流程。 - 此时你已经提前启动了一个chatServer服务端进程,
192.168.1.109:42976这个套接字地址已经被原有进程占用,导入时触发的第二次服务端启动尝试再次绑定同个端口,就会抛出WinError 10048地址占用错误。 - 就算绕过端口报错,当前实现逻辑也无法正常工作:独立启动的broadcast.py和正在运行的服务端是两个完全隔离的进程,导入拿到的
broadcast函数操作的是新进程内空的clients列表,根本无法给已经连接到原有服务端的客户端发送消息。另外你当前调用broadcast时传入的是字符串类型,而socket的send方法要求传入字节类型,还会触发类型错误。
修复步骤
- 重构chatServer.py的代码结构,将服务端启动逻辑放到
if __name__ == "__main__":判断块内,保证只有直接运行chatServer.py时才会启动服务,被其他脚本导入时不会执行端口绑定操作。重构后的chatServer.py代码参考如下:
import threading import socket # 公共配置、全局变量、工具函数保留在顶层 host = "192.168.1.109" port = 42976 clients = [] nicknames = [] def broadcast(message): for client in clients: client.send(message) def handle(client): while True: try: message = client.recv(1024) broadcast(message) except: index = clients.index(client) clients.remove(client) client.close() nickname = nicknames[index] broadcast('{} ha abbandonato!'.format(nickname).encode('utf-8')) print(f"{nickname} ha abbandonato.") nicknames.remove(nickname) break def receive(server): while True: client, address = server.accept() print("Connesso con {}".format(str(address))) client.send('NICK'.encode('utf-8')) nickname = client.recv(1024).decode('utf-8') nicknames.append(nickname) clients.append(client) print("Il nickname è {}".format(nickname)) if nickname == "Admin": broadcast("Il capo è entrato! Salutate l'Admin!".encode('utf-8')) else: broadcast("{} è entrato!".format(nickname).encode('utf-8')) client.send('Connesso al server!'.encode('utf-8')) thread = threading.Thread(target=handle, args=(client,)) thread.start() def server_command_input(): # 单独线程读取服务端控制台输入,实现广播 while True: content = input("Inserisci messaggio broadcast: ") if content.strip(): broadcast(f"[Avviso server] {content}".encode('utf-8')) if __name__ == "__main__": print(f'''Host: {host} Porta: {port}''') server = socket.socket() # 开启端口复用,避免服务端临时重启时提示端口占用 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((host, port)) server.listen() # 启动控制台广播线程 cmd_thread = threading.Thread(target=server_command_input, daemon=True) cmd_thread.start() receive(server)
- 放弃单独运行broadcast.py的实现思路:直接运行重构后的chatServer.py启动服务,服务端控制台会自动等待广播内容输入,输入内容后会直接广播给所有已连接的客户端,不需要额外启动第二个脚本,从根源上避免跨进程通信和端口冲突问题。
如果一定要保留独立广播脚本的形式,需要将广播脚本实现为特殊的管理员客户端,通过socket连接到正在运行的服务端,自定义通信协议标识广播指令,由服务端收到指令后完成广播转发,这种方案改动量较大,没有特殊需求不推荐使用。
内容的提问来源于stack exchange,提问作者GP_Gamer98
相关产品推荐
相关产品推荐

