Python Socket 套接字编程从客户端到多线程服务器实战

宋时安
宋时安
发布时间:2026-10-12| 2人浏览过
原创

本文详解 Python Socket 套接字编程的核心流程。通过逐步演示如何创建 TCP 连接、发送与接收数据,并对比单线程与多线程服务器的实现差异,帮助开发者快速掌握基于 Python 的网络通信基础,解决实际开发中的客户端交互与并发处理问题。

Socket 编程的目标与基础概念

Socket(套接字)是操作系统提供的网络通信接口,任何跨设备的报文交换都依赖它。浏览器访问网页、即时通讯软件收发消息,底层均走 Socket 通道。Python 内置的 socket 模块提供了与 C 语言高度一致的 API,主要支持两种传输协议:

  • TCP(SOCK_STREAM):面向连接、可靠传输、按序到达,适合 HTTP 请求、文件传输等场景。
  • UDP(SOCK_DGRAM):无连接、不可靠但低延迟,适合音视频流或高频轮询。本文以 TCP 为主进行讲解。

准备条件与运行环境

编写 Socket 程序无需安装第三方包,依赖 Python 标准库。请确保运行环境为 Python 3.6 及以上版本。以下为通用前置准备:

  • 打开系统命令行终端(Windows PowerShell / macOS Terminal / Linux Bash)。
  • 新建两个空白文本文件,分别命名为 client.py 与 server.py。
  • 准备本地测试工具(如 telnet 或 nc),用于模拟外部客户端接入。

第1步:构建 TCP 客户端连接

第1步:创建 Socket 实例并配置参数

目的:初始化网络通信管道。 入口:Python 标准库 socket。 动作:调用 socket.socket() 构造函数。 参数:socket.AF_INET(IPv4地址族)与 socket.SOCK_STREAM(TCP协议)。 完成状态:控制台无报错并返回 Socket 描述符对象,变量名记为 s。

import socket
import sys

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print("Socket Created")
except socket.error as msg:
    print(f"Failed to create socket. Error code: {msg[0]}, Error message: {msg[1]}")
    sys.exit()

第2步:解析域名并完成连接

目的:获取目标主机 IP 并建立握手。 入口:上一步创建的 Socket 对象 s 与 socket.gethostbyname()。 动作:将域名解析为 IPv4 字符串,随后调用 s.connect() 发起三次握手。 参数:远程主机地址(如 "127.0.0.1" 或公网域名)与端口号(如 80)。 完成状态:终端打印连接成功日志,阻塞状态解除表示握手就绪。

host = "127.0.0.1"  # 实际测试可替换为任意可访问域名
port = 8888

try:
    remote_ip = socket.gethostbyname(host)
except socket.gaierror:
    print("Hostname could not be resolved. Exiting")
    sys.exit()

s.connect((remote_ip, port))
print(f"Socket Connected to {host} on ip {remote_ip}")

第3步:发送请求并读取响应数据

目的:按应用层协议投递报文并获取反馈。 入口:已连接的 Socket 对象 s。 动作:构造符合目标的报文头,调用 s.sendall() 全量发送;调用 s.recv(4096) 接收缓冲区数据。 参数:HTTP GET 请求字符串需携带 \r\n 结束符;接收长度可根据业务调整。 完成状态:控制台输出服务器返回的原始字节流或解析后的文本内容。

message = b"GET / HTTP/1.1\r\nHost: " + host.encode() + b"\r\n\r\n"
try:
    s.sendall(message)
    print("Message send successfully")
except socket.error:
    print("Send failed")
    sys.exit()

reply = s.recv(4096)
print(reply.decode("utf-8", errors="ignore"))
s.close()

完成判断:终端正常打印服务器响应的 HTTP 状态码与头部字段(如 HTTP/1.1 200 OK 或重定向信息),即为客户端链路打通。

第2步:搭建基础服务器端

第1步:绑定地址与监听端口

目的:预留系统资源并接受外部请求路由。 入口:新建的 Socket 对象 s。 动作:绑定本机所有可用接口(空字符串)与指定端口,切换至监听模式。 参数:HOST = ""(代表 0.0.0.0),PORT = 8888(避开系统保留端口);listen(10) 设置等待队列阈值。 完成状态:调用 s.listen() 后控制台打印监听状态,此时进程进入等待态。

HOST = ""
PORT = 8888

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created")

try:
    s.bind((HOST, PORT))
except socket.error as msg:
    print(f"Bind failed. Error Code: {msg[0]} Message: {msg[1]}")
    sys.exit()

s.listen(10)
print("Socket now listening")

第2步:接受连接并处理单次交互

目的:捕获握手完成的客户端会话并回传数据。 入口:监听中的主 Socket s。 动作:调用阻塞方法 s.accept() 提取客户端对象 conn 与元组地址 addr;随后执行读写闭环。 参数:recv(1024) 限制单次最大缓冲,sendall() 保证粘包拆分。 完成状态:打印客户端 IP 与随机高位端口号,收到数据后原路返回拼接回复,最后调用 close() 释放会话。

while True:
    conn, addr = s.accept()
    print(f"Connected with {addr[0]}:{str(addr[1])}")
    
    data = conn.recv(1024)
    reply = b"OK..." + data
    if not data:
        break
    conn.sendall(reply)
    conn.close()

第3步:升级为多线程并发服务器

上述循环结构采用串行处理,主线程在 accept 处被占用时会阻塞新接入请求。生产环境通常采用线程池或独立线程模型隔离业务逻辑。

第1步:封装独立线程处理函数

目的:将长连接读写逻辑剥离出主调度循环。 入口:threading 模块与连接描述符 conn。 动作:定义回调函数负责死循环收发消息,异常断开时安全退出子线程。 参数:固定接收窗口 1024,心跳检测可在此扩展。 完成状态:函数内部不抛出未捕获异常,子线程自动随连接关闭而终止。

import threading

def clientthread(conn):
    conn.send(b"Welcome to the server. Type something and hit enter\n")
    while True:
        data = conn.recv(1024)
        reply = b"OK..." + data
        if not data:
            break
        conn.sendall(reply)
    conn.close()

第2步:主循环启动新线程维持服务

目的:实现高并发接入而不阻塞排队。 入口:主 Socket s 与 clientthread。 动作:每次 accept() 成功后,实例化 threading.Thread 并传入目标函数与参数元组,调用 .start() 立即派发。 参数:daemon=False 默认保持主进程退出时强制清理(视业务需求调整)。 完成状态:多终端同时 telnet 127.0.0.1 8888 均可独立收发,主进程持续运行且 CPU 占用平稳。

while True:
    conn, addr = s.accept()
    print(f"New connection: {addr[0]}:{addr[1]}")
    thread = threading.Thread(target=clientthread, args=(conn,))
    thread.start()

常见运行异常排查

开发过程中最常遇到的错误是 OSError: [Errno 98] Address already in use。该现象通常由以下原因引发:

  • 端口残留:上次程序非正常退出(如 Ctrl+C 强杀),内核 TIME_WAIT 状态尚未清除。等待 30~120 秒即可自愈,或更换 PORT 值绕过。
  • 权限冲突:Linux/macOS 下尝试绑定 1024 以下特权端口会触发拒绝访问。请改用高位端口或提权运行。
  • IP 复用检查:若需在重启时立即释放端口,可在 bind 前加入 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)。

以上就是 Python Socket 编程从客户端到多线程服务器的详细内容,更多关于 Python 网络开发的基础资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。