基于Python实现多人聊天室的示例代码

 更新时间:2025年02月20日 10:23:31   作者:席子哥哥的代码库  
这篇文章主要为大家详细介绍了如何基于Python实现多人聊天室功能,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考下

本文主要为大家介绍一下如何实现一个多人聊天室(server+client),感兴趣的小伙伴可以了解下

效果图

通过本地服务器以用户名登录

实现关键代码

支持群聊和私聊

sever端代码:

import socket
import threading
from datetime import datetime
from collections import OrderedDict
 
class ChatServer:
    def __init__(self, host='0.0.0.0', port=50000):
        self.clients = OrderedDict()
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server.bind((host, port))
        self.server.listen(5)
        print(f"🟢 服务端已启动在 {host}:{port}")
 
    def handle_client(self, conn, addr):
        username = None
        try:
            username = conn.recv(1024).decode().strip()
            if not username or username in self.clients:
                conn.send("USERNAME_INVALID".encode())
                conn.close()
                return
 
            conn.send("CONNECT_SUCCESS".encode())
            self.clients[username] = conn
            self.broadcast_system_msg(f"🚩 {username} 进入聊天室")
            self.broadcast_userlist()
 
            while True:
                try:
                    data = conn.recv(4096)
                    if not data: break
                    
                    msg = data.decode().strip()
                    if msg == "HEARTBEAT":
                        conn.send(b"HEARTBEAT_ACK")
                    elif msg.startswith("@@"):
                        target, _, content = msg[2:].partition(' ')
                        self.handle_private(username, target, content)
                    else:
                        self.broadcast_msg(f"{username}:{msg}")
 
                except Exception as e:
                    print(f"处理错误:{str(e)}")
                    break
 
        except ConnectionResetError:
            print(f"❌ {username} 异常断开")
        finally:
            if username in self.clients:
                del self.clients[username]
                self.broadcast_system_msg(f"🚩 {username} 离开聊天室")
                self.broadcast_userlist()
            conn.close()
 
    def handle_private(self, sender, target, content):
        if target in self.clients:
            timestamp = datetime.now().strftime("%H:%M:%S")
            msg = f"[{timestamp}] [私聊] {sender} -> 你:{content}"
            self.clients[target].send(msg.encode())
            self.clients[sender].send(msg.encode())
        else:
            self.clients[sender].send(f"用户 {target} 不在线".encode())
 
    def broadcast_msg(self, msg):
        timestamp = datetime.now().strftime("%H:%M:%S")
        full_msg = f"[{timestamp}] {msg}\n"
        for client in self.clients.values():
            try: client.send(full_msg.encode())
            except: pass
 
    def broadcast_system_msg(self, msg):
        full_msg = f"SYSTEM:{msg}\n"
        for client in self.clients.values():
            try: client.send(full_msg.encode())
            except: pass
 
    def broadcast_userlist(self):
        user_list = ",".join(self.clients.keys())
        msg = f"USERLIST:{user_list}\n"
        for client in self.clients.values():
            try: client.send(msg.encode())
            except: pass
 
    def start(self):
        while True:
            conn, addr = self.server.accept()
            threading.Thread(target=self.handle_client, args=(conn, addr)).start()
 
if __name__ == "__main__":
    ChatServer().start() 

客户端代码:

import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import socket
import threading
 
