本文是在实验楼-Pyhon实现文字聊天室的功能基础上进行的拓展功能开发

具体增加功能如下:

1.增加对指定用户发送消息功能

2.增加不同的frame框来分别显示发送和接收的消息

3.增加msg窗口来显示系统提示消息,如上下线消息,在线用户消息

4.使用panel改写设计客户端的控件展示

5.聊天窗口的title增加显示当前的用户名称

主要修改代码为客户端代码,服务器代码修改略少。

client.py客户端代码如下:

import wx
import telnetlib
from time import sleep
import _thread as threadclass LoginFrame(wx.Frame):"""登录窗口"""def __init__(self, parent, id, title, size):        # 初始化,添加控件并绑定事件wx.Frame.__init__(self, parent, id, title)self.SetSize(size)#设置窗口尺寸大小self.Center()#设置登录弹窗在桌面中心           #使用尺寸器改写,改写后拉大或者缩小窗口,中间的控件会随着窗口的大小已固定的尺寸而改变panel=wx.Panel(self)#创建一个面板,self表示实例即LoginFrame#定义panel中的控件self.serverAddressLabel = wx.StaticText(panel,label="Server Address")self.userNameLabel = wx.StaticText(panel,label="UserName")self.serverAddress = wx.TextCtrl(panel)self.userName = wx.TextCtrl(panel)self.loginButton = wx.Button(panel,label='Login')#定义一个横向的box1self.box1=wx.BoxSizer()#添加box1中的元素self.box1.Add(self.serverAddressLabel, proportion=5, flag=wx.EXPAND | wx.ALL,border=5)#该元素占box1的比例为50%,方式为伸缩,边界为5self.box1.Add(self.serverAddress, proportion=5,flag=wx.EXPAND | wx.ALL,border=5)#定义一个横向的box2self.box2=wx.BoxSizer()#添加box2中的元素self.box2.Add(self.userNameLabel, proportion=5,flag=wx.EXPAND | wx.ALL,border=5)self.box2.Add(self.userName, proportion=5,flag=wx.EXPAND | wx.ALL,border=5)#定义一个纵向的v_boxself.v_box=wx.BoxSizer(wx.VERTICAL)#添加v_box中的元素self.v_box.Add(self.box1, proportion=3,flag=wx.EXPAND | wx.ALL,border=5)#添加box1,比例为3self.v_box.Add(self.box2, proportion=3,flag=wx.EXPAND | wx.ALL,border=5)#添加box2,比例为3self.v_box.Add(self.loginButton, proportion=2,flag=wx.EXPAND | wx.ALL,border=30)#添加登录按钮,比例为3panel.SetSizer(self.v_box)        # 绑定登录方法self.loginButton.Bind(wx.EVT_BUTTON, self.login)self.Show()#显示以上控件def login(self, event):# 登录处理try:serverAddress = self.serverAddress.GetLineText(0).split(':')#获取serverAddress处的值并以:做为分隔符con.open(serverAddress[0], port=int(serverAddress[1]), timeout=10)#open方法连接主机response = con.read_some()#接收服务端返回的数据if response != b'Connect Success':self.showDialog('Error', 'Connect Fail!', (200, 100))returncon.write(('login ' + str(self.userName.GetLineText(0)) + '\n').encode("utf-8"))#通过write写给服务器端loginname=str(self.userName.GetLineText(0))#获取登录用户名称
#             print(loginname)response = con.read_some()if response == b'UserName Empty':self.showDialog('Error', 'UserName Empty!', (200, 100))elif response == b'UserName Exist':self.showDialog('Error', 'UserName Exist!', (200, 100))else:self.Close()ChatFrame(None, 2, title='ShiYanLou Chat Client - '+loginname, size=(500, 400))except Exception:self.showDialog('Error', 'Connect Fail!', (200, 150))def showDialog(self, title, content, size):# 显示错误信息对话框dialog = wx.Dialog(self, title=title, size=size)dialog.Center()wx.StaticText(dialog, label=content)dialog.ShowModal()#showModal() 方法用于显示对话窗口class ChatFrame(wx.Frame):"""聊天窗口"""def __init__(self, parent, id, title, size):# 初始化,添加控件并绑定事件wx.Frame.__init__(self, parent, id, title)self.Title=title#'ShiYanLou Chat Client - '+self.loginnameself.SetSize(780,500)#设置对话框的大小self.Center()#设置弹窗在屏幕中间#使用尺寸器改写,改写后拉大或者缩小窗口,中间的控件会随着窗口的大小已固定的尺寸而改变panel=wx.Panel(self)#创建一个面板,self表示实例即ChatFrame#定义panel中的控件self.receiveLabel = wx.StaticText(panel,label="Receive Msg")self.sendLabel = wx.StaticText(panel,label="Send Msg")self.noticeLabel = wx.StaticText(panel,label="Notice")self.chatFrame1 = wx.TextCtrl(panel,style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_LEFT)self.chatFrame2 = wx.TextCtrl(panel,style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RIGHT)self.noticeFrame = wx.TextCtrl(panel,style=wx.TE_MULTILINE | wx.TE_READONLY )self.message = wx.TextCtrl(panel,value='input message')#设置发送消息的文本输入框的位置和尺寸self.toUser=wx.TextCtrl(panel,value='input username')#设置指定用户的文本输入框的位置和尺寸self.sendButton = wx.Button(panel, label="Send")self.sendDesignButton = wx.Button(panel, label="SendDesign")  self.closeButton = wx.Button(panel, label="Close")self.usersButton = wx.Button(panel, label="Online")#定义横向的box1self.box1=wx.BoxSizer()#添加box1中的元素self.box1.Add(self.receiveLabel, proportion=4, flag=wx.EXPAND | wx.ALL,border=5)#该元素占box1的比例为40%,方式为伸缩,边界为5self.box1.Add(self.sendLabel, proportion=4,flag=wx.EXPAND | wx.ALL,border=5)self.box1.Add(self.noticeLabel, proportion=2,flag=wx.EXPAND | wx.ALL,border=5)#定义横向的box2self.box2=wx.BoxSizer()#添加box2中的元素self.box2.Add(self.chatFrame1, proportion=4,flag=wx.EXPAND | wx.ALL,border=5)self.box2.Add(self.chatFrame2, proportion=4,flag=wx.EXPAND | wx.ALL,border=5)self.box2.Add(self.noticeFrame, proportion=2,flag=wx.EXPAND | wx.ALL,border=5)#定义横向的box3self.box3=wx.BoxSizer()#添加box3中的元素self.box3.Add(self.message, proportion=6, flag=wx.EXPAND | wx.ALL,border=5)self.box3.Add(self.sendButton, proportion=2,flag=wx.EXPAND | wx.ALL,border=5)self.box3.Add(self.usersButton, proportion=2,flag=wx.EXPAND | wx.ALL,border=5)#定义横向的box4self.box4=wx.BoxSizer()#添加box4中的元素self.box4.Add(self.toUser, proportion=6, flag=wx.EXPAND | wx.ALL,border=5)self.box4.Add(self.sendDesignButton, proportion=2,flag=wx.EXPAND | wx.ALL,border=5)self.box4.Add(self.closeButton, proportion=2,flag=wx.EXPAND | wx.ALL,border=5)#定义一个纵向的v_boxself.v_box=wx.BoxSizer(wx.VERTICAL)#添加v_box中的元素self.v_box.Add(self.box1, proportion=1,flag=wx.EXPAND | wx.ALL,border=5)#添加box1,比例为1self.v_box.Add(self.box2, proportion=7,flag=wx.EXPAND | wx.ALL,border=5)#添加box2,比例为7self.v_box.Add(self.box3, proportion=1,flag=wx.EXPAND | wx.ALL,border=5)#添加box3,比例为1self.v_box.Add(self.box4, proportion=1,flag=wx.EXPAND | wx.ALL,border=5)#添加box4,比例为1panel.SetSizer(self.v_box) # 发送按钮绑定发送消息方法  self.sendButton.Bind(wx.EVT_BUTTON, self.send)#发送指定人按钮绑定方法self.sendDesignButton.Bind(wx.EVT_BUTTON,self.sendDesign)       # Users按钮绑定获取在线用户数量方法self.usersButton.Bind(wx.EVT_BUTTON, self.lookUsers)# 关闭按钮绑定关闭方法self.closeButton.Bind(wx.EVT_BUTTON, self.close)#文本框绑定点击则清除文本内容的方法thread.start_new_thread(self.receive, ())#新增一个线程来处理接收服务器消息                              self.Show()def send(self, event):#群发消息message = str(self.message.GetLineText(0)).strip()if message != '':con.write(('say ' + message + '\n').encode("utf-8"))#通过write写给服务器端self.message.Clear()def sendDesign(self, event):#给指定用户发送消息message = str(self.message.GetLineText(0)).strip()username=str(self.toUser.GetLineText(0)).strip()if message != '' and username!='':con.write(('DesignSay ' + message + ' '+username+'\n').encode("utf-8"))#通过write写给服务器端self.message.Clear()    self.toUser.Clear()             def lookUsers(self, event):# 查看当前在线用户con.write(b'look\n')def close(self, event):# 关闭窗口con.write(b'logout\n')con.close()#Close the connectionself.Close()def receive(self):# 接受服务器的消息title1=self.Title.strip().split('-',1)#去掉Title的左右空格后将Title按照-符号分隔开,获取到登录用户名loginname=title1[1].strip()+':'#去掉登录名的左右空格,加上:符号,确保是该用户发送的消息while True:sleep(0.6)result = con.read_very_eager()#不断接收来自服务器的消息                                                                  commandList=['Online Users','entered','left']#系统通知消息的指令  for com in commandList:if com in str(result):self.noticeFrame.AppendText(result)#将通知消息显示在noticeFrame中breakelse:if loginname in str(result) or 'Username not exist' in str(result):#如果用户登录名在服务器发送的消息中可以查找到,即代表是本人发送的消息self.chatFrame2.AppendText(result)#将聊天消息显示在本人的聊天窗口chatFrame2中else:self.chatFrame1.AppendText(result)#否则将消息显示在别人消息的聊天窗口chatFrame1中if __name__ == '__main__':app = wx.App()#实例化一个主循环#聊天协议基于文本,和服务器之间的通信将基于 telnetlib模块实现#连接主机----两种方法,#一种是在实例化时传入ip地址连接主机(con = telnetlib.Telnet(host_ip,port=23))#第二种是,先不传参数进行实例化再用open方法连接主机con = telnetlib.Telnet()#实例化一个telnet连接主机LoginFrame(None, -1, title="Login", size=(320, 250))#id为-1表示主窗口app.MainLoop()#启动主循环

