You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改现有Python Socket聊天服务器以支持多客户端连接?

如何修改Socket服务器以支持多客户端连接

我是Socket编程新手,现有可正常运行的客户端与服务器代码如下:

客户端代码

import socket
import threading

username = input("enter username: ")
ip = input("enter ip: ")
port = int(input("enter port: "))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
user_encode = bytes(username, "utf-8")
s.send(b"\n" + user_encode + b" has joined the room!")


def send():
    while True:
        message = input("")
        encode = bytes(message, "utf-8")
        s.send(user_encode + b": " + encode)


def receive():
    while True:
        receive_msg = s.recv(2048)
        decode = receive_msg.decode()
        print(decode)


sending = threading.Thread(target=send, daemon=False)
receiving = threading.Thread(target=receive, daemon=False)
sending.start()
receiving.start()

服务器代码

import socket
import threading
import selectors

sel = selectors.DefaultSelector()

hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
port = int(input("enter port: "))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((ip, port))
print(f"listening on {ip}")
s.listen(1)
conn, addr = s.accept()


def transfer():
    while True:
        msg = conn.recv(2048)
        conn.sendall(msg)


def commands():
    while True:
        print("Enter server commands")
        cmd = input(">>> ")
        if cmd == "sendmessage":
            what_message = input("what to send? ")
            encode_message = bytes(what_message, "utf-8")
            conn.sendall(b"Server owner: "+encode_message)


message = threading.Thread(target=transfer, daemon=False)
server_cmd = threading.Thread(target=commands, daemon=False)
message.start()
server_cmd.start()

当前服务器仅支持单个客户端连接,新客户端无法注册,无法实现真正的多人聊天功能,请问该如何修改代码以让服务器支持多客户端连接?


修改方案

要实现多客户端连接,核心是持续监听新连接,并为每个客户端创建独立的处理线程,同时维护所有客户端连接的集合用于消息广播。以下是修改后的服务器代码:

import socket
import threading

# 存储所有客户端连接的集合,线程安全需加锁
client_connections = set()
conn_lock = threading.Lock()

hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
port = int(input("enter port: "))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((ip, port))
print(f"listening on {ip}:{port}")
# 设置监听队列长度,允许多个等待连接的客户端
s.listen(5)


def handle_client(conn, addr):
    """处理单个客户端的消息接收与广播"""
    print(f"New client connected: {addr}")
    # 将新连接加入集合
    with conn_lock:
        client_connections.add(conn)
    
    try:
        while True:
            msg = conn.recv(2048)
            if not msg:
                # 客户端断开连接
                break
            # 广播消息给所有其他客户端
            with conn_lock:
                for client in client_connections:
                    if client != conn:
                        try:
                            client.sendall(msg)
                        except:
                            # 发送失败,移除失效连接
                            client_connections.remove(client)
    except Exception as e:
        print(f"Client {addr} error: {e}")
    finally:
        # 清理连接
        print(f"Client {addr} disconnected")
        with conn_lock:
            if conn in client_connections:
                client_connections.remove(conn)
        conn.close()


def accept_connections():
    """持续监听并接受新客户端连接"""
    while True:
        conn, addr = s.accept()
        # 为每个客户端启动新线程
        client_thread = threading.Thread(target=handle_client, args=(conn, addr), daemon=True)
        client_thread.start()


def commands():
    """服务器命令处理,支持给所有客户端发消息"""
    while True:
        cmd = input(">>> ")
        if cmd == "sendmessage":
            what_message = input("what to send? ")
            encode_message = b"Server owner: " + bytes(what_message, "utf-8")
            with conn_lock:
                for client in client_connections.copy():
                    try:
                        client.sendall(encode_message)
                    except:
                        client_connections.remove(client)
        elif cmd == "listclients":
            with conn_lock:
                print(f"Current connected clients: {len(client_connections)}")
        elif cmd == "quit":
            print("Shutting down server...")
            with conn_lock:
                for client in client_connections:
                    client.close()
            s.close()
            break


# 启动接受连接的线程
accept_thread = threading.Thread(target=accept_connections, daemon=True)
accept_thread.start()

# 启动命令线程
commands()

修改说明

  • 持续监听新连接:新增accept_connections函数,循环调用s.accept()接受所有新客户端,每个客户端启动独立线程处理。
  • 维护客户端连接集合:使用client_connections存储所有活跃连接,配合线程锁conn_lock保证多线程下的安全操作。
  • 消息广播机制:收到客户端消息后,遍历连接集合,将消息发送给除发送方外的所有客户端。
  • 连接清理:客户端断开或出错时,自动从集合中移除并关闭连接。
  • 增强服务器命令:新增listclients查看在线人数、quit关闭服务器的功能。

客户端代码无需修改,直接使用即可。


内容的提问来源于stack exchange,提问作者user21694465

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:54:57