Python Socket多线程服务器实现:处理多连接与消息分发
本文详细介绍如何使用Python的Socket和Threading模块构建支持多客户端连接的服务端程序。通过为每个新连接分配独立线程,实现异步消息接收与主动发送功能,并包含控制台交互命令以查看在线人数或向特定客户端发送消息。
运行效果展示
运行效果展示
在开始之前需要澄清一个常见误区:网上许多声称能处理多连接的教程实际上无法实现真正的异步并发,也无法支持服务端主动向客户端发送消息。本文将提供一个真正可行的解决方案。

在服务端控制台输入数字1,即可查询当前在线的客户端数量。

通过控制台输入指定索引和消息内容,可以向特定的在线客户端发送消息。

开发思路解析
开发思路解析
以下重点介绍服务端的开发逻辑,客户端实现相对简单,此处略过。
核心难点在于Socket的accept和recv方法默认是阻塞线程的。这意味着如果在一个线程中同时处理连接建立和数据接收,程序会卡住。因此,必须引入多线程机制来并发处理这两个操作。
具体的程序运行流程如下:
1. 启动一个独立线程专门负责监听新连接(调用socket.accept())。
2. 每当有一个新连接建立,立即为该连接创建一个新的独立线程,专门用于接收该客户端发送的消息(调用socket.recv())。
3. 主线程不处理网络IO,而是作为控制台交互界面,接收用户输入并执行其他管理操作。
总结来说,服务端架构要求为每一个建立的客户端连接都创建一个对应的处理线程。
服务端代码实现
服务端代码实现
以下是全局变量和基础配置部分的代码:
import socket # 导入 socket 模块
from threading import Thread
ADDRESS = ('127.0.0.1', 8712) # 绑定地址
g_socket_server = None # 负责监听的socket
g_conn_pool = [] # 连接池
其中,g_conn_pool列表用于存储所有已建立的客户端Socket对象,以便进行统一管理。
服务端初始化函数代码如下:
def init():
"""
初始化服务端
"""
global g_socket_server
g_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建 socket 对象
g_socket_server.bind(ADDRESS)
g_socket_server.listen(5) # 最大等待数(有很多人理解为最大连接数,其实是错误的)
print("服务端已启动,等待客户端连接...")
请注意socket.listen()参数的含义,它表示最大挂起连接数,而非最大连接总数,这是一个常见的理解误区。
接收客户端连接及处理消息的核心逻辑如下:
def accept_client():
"""
接收新连接
"""
while True:
client, _ = g_socket_server.accept() # 阻塞,等待客户端连接
# 加入连接池
g_conn_pool.append(client)
# 给每个客户端创建一个独立的线程进行管理
thread = Thread(target=message_handle, args=(client,))
# 设置成守护线程
thread.setDaemon(True)
thread.start()
def message_handle(client):
"""
消息处理
"""
client.sendall("连接服务器成功!".encode(encoding='utf8'))
while True:
bytes = client.recv(1024)
print("客户端消息:", bytes.decode(encoding='utf8'))
if len(bytes) == 0:
client.close()
# 删除连接
g_conn_pool.remove(client)
print("有一个客户端下线了。")
break
将处理线程设置为守护线程(Daemon Thread),目的是确保当主线程退出时,所有子线程也能随之结束,避免进程残留。
在消息处理逻辑中,如果接收到的数据长度为0,通常意味着客户端已断开连接。在实际生产环境中,建议采用心跳包机制来更准确地判断客户端在线状态。
最后,调用上述方法启动服务端主程序:
if __name__ == '__main__':
init()
# 新开一个线程,用于接收新连接
thread = Thread(target=accept_client)
thread.setDaemon(True)
thread.start()
# 主线程逻辑
while True:
cmd = input("""--------------------------
输入1:查看当前在线人数
输入2:给指定客户端发送消息
输入3:关闭服务端
""")
if cmd == '1':
print("--------------------------")
print("当前在线人数:", len(g_conn_pool))
elif cmd == '2':
print("--------------------------")
index, msg = input("请输入“索引,消息”的形式:").split(",")
g_conn_pool[int(index)].sendall(msg.encode(encoding='utf8'))
elif cmd == '3':
exit()
如果对整体流程仍有疑问,建议回顾前文的开发思路部分以加深理解。
客户端代码实现
客户端代码实现
客户端的设计保持简洁,主要关注连接建立和基本通信。
import socket # 导入 socket 模块
s = socket.socket() # 创建 socket 对象
s.connect(('127.0.0.1', 8712))
print(s.recv(1024).decode(encoding='utf8'))
s.send("连接了".encode('utf8'))
print(s.recv(1024).decode(encoding='utf8'))
input("")
代码末尾的input()调用用于阻塞主线程,防止程序在接收完服务器消息后立即退出,从而保持连接状态。
以上即为使用Python Socket结合Threading模块实现多连接处理的完整方法,希望能为读者提供有价值的参考。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









