基于python面向对象多人聊天室

基于python面向对象多人聊天室

1、项目环境

项目名称:多人聊天室
项目模式:C/S
开发环境:win10+python3.8+pycharm
所需知识:python GUI编程,多线程编程,网络编程,数据库编程

2、流程

多人通讯方式
单人通讯方式

3、程序设计

了解一下服务器扮演的角色,下面是服务器的业务流程。大致工作模式
服务器:
在这里插入图片描述

客户端:
在这里插入图片描述

  • 首先服务器在指定的端口进行监听,等待客户的链接
  • 客户端链接到服务器之后,服务器开启单线程来处理该用户的请求
  • 处理线程等待客户端发送的请求
  • 服务器根据客户端请求类型的不同,调用不同处理的函数
  • 处理完客户端请求之后,再次回到第三步继续等待处理客户端新的请求
  • 客户端退出登录,服务器也会关闭对客户端的处理线程,释放资源

4、响应协议设计

  • 我们都知道三次握手和四次挥手,这里呢我们约定了客户端发送什么样格式的数据给服务器,服务器又需要返回什么样格式的数据给客户端,客户端会有不同的请求,所以我们针对不同的请求个响应定义了需求个相应号,来区分不同的请求和响应

  • 网络上一般使用json和xml格式来传输数据,但是用他们来传输,对于我们的项目有点复杂,我们的项目没有这么复杂的数据,我们采用|进行分割,然后拿到数据进行split一下就可以了。

  • 登录响应格式: 1001|ret|nickname|username,其中ret
    代表服务器端验证的结果,如果是0,表示服务端验证失败,后面的nickname username
    会为空字符串,若是1 ,表示服务端验证成功,nickname 为服务端返回的该用户的昵称,username 是该用户的用户名。

  • 聊天的响应格式:1002|nickname|message, nicakname 是为聊天信息发送者的昵称,message
    是发送的聊天信息

    下面我们定义了服务端需要的一些常量,以及为了实现客户端和服务端通信定义的一些协议编号,协议编号如下:

#----数据协议相关配置----
REQUEST_LOGIN = '0001' #登陆请求
REQUEST_CHAT= '0002' #聊天请求
RESPONSE_LOGIN_RESULT = '1001' #登陆结果响应
RESPONSE_CHAT= '1002' #聊天响应
DELIMITER = '|' #自定义协议数据分割符
SERVER_IP = '127.0.0.1' #服务器地址
SERVER_PORT = 8090 #服务器端口

5、面向对象的思想

服务器、客户端分离设计内容:
在这里插入图片描述

6、服务器通讯实现

  1. 制作协议报头,响应数据,制定一个模块config.py
#----数据协议相关配置----
REQUEST_LOGIN = '0001' #登陆请求
REQUEST_CHAT= '0002' #聊天请求
RESPONSE_LOGIN_RESULT = '1001' #登陆结果响应
RESPONSE_CHAT= '1002' #聊天响应
DELIMITER = '|' #自定义协议数据分割符
SERVER_IP = '127.0.0.1' #服务器地址
SERVER_PORT = 8090 #服务器端口


#----数据库相关配置----   #具体参数自己设置
DB_HOST='127.0.0.1'#这里是你数据库IP地址
DB_PORT=3306       #这里是你数据库端口
DB_NAME='py_chat'  #这里是你数据库名
DB_USER='root'     #这里是你数据库登陆账号
DB_PASSWD='123456' #这里是你数据库密码
CHARSET='utf-8'

  1. 处理服务器响应字符串的拼接,制定一个模块response_protocol.py
from config import *

class ResponseProtocol (object):
    """服务器响应协议的格式字符串处理"""
    @staticmethod
    def response_login_result(result: str, nickname: str, username: str) -> str:
        """
            拼接登陆响应
            :param result:登陆结果,0或则1,0标识登陆失败,1标识登陆成功
            :param nickname:登陆名,登陆失败,该值为空字符串
            :param username:登陆ID,登陆失败,该值为空字符串
            :return 登陆结果相应格式字符串
        """
        return DELIMITER.join ([RESPONSE_LOGIN_RESULT, result, nickname, username])

    @staticmethod
    def response_chat(nickname, messages):
        """
        拼接聊天相应,数据格式为:“相应协议编号|聊天发送者昵称|聊天信息”
        :param nickname: 聊天内容发送者昵称
        :param messages: 聊天内容
        :return: 聊天相应协议格式字符串
        """
        return DELIMITER.join([RESPONSE_CHAT, nickname, messages])

