推荐起点是ssl.create_default_context(),客户端须设server_hostname、服务端须load_cert_chain并设server_side=True,禁用已弃用的ssl.wrap_socket()。

ssl.create_default_context() 是唯一推荐的起点,其他方式要么过时、要么配置不安全。直接用它,再根据客户端或服务端角色调用 context.wrap_socket(),否则握手必然失败。
客户端必须传 server_hostname 参数
不加这个参数,context.wrap_socket() 会跳过主机名验证,但现代服务(尤其启用了 SNI 的)大概率拒绝连接,报错类似 ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] 或静默断连。
- 即使连的是
127.0.0.1,只要服务端证书里Subject Alternative Name (SAN)写了域名(比如localhost),就必须填对应域名,不能填 IP - 若服务端用自签名证书且你信任它,可临时禁用验证:
context.check_hostname = False和context.verify_mode = ssl.CERT_NONE,但仅限本地测试 - 真实生产环境务必保留主机名验证,这是防中间人攻击的第一道防线
服务端必须显式加载证书并设 server_side=True
只调 context.wrap_socket() 却不加载证书,会触发 ssl.SSLError: [SSL: SSL_HANDSHAKE_FAILURE]。关键点有三个:
-
certfile和keyfile路径必须存在且可读,强烈建议用绝对路径,避免相对路径引发FileNotFoundError - 上下文初始化时需指定
ssl.Purpose.CLIENT_AUTH,否则默认只支持客户端用途,无法接受入站 TLS 握手 -
context.wrap_socket(client_socket, server_side=True)中server_side=True不可省略——漏掉会导致ssl.SSLEOFError或 recv() 返回空字节
别再用 ssl.wrap_socket(),它已弃用
旧教程里常见的 ssl.wrap_socket(sock) 在 Python 3.12+ 已标记为弃用,运行时抛 DeprecationWarning,未来版本可能移除。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 真正该用的是上下文模式:先创建
SSLContext实例,再调wrap_socket() - 服务端初始化应写成
ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER),而非泛用create_default_context() - 如需控制加密套件(比如禁用弱算法),用
context.set_ciphers("ECDHE-ECDSA-AES256-GCM-SHA384"),而不是操作底层 socket
证书不匹配是调试中最常卡住的地方
现象通常是连接建立后立刻断开,或 recv() 返回空字节。根本原因往往不是代码逻辑,而是证书细节:
立即学习“Python免费学习笔记(深入)”;
- 自签名证书必须用
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365 -subj "/CN=localhost"生成,且CN或SAN必须与客户端传的server_hostname严格一致 - 服务端证书链要完整:如果用了中间 CA,
certfile必须包含服务器证书 + 中间证书(按顺序拼接),不能只放终端证书 - 私钥权限必须为 600,Linux 下若权限过大(如 644),OpenSSL 会拒绝加载,但 Python 不报明确错误,只表现为握手失败
openssl s_client -connect example.com:443 -servername example.com 验证证书链和 SNI 是否正常。

















