OSError: [WinError 10022]参数无效问题排查(P2P文件分发系统)
问题描述
实现了一套以服务器为中间人的P2P文件分发系统,用于向N个客户端分发文件。服务器端执行connect操作时触发OSError: [WinError 10022] An invalid argument was supplied错误,客户端TCP处理逻辑仅显示N个端口超时,请求排查问题原因。
服务器端出错代码片段
try: for i in l: print(i) x = random.randint(0,N-1) print(x,"Index") serverSocketTCPRequest = serverSocketTCPList[x] serverSocketTCPRequest.settimeout(2) serverSocketTCPRequest.connect((i[0],i[1])) serverSocketTCPRequest.send("SEND".encode()) serverSocketTCPRequest.send(str(chunkID).encode()) data = serverSocketTCPRequest.recv(1024) serverSocketTCPRequest.close() b = False return data except Exception as ex: print(traceback.format_exc()) time.sleep(1) # print(l) pass
报错栈信息
Traceback (most recent call last): File "d:\IITD\5th Sem\COL334\Assignment 2\server.py", line 149, in getChunks serverSocketTCPRequest.connect((i[0],i[1])) OSError: [WinError 10022] An invalid argument was supplied Traceback (most recent call last): During handling of the above exception, another exception occurred: Traceback (most recent call last): File "d:\IITD\5th Sem\COL334\Assignment 2\server.py", line 198, in sendChunkRequest checkMessage, serverAddress = serverSocketUDPRequest.recvfrom(1024) socket.timeout: timed out During handling of the above exception, another exception occurred: Traceback (most recent call last): File "d:\IITD\5th Sem\COL334\Assignment 2\server.py", line 149, in getChunks serverSocketTCPRequest.connect((i[0],i[1])) OSError: [WinError 10022] An invalid argument was supplied
客户端TCP处理代码片段
def handleTCP(client:Client): global N while(True): try: # print(clientList.index(client), client.clientSocketTCPRequest.getsockname()) client.clientSocketTCPRequest.listen(2*N) client.clientSocketTCPRequest.settimeout(2) connectionSocket, addr = client.clientSocketTCPRequest.accept() print("Connected") message = connectionSocket.recv(1024).decode() if message.decode() == "SEND": i = connectionSocket.recv(1024).decode() connectionSocket.send(client.dict[int(i)]) connectionSocket.close() elif message.decode() == "GET": i = connectionSocket.recv(1024).decode() client.dict[int(i)] = connectionSocket.recv(1024) connectionSocket.close() except Exception as ex: template = "An exception of type {0} occurred. Arguments:\n{1!r}" m = template.format(type(ex).__name__, ex.args) print(m,client.clientSocketTCPRequest.getsockname()) # print(traceback.format_exc()) continue
说明:存在完整的client.py、server.py代码及测试文件A2_small_file.txt。
问题排查与修复方案
核心问题分析
- 服务器端socket复用错误:
服务器从serverSocketTCPList中随机取出socket使用,用完后调用close()关闭,但该socket仍留在列表中。后续再次取到这个已关闭的socket执行connect时,会触发WinError 10022错误——已关闭的socket对象无法再用于连接操作,参数无效。 - 客户端TCP处理逻辑错误:
- 对
recv得到的字符串重复调用decode():message = connectionSocket.recv(1024).decode()已经完成解码,后续message.decode()会直接抛出异常,导致客户端无法正确处理服务器的请求,进而服务器端出现超时。 - 循环内重复调用
listen():listen()只需在socket绑定后调用一次,每次循环都调用会导致socket状态异常,引发超时。
- 对
具体修复步骤
服务器端修复
放弃复用旧socket,每次需要连接时创建新的socket实例:
try: for i in l: print(i) # 创建新的TCP socket serverSocketTCPRequest = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serverSocketTCPRequest.settimeout(2) serverSocketTCPRequest.connect((i[0],i[1])) serverSocketTCPRequest.send("SEND".encode()) serverSocketTCPRequest.send(str(chunkID).encode()) data = serverSocketTCPRequest.recv(1024) serverSocketTCPRequest.close() b = False return data except Exception as ex: print(traceback.format_exc()) time.sleep(1) pass
也可维护一个动态的可用socket列表,关闭socket后从列表中移除,避免重复使用已失效的socket。
客户端修复
- 移除重复的
decode()调用:
message = connectionSocket.recv(1024).decode() if message == "SEND": # 去掉多余的decode()
- 将
listen()移到while循环外部,仅调用一次:
def handleTCP(client:Client): global N # 只调用一次listen client.clientSocketTCPRequest.listen(2*N) while(True): try: client.clientSocketTCPRequest.settimeout(2) connectionSocket, addr = client.clientSocketTCPRequest.accept() print("Connected") message = connectionSocket.recv(1024).decode() if message == "SEND": i = connectionSocket.recv(1024).decode() connectionSocket.send(client.dict[int(i)]) connectionSocket.close() elif message == "GET": i = connectionSocket.recv(1024).decode() client.dict[int(i)] = connectionSocket.recv(1024) connectionSocket.close() except Exception as ex: template = "An exception of type {0} occurred. Arguments:\n{1!r}" m = template.format(type(ex).__name__, ex.args) print(m,client.clientSocketTCPRequest.getsockname()) continue
- 可选优化:处理
recv的不完整数据,添加循环确保接收到完整的指令字符串。
内容的提问来源于stack exchange,提问作者Harshit Mawandia
相关产品推荐
相关产品推荐