7、主体框架搭建

基本逻辑业务-服务端
server.py 模块定义Server类来处理服务器业务逻辑,该类实现了服务器的主体框架

from server_socket import ServerSoket
from socket_warpper import SocketWrapper
from threading import Thread
from config import *
from response_protocol import *
from dbHandle import DBHandle


class Server(object):
    """自定义套接字,负责初始化服务器套接字需要的相关参数"""

    def __init__(self):
        # 初始化套结字
        self.server_socket = ServerSoket()

        # 创建请求的ID和方法关联字典
        self.requset_handle_function = {}
        self.register(REQUEST_LOGIN, self.request_login_handle)
        self.register(REQUEST_CHAT, self.request_chat_handle)
        # 创建保存当前登录用户字典
        self.clients = {}
        self.db = DBHandle()

    '''注册消息类型和处理函数到字典'''

    def register(self, requeset_id, handle_function):

        self.requset_handle_function[requeset_id] = handle_function

    '''启动程序'''

    def startup(self):
        """启动器"""
        while True:
            print('正在等待客户端连接')
            soc, addr = self.server_socket.accept()
            # print ('获取到客户端连接')
            client_soc = SocketWrapper(soc)
            # 启动线程处理该用户请求
            Thread(target=lambda: self.request_handle(client_soc)).start()

    '''处理客户端数据'''

    def request_handle(self, client_soc):
        while True:
            # 接收客户端数据
            recv_data = client_soc.recv_data()
            if not recv_data:
                # 没有接收到数据客户端应该已经关闭
                self.remve_offline_user(client_soc)
                client_soc.close()
                break
            '''解析数据'''
            parse_data = self.parse_request_text(recv_data)
            '''分析请求类型,并依据请求类型调用相应的分类处理'''
            '''
            # 获得使用的方法名 方法名 = 字典[value]  注: 如 字典[key]可以互相找到字典[value]
            # 此处 字典[key]=0001 对应得字典[value] = REQUEST_LOGIN
            #例子:
            parse_data = '0001|XXX|XXX'
            parse_data['requset_id'] = ‘0001’
            requset_handle_function['0001'] = self.request_login_handle
            handle_funtion = self.request_login_handle
            '''
            handle_funtion = self.requset_handle_function.get(parse_data['requset_id'])

            if handle_funtion:
                # 按照方法名调用方法
                handle_funtion(client_soc, parse_data)
            else:
                # 如果传输内容不匹配,返回错误请求
                self.request_err_handle(client_soc)

    '''用户离线操作'''

    def remve_offline_user(self, client_soc):
        for username, info in self.clients.items():
            if info['sock'] == client_soc:
                print(self.clients[username]['nickname'] + '已经离开')
                del self.clients[username]
                break

        '''解析客户端发送来的数据'''

    '''解析数据内容'''

    def parse_request_text(self, recv_data):
        '''
        登录信息
        登录信息:0001|username|password
        聊天信息:0002|username|messages
        错误信息:err
        '''

        print('解析客户端数据:' + recv_data)
        requset_list = recv_data.split(DELIMITER)
        requset_data = {}
        requset_data['requset_id'] = requset_list[0]
        if requset_data['requset_id'] == REQUEST_LOGIN:
            requset_data['username'] = requset_list[1]
            requset_data['password'] = requset_list[2]
        elif requset_data['requset_id'] == REQUEST_CHAT:
            requset_data['username'] = requset_list[1]
            requset_data['messages'] = requset_list[2]
        return requset_data

    '''登录处理'''

    def request_login_handle(self, client_sock, requet_data):
        # print('收到登录请求')
        username = requet_data['username']
        password = requet_data['password']
        # 查询用户是否合法
        ret, nickname, username = self.check_user_login(username, password)
        # 如果登录成功,则保存用户连接套接字
        if ret == '1':
            self.clients[username] = {'sock': client_sock, 'nickname': nickname}
        # 组装响应结果
        response_text = ResponseProtocol.response_login_result(ret, nickname, username)
        # 发送响应结果
        client_sock.send_data(response_text)

    '''聊天处理'''

    def request_chat_handle(self, client_sock, requet_data):
        # 获取消息内容

        username = requet_data['username']
        messages = requet_data['messages']

        try:
            nickname = self.clients[username]['nickname']
        except:
            client_sock.send_data('您未登录,请登录后再发消息')
            return
        # 拼接发送给客户的消息文本
        msg = ResponseProtocol.response_chat(nickname, messages)
        # 转发消息给在线用户
        for u_name, info in self.clients.items():
            if username == u_name:
                continue
            info['sock'].send_data(msg)
            print(msg)

    '''错误信息处理'''

    def request_err_handle(self, client_sock):
        print("传输数据出错------")
        client_sock.send_data('数据无效,请重新确认')

    '''检查用户是否登录成功,返回检查结果(0/失败,1/成功,昵称,用户账号'''

    def check_user_login(self, username, password):

        # print("正在检测是否成功")
        # 从数据库查询用户信息
        sql = "select * from users where username = '%s' " % username
        result = self.db.get_one(sql)
        # 如果没有查询结果,用户不存在,登录失败
        if not result:
            # print("用户不存在,登录失败")
            return '-1', ' ', username
        # 密码不匹配,说明密码错误,登录失败
        if password != result["password"]:
            # print("密码错误,登录失败")
            return '0', ' ', username
        # 登录成功
        # print("验证正确,登录成功")
        print(result['nickname'] + "进入聊天室")
        return '1', result['nickname'], username


