添加SSL认证时遇WinError 10038:非套接字操作问题排查
SSL认证TCP服务器报错WinError 10038的原因与修复
问题背景
我创建了一个可显示客户端发送数据的TCP服务器,原本运行正常,但添加SSL认证后出现故障,调用wrap_socket()函数时抛出错误。
服务器代码
import socket import json import ssl HOST: str = '127.0.0.1' PORT: int = 5507 def create_server_socket() -> socket.socket: """Creates a TCP socket, binds it to the host and port and listens for a connection. Will try again should the process fail""" try: server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((HOST, PORT)) server_socket.listen() print(f"SERVER LISTENING ON {HOST, PORT}") return server_socket except socket.error as message: print("Socket creation error: " + str(message) + "\n Retrying...") return create_server_socket() def main() -> None: """Main function to start the server.""" context : ssl.SSLContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain("ssl/server.crt", "ssl/server.key") server_socket: socket.socket = create_server_socket() context.wrap_socket(server_socket, server_side=True) client_socket, client_address = server_socket.accept() with client_socket: data: bytes = client_socket.recv(1024) print(f"{client_address} connected as {data.decode(encoding='utf-8')}\n") while True: data: bytes = client_socket.recv(1024) decoded_data: str = data.decode(encoding='utf-8') try: data: dict =json.loads(decoded_data) except json.JSONDecodeError: print(f"{client_address} disconnected!") server_socket.close() client_socket.close() break print(f"{data['sender']}: {data['msg']}") if __name__ == '__main__': main()
错误信息
Traceback (most recent call last): File "c:\Users\Yoocee\Desktop\Algorithmic Sciences\server.py", line 82, in <module> main() File "c:\Users\Yoocee\Desktop\Algorithmic Sciences\server.py", line 57, in main client_socket, client_address = server_socket.accept() ^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Yoocee\AppData\Local\Programs\Python\Python311\Lib\socket.py", line 294, in accept fd, addr = self._accept() ^^^^^^^^^^^^^^ OSError: [WinError 10038] An operation was attempted on something that is not a socket
错误原因
问题出在wrap_socket()的使用逻辑上:
当调用context.wrap_socket(server_socket, server_side=True)时,该函数不会修改原有TCP套接字,而是返回一个新的SSL套接字对象,同时原server_socket会被自动关闭(默认do_handshake_on_connect=True,包装过程中原套接字的文件描述符会被接管)。后续继续使用已失效的原套接字调用accept(),就会触发"操作对象不是套接字"的错误。
修复方法
将wrap_socket()返回的SSL套接字赋值给server_socket变量,后续所有监听、接受连接的操作都使用这个新的SSL套接字:
修改main函数中的关键代码:
# 原错误代码 context.wrap_socket(server_socket, server_side=True) # 修改后正确代码 server_socket = context.wrap_socket(server_socket, server_side=True)
完整修复后的main函数
def main() -> None: """Main function to start the server.""" context : ssl.SSLContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain("ssl/server.crt", "ssl/server.key") server_socket: socket.socket = create_server_socket() # 关键修复:将wrap_socket返回的SSL套接字赋值给原变量 server_socket = context.wrap_socket(server_socket, server_side=True) client_socket, client_address = server_socket.accept() with client_socket: data: bytes = client_socket.recv(1024) print(f"{client_address} connected as {data.decode(encoding='utf-8')}\n") while True: data: bytes = client_socket.recv(1024) decoded_data: str = data.decode(encoding='utf-8') try: data: dict =json.loads(decoded_data) except json.JSONDecodeError: print(f"{client_address} disconnected!") server_socket.close() client_socket.close() break print(f"{data['sender']}: {data['msg']}")
额外注意:客户端也需要使用SSL方式连接,否则会握手失败。客户端需用
ssl.wrap_socket或context.wrap_socket包装自身套接字,必要时指定server_hostname参数验证服务器证书。
内容的提问来源于stack exchange,提问作者Yoocee Ansah
相关产品推荐
相关产品推荐