server.py客户端代码如下:

#-*-coding:utf-8-*-
import asynchat
import asyncore# 定义端口
PORT = 6666# 定义结束异常类
class EndSession(Exception):passclass ChatServer(asyncore.dispatcher):#dispatcher是asyncore中一个socket框架,为socket添加一些通用的回调方法"""聊天服务器"""def __init__(self, port):asyncore.dispatcher.__init__(self)# 创建socketself.create_socket()# 设置 socket 为可重用self.set_reuse_addr()# 监听端口self.bind(('', port))self.listen(5)self.users = {}#初始化用户self.main_room = ChatRoom(self)#定义聊天室def handle_accept(self):conn, addr = self.accept()#accept()会等待并返回一个客户端的连接ChatSession(self, conn)class ChatSession(asynchat.async_chat):#负责和客户端通信def __init__(self,server,sock):
#         print(server,sock)#server:<__main__.ChatServer listening :6666 at 0x2994860>#sock:<socket.socket fd=204, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6666), raddr=('127.0.0.1', 52148)>asynchat.async_chat.__init__(self, sock)self.server=serverself.set_terminator(b'\n')#定义终止符self.data=[]self.name=Noneself.enter(LoginRoom(server))def enter(self,room):#从当前房间移除自身,然后添加到指定房间try:cur=self.roomexcept AttributeError:#该错误是python找不到对应的对象的属性passelse:cur.remove(self)#如果try内的语句正常执行,接着执行else里的语句self.room=roomroom.add(self)def collect_incoming_data(self, data):#接收客户端的数据self.data.append(data.decode("utf-8"))def found_terminator(self):#当客户端的一条数据结束时的处理line=''.join(self.data)self.data=[]try:self.room.handle(self,line.encode("utf-8"))#退出聊天室的处理except EndSession:self.handle_close()def handle_close(self):#当session关闭时,将进入logoutRoomasynchat.async_chat.handle_close(self) self.enter(LogoutRoom(self.server))  class CommandHandler:#命令处理类def unknown(self,session,cmd):#响应未知命令#通过aynchat.async_chat.push方法发送消息session.push(('Unknown command {} \n'.format(cmd)).encode('utf-8'))def handle(self,session,line):line=line.decode()
#         print(line)#命令处理if not line.strip():#如果line去掉左右空格后为空returnparts=line.split(' ',1)#以空格为分隔符,分隔成两个cmd=parts[0]try:line=parts[1].strip()except IndexError:line=''#通过协议代码执行相应的方法method=getattr(self,'do_'+cmd,None)#getattr()函数用于返回一个对象属性值。class A(object):bar = 1 >>>a = A(),getattr(a, 'bar')# 获取属性 bar值=1
#         print(method)try:method(session,line)#跳转到对应的方法,如do_look,do_sayexcept TypeError:self.unknown(session, cmd)class Room(CommandHandler):#包含多个用户的环境,负责基本的命令处理和广播def __init__(self,server):self.server=serverself.sessions=[]def add(self,session):#一个用户进入房间self.sessions.append(session)def remove(self,session):#一个用户离开房间self.sessions.remove(session)def broadcast(self,line):#向所有用户发送指定消息#使用asynchat.async_chat.push方法发送数据for session in self.sessions:session.push(line)def sendDesignMsg(self,msg,sendpeople,topeople):#对指定用户发送消息print(sendpeople,topeople,self.sessions,self.server.users)if topeople in self.server.users:session1=self.server.users[sendpeople]#获取发信人的sessionsession2=self.server.users[topeople]#获取收信人的sessionsession1.push(msg)#发信人和收信人的聊天页面均显示消息session2.push(msg)else:session=self.server.users[sendpeople]session.push(b'Username not exist\n')def do_logout(self,session,line):#退出房间raise EndSessionclass LoginRoom(Room):#处理登录用户def add(self,session):#用户连接成功的回应Room.add(self, session)#使用asynchat.async_chat.push方法发送数据'''Python3的字符串的编码语言用的是unicode编码,由于Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干字节,如果要在网络上传输,或保存在磁盘上就需要把str变成以字节为单位的bytespython对bytes类型的数据用带b前缀的单引号或双引号表示:'''session.push(b'Connect Success')def do_login(self,session,line):#用户登录逻辑name=line.strip()#获取用户名称if not name:session.push(b'UserName Empty')#检查是否是同名用户elif name in self.server.users:session.push(b'UserName Exist')else:session.name=namesession.enter(self.server.main_room)class LogoutRoom(Room):#处理退出用户def add(self,session):#从服务器中移除try:del self.server.users[session.name]except KeyError:passclass ChatRoom(Room):#聊天用的房间def add(self,session):#广播新用户进来session.push(b'Login Success')self.broadcast((session.name+' has entered the room.\n').encode('utf-8'))self.server.users[session.name]=sessionRoom.add(self, session)        def remove(self,session):#广播用户离开Room.remove(self, session)self.broadcast((session.name+' has left the room.\n').encode('utf-8'))def do_say(self,session,line):#发送消息self.broadcast((session.name+':'+line+'\n').encode('utf-8'))def do_DesignSay(self,session,line):#发送消息给指定的用户words=line.split('&',1)#以&为分隔符,分隔成两个,发送的消息和指定收信人的姓名msg=words[0]#获取发送消息内容topeople=words[1]#获取收信人名称sendpeople=session.name#获取发信人的名称self.sendDesignMsg((session.name+':'+msg+'\n').encode('utf-8'),sendpeople,topeople)def do_look(self,session,line):#查看在线用户session.push(b'Online Users:\n')for other in self.sessions:session.push((other.name+'\n').encode('utf-8'))if __name__=='__main__':s=ChatServer(PORT)try:print("chat serve run at '127.0.0.1:{0}'".format(PORT))asyncore.loop()except KeyboardInterrupt:print('chat server exit')