if __name__ == '__main__':
    Server().startup()

  • 这里我们自定义一个套接字,让类继承socket、super找父类的套接字有一个初始化,不初始化的类型告诉他
import socket
import config

class ServerSoket(socket.socket):
    """自定义套接字,负责初始化服务器套接字需要的相关参数"""

    def __init__(self ):
        #设置TCP类型
        
        #初始化套结字
        super(ServerSoket,self).__init__(socket.AF_INET,socket.SOCK_STREAM)

        self.bind((config.SERVER_IP,config.SERVER_PORT))

        #设置为监听模式
        self.listen(128)

super(ServerSocket,self).init(socket.AF_INET,socket.SOCK_STREAM),绑定地址和端口,这里的参数不能写死,因为你要是写死,以后你要改代码要找一大堆的代码,这里我们把它固定在config.py 里面,以后要想改直接到配置相关项去改。

  • 初始化服务器套接字需要的相关操作。
from server_socket import ServerSocket
from socket_wrapper import SocketWrapper
from threading import Thread
class Server(object):
    """服务器的核心类"""
     def __init__(self):
        # 初始化套结字
        self.server_socket = ServerSoket()
        # 创建请求的ID和方法关联字典
        self.requset_handle_function = {}
        self.register(REQUEST_LOGIN, self.request_login_handle)
        self.register(REQUEST_CHAT, self.request_chat_handle)
        # 创建保存当前登录用户字典
        self.clients = {}
        self.db = DBHandle()

     def startup(self):
        """启动器"""
        while True:
            print('正在等待客户端连接')
            soc, addr = self.server_socket.accept()
            # print ('获取到客户端连接')
            client_soc = SocketWrapper(soc)
            # 启动线程处理该用户请求
            Thread(target=lambda: self.request_handle(client_soc)).start()

首先在__ init__ 方法里创建监听的套接字,当我们调用start方法启动服务器程序,在该函数中我们使用while来获取客户端的连接,有客户连接到服务器,服务器会获取一个套接字来标识与该客户的连接,然后我们开启新的线程来处理客户端的连接,该线程函数为Server类中的request_handle方法,该方法接收套接字作为参数,request_handle 方法是服务端请求处理的核心方法

8、消息处理request_handle 的处理

接收–>解析–>判断–>处理

def __init__(self):
        # 初始化套结字
        self.server_socket = ServerSoket()
        # 创建请求的ID和方法关联字典
        self.requset_handle_function = {}
        self.register(REQUEST_LOGIN, self.request_login_handle)
        self.register(REQUEST_CHAT, self.request_chat_handle)
        # 创建保存当前登录用户字典
        self.clients = {}
        
def register(self, requeset_id, handle_function):
		'''注册消息类型和处理函数到字典'''
        self.requset_handle_function[requeset_id] = handle_function
        
