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

Python Socket聊天程序问题:输入/users返回IP端口而非用户名

问题分析与修复方案

核心问题

代码中线程参数传递错误是导致/users返回IP端口的直接原因:

  • 服务端启动user_conn线程时,传入的第二个参数是addr(客户端IP+端口的元组)
  • 但user_conn函数将第二个参数定义为nicknames,导致函数内部使用的nicknames实际上是客户端的IP端口,而非全局存储用户名的列表。

具体修复步骤

1. 修正线程参数与函数定义

修改server函数中启动线程的代码,移除错误的addr参数传递:

# 原代码
threading.Thread(target=user_conn, args=[client, addr]).start()
# 修正后
threading.Thread(target=user_conn, args=[client]).start()

同时修改user_conn函数的定义,去掉错误的nicknames参数,直接使用全局的nicknames列表:

# 原代码
def user_conn(conn: socket.socket, nicknames):
# 修正后
def user_conn(conn: socket.socket):

2. 优化/users命令的返回格式

将直接发送列表字符串的逻辑改为更友好的格式化文本:

# 原代码
if "/users" in msg:
    conn.sendall(bytearray(str(nicknames).encode()))
# 修正后
if "/users" in msg:
    # 生成友好的在线用户列表文本
    user_list = "当前在线用户: " + ", ".join(nicknames) if nicknames else "暂无在线用户"
    conn.send(user_list.encode(FORMAT))

3. 完善用户断开后的清理逻辑

用户断开连接时,同步移除nicknames中对应的用户名,避免出现用户名残留:

# 原代码
def byeee(conn: socket.socket):
    if conn in clients:
        conn.close()
        clients.remove(conn)
# 修正后
def byeee(conn: socket.socket):
    if conn in clients:
        # 找到客户端对应的索引,同步移除昵称
        idx = clients.index(conn)
        clients.remove(conn)
        conn.close()
        if idx < len(nicknames):
            nicknames.pop(idx)

4. (可选)优化客户端命令发送逻辑

当前客户端发送/users时会带上昵称前缀(如张三: /users),可以修改write函数,让纯命令不带前缀,更简洁:

# 原代码
msg = f"{nickname}: {input('')}"
# 修正后
content = input('')
# 如果是纯命令,直接发送,否则带昵称前缀
msg = content if content.startswith('/') else f"{nickname}: {content}"

修复后的完整代码

服务端代码

import socket, threading

clients = []
nicknames = []
BYTES = 1024
FORMAT = "utf-8"


def server():
    IP = "127.0.0.1"
    PORT = 9090
    BIND = (IP, PORT)

    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(BIND)
        sock.listen()
        print("Welcome to Budget-Discord!")

        while True:
            client, addr = sock.accept()
            print("Connected with {}".format(str(addr)))       
            client.send('NICKNAME'.encode(FORMAT))
            nickname = client.recv(BYTES).decode()
            nicknames.append(nickname)
            clients.append(client)
            print("Nickname is {}".format(nickname))
            print(nicknames)
            client.send("\t >>> Connected to server!".encode(FORMAT))
            # 修正线程参数
            threading.Thread(target=user_conn, args=[client]).start()

    except Exception as e:
        print(f"Error, socket: {e}")


def sendall(msg: str, conn: socket.socket): # Broadcast
    for client_conn in clients:
        if client_conn != conn:
            try:
                client_conn.send(msg.encode())
            except Exception as e:
                print(f"Error, sendall: {e}")
                byeee(client_conn)


# 修正函数参数
def user_conn(conn: socket.socket):
    while True:
        try:
            msg = conn.recv(BYTES).decode()
            if "/users" in msg:
                # 优化返回格式
                user_list = "当前在线用户: " + ", ".join(nicknames) if nicknames else "暂无在线用户"
                conn.send(user_list.encode(FORMAT))
            if msg:
                print(msg)
                allchat = f"{msg}"
                sendall(allchat, conn)
        except Exception as e:
            print(f"Error, user connection: {e}")
            byeee(conn)
            break


# 完善清理逻辑
def byeee(conn: socket.socket):
    if conn in clients:
        idx = clients.index(conn)
        clients.remove(conn)
        conn.close()
        if idx < len(nicknames):
            nicknames.pop(idx)


if __name__ == "__main__":
    server()

客户端代码

import socket, threading

IP = "127.0.0.1"
PORT = 9090
BIND = (IP, PORT)
BYTES = 1024
FORMAT = "utf-8"

nickname = input("Choose your nickname: ")

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     
client.connect(BIND)                            

def receive():
    while True:                                                
        try:
            msg = client.recv(BYTES).decode()
            if msg == 'NICKNAME':
                client.send(nickname.encode())
            else:
                print(msg)
        except Exception as e:
            print(f"Error, client receive: {e}")
            client.close()
            break

def write():
    while True:                                                
        content = input('')
        # 纯命令不带昵称前缀
        msg = content if content.startswith('/') else f"{nickname}: {content}"
        client.send(msg.encode())

receive_t = threading.Thread(target=receive).start()            
write_t = threading.Thread(target=write).start()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 22:25:41