完成后就可以运行程序进行聊天了,注意需要先启动服务器再启动客户端。

这个项目中使用了 asyncore 的 dispatcher 来实现服务器,asynchat 的 asyn_chat 来维护用户的连接会话,用 wxPython 来实现图形界面,用 telnetlib 来连接服务器,在子线程中接收服务器发来的消息,由此一个简单的聊天室程序就完成了。
聊天页面如下图:

Python 实现文字聊天室-功能拓展相关推荐

  1. python远程聊天_python实现简单聊天室功能 可以私聊

    本文实例为大家分享了python实现简单聊天室功能的具体代码,供大家参考,具体内容如下 公共模块 首先写一个公共类,用字典的形式对数据的收发,并且进行封装,导入struct解决了TCP的粘包问题,并在 ...

  2. python udp 直播_[Python] socket发送UDP广播实现聊天室功能

    原博文 2018-11-24 12:33 − 一.说明 本文主要使用socket.socket发送UDP广播来实现聊天室功能. 重点难点:理解UDP通讯流程.多线程.UDP广播收发等. 测试环境:Wi ...

  3. 基于python的聊天室_Python实现文字聊天室

    你是否想过用所学的Python开发一个图形界面的聊天室程序啊? 像这样的: image 如果你想开发这样一个有点怀旧风格的聊天程序,那么可以接着看: 要开发这个聊天程序,你需要具备以下知识点: asy ...

  4. python聊天室源代码_Python实现文字聊天室

    你是否想过用所学的Python开发一个图形界面的聊天室程序啊? 像这样的: 如果你想开发这样一个有点怀旧风格的聊天程序,那么可以接着看: 要开发这个聊天程序,你需要具备以下知识点: asyncore ...

  5. APP开发者如何来实现视频聊天室功能

    这是一个新型的互联网业态,直播社交业务所带来的"钱景"正吸引越来越多的玩家进入这一行业.无论是专注秀场直播的YY,网易BoBo,还是提供手机直播的爆款应用Meerkat.在2015 ...

  6. 基于python实现的聊天室(客户端:一)窗口设置

    前言 就是自己想用python做一个聊天室,然后看看socket库,websocket库,有点底层,然后也会用到协程的东西,不是很明白,一时间也不知道怎么写,因为前面使用过了flask-socketi ...

  7. Python实现网络聊天室(支持多人聊天与私聊)

    实验名称: 网络聊天室 功能: i. 掌握利用Socket进行编程的技术 ii. 掌握多线程技术,保证双方可以同时发送 iii. 建立聊天工具 iv. 可以和单人聊天 v. 可以和多个人同时进行聊天 ...

  8. 原生JavaScript+WebSocket+nodejs实现聊天室功能

    码字不易,有帮助的同学希望能关注一下我的微信公众号:Code程序人生,感谢!代码自用自取. WebSocket也是前端非常重要的技术栈. 现在各种网站.App.小程序都伴有即时通信的功能.WebSoc ...

  9. 从头搭建一个基于 Python 的在线聊天室

    本场 Chat,是基于 Python + Redis + Flask 来搭建一个简单易用的在线聊天室.完全从零开始,一步一步完成整个项目. 主要分享内容: Flask 项目结构 Python Redi ...

  10. Python实现web聊天室

    使用Python模块中的select模块实现web聊天室功能 select模块 Python中的select模块专注于I/O多路复用,提供了select  poll  epoll三个方法(其中后两个在 ...

最新文章

  1. 网络编程试卷选择解析
  2. Linux系统下Oracle11g r1的安装之四: 开始安装Oracle
  3. Oracle 日志原理剖析
  4. 入门Web前端有哪些误区?该如何避免?
  5. 回调函数与DOM事件
  6. Angular sort recursive的实现原理
  7. bootstrap mysql源码_Django+Bootstrap+Mysql 搭建个人博客 (六)
  8. Sublime Text 3 设置
  9. Dungeon Master 地下城大师(BFS进阶)
  10. 区位码、国标码、机内码的区别和内在机制
  11. 解决word或wps删除空白页后页面布局变乱
  12. 摄像头各参数的意义_详解:监控摄像头参数介绍说明 | 58监控网
  13. ubuntu安装docker + 配置国内源和加速器
  14. wps在线浏览 java_java实现word转pdf在线预览(前端使用PDF.js;后端使用openoffice、aspose)...
  15. Android 磁场传感器 地磁倾角计算 SensorManager.getInclination方法
  16. 教师直播平台对比分析
  17. Activiti核心API
  18. 特斯拉2021年自动驾驶,特斯拉自动驾驶技术专利
  19. 微信聊天机器人-存储好友分享消息
  20. 【内网学习笔记】20、Hashcat 的使用

热门文章

  1. BUUCTF misc 喵喵喵
  2. 《认知与设计——理解UI设计准则》系列笔记目录
  3. c++文件的读取和写入
  4. 手机测试wifi的延迟的软件,六款最佳、免费的网络延迟测试工具
  5. 美国市场数据分析初创公司Simon Data获2000万美元融资
  6. 从一个帝国的消逝,看商业组织的进化
  7. NLP - 词法分析
  8. 计算机第四章文字处理软件应用课后答案,计算机应用基础第四章文字处理软件.doc...
  9. 【beef工具-01】神器beef的安装与简介
  10. 大脑信息编码_编码人大脑的5大小吃