你能否用一个案例演示Python的SocketServer模块的用法

访客 网络编程 1

本文目录导读:

  1. 服务端代码 (server.py)
  2. 客户端代码 (client.py)
  3. 运行效果演示
  4. 关键知识点

我来用一个简单的多人在线聊天室案例演示 socketserver 模块的用法,这个案例包含服务端和客户端,支持多用户同时在线聊天。

服务端代码 (server.py)

import socketserver
import threading
from datetime import datetime
class ChatHandler(socketserver.StreamRequestHandler):
    # 存储所有连接的客户端
    clients = {}
    clients_lock = threading.Lock()
    def setup(self):
        """连接建立时的初始化"""
        print(f"新客户端连接: {self.client_address}")
    def handle(self):
        """处理客户端消息的主循环"""
        # 客户端连接后,先接收用户名
        try:
            username = self.rfile.readline().strip().decode('utf-8')
            if not username:
                return
            # 将客户端加入在线列表
            with self.clients_lock:
                self.__class__.clients[username] = self
            # 广播用户上线消息
            self.broadcast(f"📢 {username} 加入了聊天室", exclude=None)
            # 发送欢迎消息给当前用户
            welcome_msg = f"🟢 欢迎 {username} 加入聊天室!当前在线人数: {len(self.clients)}"
            self.send_message(welcome_msg)
            self.send_message("💡 输入 'quit' 退出聊天, 输入 'users' 查看在线用户")
            # 持续接收和转发消息
            while True:
                data = self.rfile.readline().strip()
                if not data:
                    break
                message = data.decode('utf-8')
                # 处理特殊命令
                if message.lower() == 'quit':
                    break
                elif message.lower() == 'users':
                    # 显示在线用户
                    with self.clients_lock:
                        online_users = ', '.join(self.clients.keys())
                    self.send_message(f"👥 当前在线用户: {online_users}")
                else:
                    # 广播普通消息
                    timestamp = datetime.now().strftime("%H:%M:%S")
                    formatted_msg = f"[{timestamp}] {username}: {message}"
                    self.broadcast(formatted_msg, exclude=None)
        except Exception as e:
            print(f"处理客户端消息时出错: {e}")
        finally:
            self.cleanup(username)
    def cleanup(self, username):
        """清理客户端连接"""
        if username:
            with self.clients_lock:
                if username in self.clients:
                    del self.clients[username]
            # 广播用户离线消息
            self.broadcast(f"📢 {username} 离开了聊天室", exclude=None)
            print(f"客户端断开: {username} ({self.client_address})")
    def send_message(self, message):
        """发送消息到当前客户端"""
        try:
            self.wfile.write((message + '\n').encode('utf-8'))
            self.wfile.flush()
        except:
            pass
    def broadcast(self, message, exclude=None):
        """广播消息给所有客户端(可选排除某个客户端)"""
        with self.clients_lock:
            for username, client in self.clients.items():
                if username != exclude:
                    try:
                        client.send_message(message)
                    except:
                        pass
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    """支持多线程的TCP服务器"""
    allow_reuse_address = True
    daemon_threads = True
def main():
    HOST = 'localhost'
    PORT = 12345
    server = ThreadedTCPServer((HOST, PORT), ChatHandler)
    print(f"服务器启动在 {HOST}:{PORT}")
    print("等待客户端连接...")
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\n服务器关闭...")
        server.shutdown()
        server.server_close()
if __name__ == '__main__':
    main()

客户端代码 (client.py)

import socket
import threading
import sys
class ChatClient:
    def __init__(self, host='localhost', port=12345):
        self.host = host
        self.port = port
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.running = True
    def connect(self):
        """连接到服务器"""
        try:
            self.socket.connect((self.host, self.port))
            print(f"已连接到服务器 {self.host}:{self.port}")
            return True
        except Exception as e:
            print(f"连接失败: {e}")
            return False
    def send_username(self, username):
        """发送用户名"""
        self.socket.send((username + '\n').encode('utf-8'))
    def receive_messages(self):
        """接收消息的线程"""
        while self.running:
            try:
                data = self.socket.recv(1024)
                if not data:
                    print("\n[连接已断开]")
                    self.running = False
                    break
                message = data.decode('utf-8').strip()
                if message:
                    print(f"\r{message}\n> ", end='', flush=True)
            except Exception as e:
                if self.running:
                    print(f"\n[接收消息出错: {e}]")
                    self.running = False
                break
    def send_messages(self):
        """发送消息的主循环"""
        while self.running:
            try:
                message = input("> ")
                if message:
                    self.socket.send((message + '\n').encode('utf-8'))
                    if message.lower() == 'quit':
                        break
            except (EOFError, KeyboardInterrupt):
                break
            except Exception as e:
                print(f"发送消息出错: {e}")
                break
        self.running = False
        self.socket.close()
def main():
    # 获取用户输入
    host = input("服务器地址 (默认 localhost): ") or 'localhost'
    port = input("端口号 (默认 12345): ") or '12345'
    username = input("请输入你的昵称: ")
    # 创建并连接客户端
    client = ChatClient(host, int(port))
    if not client.connect():
        return
    # 发送用户名
    client.send_username(username)
    print("\n=== 欢迎来到聊天室 ===")
    print("输入消息发送,输入 'quit' 退出")
    print("=" * 30)
    # 启动接收线程
    receive_thread = threading.Thread(target=client.receive_messages)
    receive_thread.daemon = True
    receive_thread.start()
    # 在主线程中发送消息
    client.send_messages()
    print("\n已退出聊天室")
if __name__ == '__main__':
    main()

运行效果演示

第一步:启动服务器

python server.py
# 输出:
# 服务器启动在 localhost:12345
# 等待客户端连接...

第二步:启动多个客户端(打开多个终端)

# 终端1 - 用户 Alice
python client.py
# 输入:服务器地址 localhost
# 输入:端口 12345
# 输入:昵称 Alice
# 终端2 - 用户 Bob
python client.py
# 输入:服务器地址 localhost
# 输入:端口 12345
# 输入:昵称 Bob

聊天演示

# Alice 的终端:
> 大家好!
[14:30:25] Alice: 大家好!
> 今天天气不错
[14:30:45] Alice: 今天天气不错
# Bob 的终端:
📢 Alice 加入了聊天室
> 嗨,Alice!
[14:30:25] Alice: 大家好!
> 
[14:30:45] Alice: 今天天气不错
> 是啊,很适合出去玩
[14:31:00] Bob: 是啊,很适合出去玩
# 使用命令:
> users
👥 当前在线用户: Alice, Bob
> quit
📢 Bob 离开了聊天室

关键知识点

socketserver 核心类

  • StreamRequestHandler:处理TCP连接
  • ThreadingMixIn:添加多线程支持
  • TCPServer:基础的TCP服务器

主要方法

  • setup():连接初始化
  • handle():处理客户端请求
  • finish():连接清理

通信协议

  • 使用 rfile.readline() 读取数据(文本模式)
  • 使用 wfile.write() 发送数据
  • 每条消息以换行符 \n

线程安全

  • 使用 threading.Lock 保护共享数据
  • daemon_threads = True 自动管理线程生命周期

这个案例展示了 socketserver 模块的核心用法,包括多线程处理、消息广播、用户管理等实际聊天室功能,你可以基于此扩展更多功能,如私聊、文件传输、房间管理等。

标签: multithreading TCP server

抱歉,评论功能暂时关闭!