def request_handle(self, client_soc):
		'''处理客户端数据'''
        while True:
            # 接收客户端数据
            recv_data = client_soc.recv_data()
            if not recv_data:
                # 没有接收到数据客户端应该已经关闭
                self.remve_offline_user(client_soc)
                client_soc.close()
                break
            '''解析数据'''
            parse_data = self.parse_request_text(recv_data)
            '''分析请求类型,并依据请求类型调用相应的分类处理'''
            '''
            # 获得使用的方法名 方法名 = 字典[value]  注: 如 字典[key]可以互相找到字典[value]
            # 此处 字典[key]=0001 对应得字典[value] = REQUEST_LOGIN
            #例子:
            parse_data = '0001|XXX|XXX'
            parse_data['requset_id'] = ‘0001’
            requset_handle_function['0001'] = self.request_login_handle
            handle_funtion = self.request_login_handle
            '''
            handle_funtion = self.requset_handle_function.get(parse_data['requset_id'])

            if handle_funtion:
                # 按照方法名调用方法
                handle_funtion(client_soc, parse_data)
            else:
                # 如果传输内容不匹配,返回错误请求
                self.request_err_handle(client_soc)
  • 我们接受到客户的数据之后看它发来的数据类型是什么,调用相应的处理函数,这里的id类型和方法是唯一的,我们只需要初始化一次就可以,在init初始化。在后面我们不可能只有发送信息的功能,可能还有图片,视频等等在初始化里面加功能id就可以,来梳理思路:假如发送的消息是0001|uu|11111
    调用 parse_request_text,按照类型分析数据 ,发现id=0001,返回 request_data
    ,分析请求类型,调用相应的处理函数 ,调用 request_handle_function, 发现请求的id在里面,开始调用登录功能。

9、登录和聊天功能的处理

  • 获取登录的用户名和密码
  • 查询数据,是否存在对应的用户
  • 如果登录成功,保存用户信息,失败什么都不做
  • 返回登录结果给客户端
'''登录处理'''

    def request_login_handle(self, client_sock, requet_data):
        # print('收到登录请求')
        username = requet_data['username']
        password = requet_data['password']
        # 查询用户是否合法
        ret, nickname, username = self.check_user_login(username, password)
        # 如果登录成功,则保存用户连接套接字
        if ret == '1':
            self.clients[username] = {'sock': client_sock, 'nickname': nickname}
        # 组装响应结果
        response_text = ResponseProtocol.response_login_result(ret, nickname, username)
        # 发送响应结果
        client_sock.send_data(response_text)
'''聊天处理'''

def request_chat_handle(self, client_sock, requet_data):
    # 获取消息内容

    username = requet_data['username']
    messages = requet_data['messages']

    try:
        nickname = self.clients[username]['nickname']
    except:
        client_sock.send_data('您未登录,请登录后再发消息')
        return
    # 拼接发送给客户的消息文本
    msg = ResponseProtocol.response_chat(nickname, messages)
    # 转发消息给在线用户
    for u_name, info in self.clients.items():
        if username == u_name:
            continue
        info['sock'].send_data(msg)
        print(msg)
'''检查用户是否登录成功,返回检查结果(0/失败,1/成功,昵称,用户账号'''

def check_user_login(self, username, password):

    # print("正在检测是否成功")
    # 从数据库查询用户信息
    sql = "select * from users where username = '%s' " % username
    result = self.db.get_one(sql)
    # 如果没有查询结果,用户不存在,登录失败
    if not result:
        # print("用户不存在,登录失败")
        return '-1', ' ', username
    # 密码不匹配,说明密码错误,登录失败
    if password != result["password"]:
        # print("密码错误,登录失败")
        return '0', ' ', username
    # 登录成功
    # print("验证正确,登录成功")
    print(result['nickname'] + "进入聊天室")
    return '1', result['nickname'], username

10、数据库的处理

  • 新建dbHandle.py
from  pymysql import connect
from  config import  *

class DBHandle(object):
    '''mysql管理器'''

    def __init__(self):
        '''初始化数据库'''
        self.conn= connect(host=DB_HOST,
                           port=DB_PORT,
                           database=DB_NAME,
                           user=DB_USER,
                           password=DB_PASSWD)
        self.cursor = self.conn.cursor()

    # 释放数据库资源
    def close_db(self):
        self.cursor.close()
        self.conn.close()

    def get_one(self, sql):
        #执行SQL结果
        self.cursor.execute(sql)
        #获取查询结果
        query_result = self.cursor.fetchone()
        #判断是否有结果
        if not query_result:
            return None
        #获得字段名称列表
        fileds = [filed[0] for filed in self.cursor.description]
        #保存返回结果
        return_data = {}
        for filed, value in zip(fileds, query_result):
            return_data[filed] = value
        #查询结果
        return return_data
  • 清理离线的用户
 '''用户离线操作'''

    def remve_offline_user(self, client_soc):
        for username, info in self.clients.items():
            if info['sock'] == client_soc:
                print(self.clients[username]['nickname'] + '已经离开')
                del self.clients[username]
                break
  • 聊天功能处理:通过服务器向每一个登录在线的人转发消息,不需要向自己发消息
    ‘’‘聊天处理’’’
 def request_chat_handle(self, client_sock, requet_data):
        # 获取消息内容

        username = requet_data['username']
        messages = requet_data['messages']

        try:
            nickname = self.clients[username]['nickname']
        except:
            client_sock.send_data('您未登录,请登录后再发消息')
            return
        # 拼接发送给客户的消息文本
        msg = ResponseProtocol.response_chat(nickname, messages)
        # 转发消息给在线用户
        for u_name, info in self.clients.items():
            if username == u_name:
                continue
            info['sock'].send_data(msg)
            print(msg)