class ChatClient:
    def __init__(self, master):
        self.master = master
        self.client_socket = None
        self.username = ""
        self.running = False
        
        master.title("在线聊天室")
        master.geometry("900x600")
        self.create_widgets()
        self.show_login_dialog()
 
    def create_widgets(self):
        self.user_frame = ttk.Frame(self.master, width=200)
        self.user_frame.pack(side=tk.LEFT, fill=tk.Y)
        
        self.user_list = ttk.Treeview(self.user_frame, show="tree", selectmode='browse')
        self.user_list.pack(expand=True, fill=tk.BOTH)
        self.user_list.bind('<<TreeviewSelect>>', self.select_user)
 
        self.chat_frame = ttk.Frame(self.master)
        self.chat_frame.pack(expand=True, fill=tk.BOTH)
        
        self.chat_area = scrolledtext.ScrolledText(self.chat_frame, state=tk.DISABLED)
        self.chat_area.pack(expand=True, fill=tk.BOTH)
        
        # 输入框和按钮框架
        input_frame = ttk.Frame(self.chat_frame)
        input_frame.pack(fill=tk.X, pady=5)
        
        self.msg_entry = ttk.Entry(input_frame)
        self.msg_entry.pack(side=tk.LEFT, expand=True, fill=tk.X)
        self.msg_entry.bind("<Return>", self.send_message)
        
        # 添加发送按钮
        send_btn = ttk.Button(input_frame, text="发送", command=self.send_message)
        send_btn.pack(side=tk.RIGHT, padx=5)
 
    def select_user(self, event):
        selected = self.user_list.selection()
        if selected:
            target = self.user_list.item(selected[0])['text']
            current = self.msg_entry.get()
            self.msg_entry.delete(0, tk.END)
            self.msg_entry.insert(0, f"@@{target} " if not current.startswith("@") else "")
 
    def show_login_dialog(self):
        self.login_dialog = tk.Toplevel(self.master)
        self.login_dialog.title("登录")
        
        ttk.Label(self.login_dialog, text="服务器地址:").grid(row=0, column=0, padx=5, pady=5)
        self.server_entry = ttk.Entry(self.login_dialog)
        self.server_entry.insert(0, "127.0.0.1")
        self.server_entry.grid(row=0, column=1, padx=5, pady=5)
 
        ttk.Label(self.login_dialog, text="端口号:").grid(row=1, column=0, padx=5, pady=5)
        self.port_entry = ttk.Entry(self.login_dialog)
        self.port_entry.insert(0, "50000")
        self.port_entry.grid(row=1, column=1, padx=5, pady=5)
 
        ttk.Label(self.login_dialog, text="用户名:").grid(row=2, column=0, padx=5, pady=5)
        self.username_entry = ttk.Entry(self.login_dialog)
        self.username_entry.grid(row=2, column=1, padx=5, pady=5)
 
        ttk.Button(self.login_dialog, text="登录", command=self.connect_server).grid(row=3, columnspan=2, pady=10)
 
    def connect_server(self):
        server = self.server_entry.get()
        port = self.port_entry.get()
        self.username = self.username_entry.get().strip()
 
        if not self.username:
            messagebox.showerror("错误", "用户名不能为空")
            return
 
        try:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.client_socket.connect((server, int(port)))
            self.client_socket.send(self.username.encode())
            
            response = self.client_socket.recv(1024).decode()
            if response != "CONNECT_SUCCESS":
                messagebox.showerror("错误", f"连接失败: {response}")
                return
 
            self.running = True
            self.login_dialog.destroy()
            self.master.title(f"在线聊天室 - {self.username}")
            threading.Thread(target=self.receive_messages, daemon=True).start()
 
        except Exception as e:
            messagebox.showerror("连接失败", str(e))
            if self.client_socket:
                self.client_socket.close()
 
    def receive_messages(self):
        buffer = ""
        while self.running:
            try:
                data = self.client_socket.recv(4096)
                if not data: break
                
                buffer += data.decode()
                while "\n" in buffer:
                    msg, buffer = buffer.split("\n", 1)
                    if msg.startswith("USERLIST:"):
                        self.update_user_list(msg[9:].split(','))
                    elif msg.startswith("SYSTEM:"):
                        self.display_system_msg(msg[7:])
                    else:
                        self.display_message(msg)
            except:
                break
 
    def update_user_list(self, users):
        current = set(self.user_list.get_children())
        online = set(users)
        
        for user in current - online:
            self.user_list.delete(user)
        
        for user in online - current:
            self.user_list.insert("", "end", iid=user, text=user)
 
    def display_message(self, msg):
        self.chat_area.config(state=tk.NORMAL)
        self.chat_area.insert(tk.END, msg + "\n")
        self.chat_area.see(tk.END)
        self.chat_area.config(state=tk.DISABLED)
 
    def display_system_msg(self, msg):
        self.chat_area.config(state=tk.NORMAL)
        self.chat_area.insert(tk.END, f"【系统】{msg}\n", 'system')
        self.chat_area.see(tk.END)
        self.chat_area.config(state=tk.DISABLED)
 
    def send_message(self, event=None):
        msg = self.msg_entry.get().strip()
        if msg:
            try:
                self.client_socket.send(f"{msg}\n".encode())
                self.msg_entry.delete(0, tk.END)
                if msg.startswith("@@"):
                    self.display_message(f"[我] 私聊 {msg[2:].split(' ')[0]}:{' '.join(msg.split()[1:])}")
                else:
                    self.display_message(f"[我]:{msg}")
            except Exception as e:
                messagebox.showerror("发送失败", str(e))
 