11、客户端实现

客户端采用GUI视图来写
登录窗口显示
新建项目 Client
新建win_client.py

from tkinter import Tk
from tkinter import Label,Entry,Frame,Button,LEFT,END


class WindowLogin (Tk):
    """登陆窗口"""

    def __init__(self):
        super (WindowLogin, self).__init__ ()

        # 设置窗口属性
        self.window_init ()

        # 填充控件
        self.add_widgets ()

        # self.on_reset_button_click (lambda :print(self.get_username()))

        # self.on_login_button_click (lambda: print(self.get_password()))

    """初始化窗口属性"""
    def window_init(self):
        #设置窗口标题
        self.title('登陆窗口')
        #设置窗口不能被拉伸
        self.resizable  (False,False)

        #获取窗口的位置变量
        window_width = 255
        window_height =100
        screenWidth = self.winfo_screenwidth()
        screenHeight = self.winfo_screenheight()
        pos_x = (screenWidth-window_width)/2
        pos_y = (screenHeight-window_height)/2
        #设置窗口大小和位置
        self.geometry('%dx%d+%d+%d' % (window_width,window_height,pos_x,pos_y))

    """添加控件到窗口"""
    def add_widgets(self):
        """添加控件到窗口"""

        # 用户名提示标签
        username_label = Label (self)
        username_label['text'] = '用户名:'
        username_label.grid (row=0, column=0, padx=10, pady=5)

        # 用户名输入文本框
        username_entry = Entry (self, name='username_entry')
        username_entry['width'] = 20
        username_entry.grid (row=0, column=1, padx=10, pady=5)

        # 密码提示标签
        password_label = Label (self)
        password_label['text'] = '密 码:'
        password_label.grid (row=1, column=0)

        # 密码输入文本框
        password_entry = Entry (self, name='password_entry')
        password_entry['show'] = '*'
        username_entry['width'] = 20
        password_entry.grid (row=1, column=1)

        # 按钮区
        button_frame = Frame (self, name='button_frame')

        # 重置按钮
        reset_button = Button (button_frame, name='reset_button')
        reset_button['text'] = '重置'
        reset_button.pack (side=LEFT, padx=40)

        # 登录按钮
        login_button = Button (button_frame, name='login_button')
        login_button['text'] = '登录'
        login_button.pack (side=LEFT)

        button_frame.grid (row=2, columnspan=2, pady=5)

    def get_username(self):
        """获取用户名"""
        return self.children['username_entry'].get ()

    def get_password(self):
        """获取密码"""
        return self.children['password_entry'].get ()

    def clear_username(self):
        """ 清空用户名"""
        return self.children['username_entry'].delete (0, END)

    def clear_password(self):
        """ 清空用户名"""
        return self.children['password_entry'].delete (0, END)

    def on_reset_button_click(self, command):
        """重置按钮的响应注册"""
        reset_button = self.children['button_frame'].children['reset_button']
        reset_button['command'] = command

    def on_login_button_click(self, command):
        """登录按钮的响应注册"""
        login_button = self.children['button_frame'].children['login_button']
        login_button['command'] = command  # 把command函数赋值给登录按钮的command,点击时调用command

    def on_window_close(self, command):
        """关闭窗口的响应注册"""
        self.protocol ('WM_DELETE_WINDOW', command)
  • 整体采用了grid表格的布局,其中用户名标签放置在(1,1)第一行第一列位置,对应的用户名的输入放置在(1,2),密码标签放置在(2,1),密码的输入放置在(2,2),重置和登录按钮放置在第三行居中的位置。
  • 由于我们已经全局使用了grid表格布局,所有我们将他们放在一个Frame里面,两个按钮在Frame中水平布局
    再将Frame整体放置在窗口的第三行,并占据两列。