if __name__ == "__main__":
    root = tk.Tk()
    app = ChatClient(root)
    root.mainloop() 

以上就是基于Python实现多人聊天室的示例代码的详细内容,更多关于Python多人聊天室的资料请关注脚本之家其它相关文章!

相关文章

  • python读取图片并修改格式与大小的方法

    python读取图片并修改格式与大小的方法

    这篇文章主要为大家详细介绍了python读取图片并修改格式与大小的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • python如何用matplotlib创建三维图表

    python如何用matplotlib创建三维图表

    这篇文章主要介绍了python如何在matplotlib中创建三维图表,帮助大家更好的利用python进行数据分析,感兴趣的朋友可以了解下
    2021-01-01
  • Selenium自动化测试工具使用方法汇总

    Selenium自动化测试工具使用方法汇总

    这篇文章主要介绍了Selenium自动化测试工具使用方法汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • python 统计代码耗时的几种方法分享

    python 统计代码耗时的几种方法分享

    本文实例讲述了Python中统计代码片段、函数运行耗时的几种方法,分享给大家,仅供参考。
    2021-04-04
  • 详解TensorFlow训练网络两种方式

    详解TensorFlow训练网络两种方式

    本文主要介绍了TensorFlow训练网络两种方式,一种是基于tensor(array),另外一种是迭代器,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Python subprocess库六个实例快速掌握

    Python subprocess库六个实例快速掌握

    这次来说Python的第三方库subprocess库,在python2.4以上的版本commands模块被subprocess取代了。一般当我们在用Python写运维脚本时,需要履行一些Linux shell的命令,Python中subprocess模块就是专门用于调用Linux shell命令,并返回状态和结果,可以完美的解决这个问题
    2022-10-10
  • django inspectdb 操作已有数据库数据的使用步骤

    django inspectdb 操作已有数据库数据的使用步骤

    这篇文章主要介绍了django inspectdb 操作已有数据库数据的使用步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • Python打印“菱形”星号代码方法

    Python打印“菱形”星号代码方法

    本篇文章通过代码实例给大家详细分析了Python打印“菱形”星号代码方法,对此有需要的朋友参考下吧。
    2018-02-02
  • python里读写excel等数据文件的6种常用方式(小结)

    python里读写excel等数据文件的6种常用方式(小结)

    这篇文章主要介绍了python里读写excel等数据文件的6种常用方式(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 基于Python制作一个汇率换算程序

    基于Python制作一个汇率换算程序

    这篇文章主要为大家详细介绍了如何利用Python语言制作一个汇率换算程序,文中的示例代码讲解详细,对我们学习Python有一定帮助,需要的可以参考一下
    2022-09-09

最新评论