12、客户端通讯实现

通讯模块

  1. 制作协议报头,响应数据,创建一个模块config.py
#----数据协议相关配置----
REQUEST_LOGIN = '0001' #登陆请求
REQUEST_CHAT= '0002' #聊天请求
RESPONSE_LOGIN_RESULT = '1001' #登陆结果响应
RESPONSE_CHAT= '1002' #聊天响应
DELIMITER = '|' #自定义协议数据分割符
SERVER_IP = '127.0.0.1' #服务器地址
SERVER_PORT = 8090 #服务器端口
CHARSET='utf-8'

  1. 处理服务器响应字符串的拼接,制定一个模块request_protocol.py

from config import *

class RequestProtocol (object):
    """服务器响应协议的格式字符串处理"""
    @staticmethod
    def request_login_result(username,password):
        """
            拼接登陆响应
            :param username:登陆用户名,登陆失败,该值为空字符串
            :param password:登陆密码
            :return 登陆结果相应格式字符串
        """
        return DELIMITER.join ([REQUEST_LOGIN,username, password])

    @staticmethod
    def request_chat(username, messages):
        """
        拼接聊天相应,数据格式为:“相应协议编号|聊天发送者账号|聊天信息”
        :param REQUEST_CHAT:
        :param username: 聊天内容发送者账号
        :param messages: 聊天内容
        :return: 聊天相应协议格式字符串
        """
        return DELIMITER.join ([REQUEST_CHAT, username, messages])

13、客户端业务实现

新建模块client.py

   from request_protocol import RequestProtocol
from window_login import WindowLogin
from client_socket import ClientSocket
from threading import Thread
from config import *
from tkinter.messagebox import  showinfo


class Client(object):

    def __init__(self):
        """初始化客户端资源"""
        # 初始化登陆窗口
        self.window = WindowLogin()
        self.window.on_login_button_click(self.send_login_data)
        self.window.on_reset_button_click(self.clear_inputs)

        # 创建客户端套接字
        self.conn = ClientSocket()

        # 初始化消息处理函数
        self.response_handle_funtion = {}
        self.regist(RESPONSE_LOGIN_RESULT, self.response_login_handle)
        self.regist(RESPONSE_CHAT, self.response_chat_handle)

    def regist(self, requeset_id, handle_function):
        """注册消息和消息对应的方法到字典里"""
        self.response_handle_funtion[requeset_id] = handle_function

    def startup(self):
        '''开启窗口'''
        self.conn.connect()
        Thread(target=self.response_handle).start()
        self.window.mainloop()

    def clear_inputs(self):
        """清空窗口内容"""
        self.window.clear_password()
        self.window.clear_username()

    def send_login_data(self):

        username = self.window.get_username()
        password = self.window.get_password()

        request_text = RequestProtocol.request_login_result(username, password)
        self.conn.send_data(request_text)

    def response_handle(self):
        "不断收发服务器消息"
        while True:
            recv_data = self.conn.recv_data()
            print('收到服务器消息:' + recv_data)
            response_data = self.parse_response_data(recv_data)

            # 根据事件类型,调用指定方法名
            handle_funtionn = self.response_handle_funtion[response_data['response_id']]
            if handle_funtionn:
                handle_funtionn(response_data)
    @staticmethod
    def parse_response_data(recv_data):
        '''
        登陆响应消息:1001|成功/失败|昵称|账号
        聊天响应消息:1002|发送者昵称|消息内容
        '''
        # 使用协议约定的符号来切割消息
        response_data_list = recv_data.split(DELIMITER)
        # 解析消息的各个组成部分
        response_data = {}

        response_data['response_id'] = response_data_list[0]

        if response_data['response_id'] == RESPONSE_LOGIN_RESULT:

            response_data['result'] = response_data_list[1]
            response_data['nickname'] = response_data_list[2]
            response_data['username'] = response_data_list[3]

        elif response_data['response_id'] == RESPONSE_CHAT:

            response_data['nickname'] = response_data_list[1]
            response_data['message'] = response_data_list[2]

        return response_data

    def response_chat_handle(self, response_data):
        print('接收到聊天消息~', response_data)

    def response_login_handle(self, response_data):
        result = response_data['result']
        if result !='1':
            showinfo('提示','账号或密码错误')
            return
        nickname = response_data['nickname']
        username = response_data['username']
        print('%s 的昵称为 %s ,已经登录聊天室' % (username,nickname))

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值