Python实现网络聊天室的示例代码(支持多人聊天与私聊)


Posted in Python onJanuary 27, 2021

实验名称:

网络聊天室

功能:

i. 掌握利用Socket进行编程的技术
ii. 掌握多线程技术,保证双方可以同时发送
iii. 建立聊天工具
iv. 可以和单人聊天
v. 可以和多个人同时进行聊天
vi. 使用图形界面,显示双方的语录
vii. 程序可以在一定程度上进行错误识别

概述

实验通过聊天室可以完成单人或多人之间的聊天通信,功能的实现主要是通过Socket通信来实现。本次实验采用客户端/服务器(C/S)架构模式,通过Python语言来编写服务器端与客户端的程序。运用多线程可完成多点对多点的聊天。
服务器端程序主要用于接收用户信息,消息接收与转发。
客户端程序实现用户注册登录,聊天信息显示与信息输入。

代码解释

统计当前在线人数,并且将新用户加到用户列表中。
Serve.py

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

这是服务器对于聊天服务的实现。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

通过继承threading.Thread类而实现多线程,重写run函数。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

接受来自客户端的用户名,如果用户名为空,使用用户的IP与端口作为用户名。如果用户名出现重复,则在出现的用户名依此加上后缀“2”、“3”、“4”……

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

在获取用户名后便会不断地接受用户端发来的消息(即聊天内容),结束后关闭连接。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

如果用户断开连接,将该用户从用户列表中删除,然后更新用户列表。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

将地址与数据(需发送给客户端)存入messages队列。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

服务端在接受到数据后,会对其进行一些处理然后发送给客户端,如下图,对于聊天内容,服务端直接发送给客户端,而对于用户列表,便由json.dumps处理后发送。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

Client.py
建立连接,发送用户名及判断是否为私聊消息,私聊用~识别

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

接受来自服务器发送的消息

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

对接收到的消息进行判断,如果是在线用户列表(用json.dumps处理过),便清空在线用户列表框,并将此列表输出在在线用户列表框中。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

如果是聊天内容,便将其输出在聊天内容显示框中。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

设置登录窗口

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

设置消息界面

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

设置在线用户列表。

Python实现网络聊天室的示例代码(支持多人聊天与私聊)

完整代码:
Serve.py

import socket
import threading
import queue
import json # json.dumps(some)打包  json.loads(some)解包
import os
import os.path
import sys


IP = '127.0.0.1'
PORT = 9999   # 端口
messages = queue.Queue()
users = []  # 0:userName 1:connection
lock = threading.Lock()

def onlines():  # 统计当前在线人员
  online = []
  for i in range(len(users)):
    online.append(users[i][0])
  return online

class ChatServer(threading.Thread):
  global users, que, lock

  def __init__(self):     # 构造函数
    threading.Thread.__init__(self)
    self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    os.chdir(sys.path[0])
# 接受来自客户端的用户名,如果用户名为空,使用用户的IP与端口作为用户名。如果用户名出现重复,则在出现的用户名依此加上后缀“2”、“3”、“4”……
  def receive(self, conn, addr):       # 接收消息
    user = conn.recv(1024)    # 用户名称
    user = user.decode()
    if user == '用户名不存在':
      user = addr[0] + ':' + str(addr[1])
    tag = 1
    temp = user
    for i in range(len(users)):   # 检验重名,则在重名用户后加数字
      if users[i][0] == user:
        tag = tag + 1
        user = temp + str(tag)
    users.append((user, conn))
    USERS = onlines()
    self.Load(USERS,addr)
    # 在获取用户名后便会不断地接受用户端发来的消息(即聊天内容),结束后关闭连接。
    try:
      while True:
        message = conn.recv(1024)      # 发送消息
        message = message.decode()
        message = user + ':' + message
        self.Load(message,addr)
      conn.close()
    # 如果用户断开连接,将该用户从用户列表中删除,然后更新用户列表。
    except:  
      j = 0      # 用户断开连接
      for man in users:
        if man[0] == user:
          users.pop(j)    # 服务器段删除退出的用户
          break
        j = j+1

      USERS = onlines()
      self.Load(USERS,addr)
      conn.close()

# 将地址与数据(需发送给客户端)存入messages队列。
  def Load(self, data, addr):
    lock.acquire()
    try:
      messages.put((addr, data))
    finally:
      lock.release()    

  # 服务端在接受到数据后,会对其进行一些处理然后发送给客户端,如下图,对于聊天内容,服务端直接发送给客户端,而对于用户列表,便由json.dumps处理后发送。
  def sendData(self): # 发送数据
    while True:
      if not messages.empty():
        message = messages.get()
        if isinstance(message[1], str):
          for i in range(len(users)):
            data = ' ' + message[1]
            users[i][1].send(data.encode())
            print(data)
            print('\n')

        if isinstance(message[1], list):
          data = json.dumps(message[1])
          for i in range(len(users)):
            try:
              users[i][1].send(data.encode())
            except:
              pass

  def run(self):
    self.s.bind((IP,PORT))
    self.s.listen(5)
    q = threading.Thread(target=self.sendData)
    q.start()
    while True:
      conn, addr = self.s.accept()
      t = threading.Thread(target=self.receive, args=(conn, addr))
      t.start()
    self.s.close()
if __name__ == '__main__':
  cserver = ChatServer()
cserver.start()

Client.py

import socket
import tkinter
import tkinter.messagebox
import threading
import json
import tkinter.filedialog
from tkinter.scrolledtext import ScrolledText

IP = ''
PORT = ''
user = ''
listbox1 = '' # 用于显示在线用户的列表框
show = 1 # 用于判断是开还是关闭列表框
users = [] # 在线用户列表
chat = '------Group chat-------' # 聊天对象

#登陆窗口

root0 = tkinter.Tk()
root0.geometry("300x150")
root0.title('用户登陆窗口')
root0.resizable(0,0)
one = tkinter.Label(root0,width=300,height=150,bg="LightBlue")
one.pack()

IP0 = tkinter.StringVar()
IP0.set('')
USER = tkinter.StringVar()
USER.set('')

labelIP = tkinter.Label(root0,text='IP地址',bg="LightBlue")
labelIP.place(x=20,y=20,width=100,height=40)
entryIP = tkinter.Entry(root0, width=60, textvariable=IP0)
entryIP.place(x=120,y=25,width=100,height=30)

labelUSER = tkinter.Label(root0,text='用户名',bg="LightBlue")
labelUSER.place(x=20,y=70,width=100,height=40)
entryUSER = tkinter.Entry(root0, width=60, textvariable=USER)
entryUSER.place(x=120,y=75,width=100,height=30)

def Login(*args):
	global IP, PORT, user
	IP, PORT = entryIP.get().split(':')
	user = entryUSER.get()
	if not user:
		tkinter.messagebox.showwarning('warning', message='用户名为空!')
	else:
		root0.destroy()

loginButton = tkinter.Button(root0, text ="登录", command = Login,bg="Yellow")
loginButton.place(x=135,y=110,width=40,height=25)
root0.bind('<Return>', Login)

root0.mainloop()

# 建立连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, int(PORT)))
if user:
  s.send(user.encode()) # 发送用户名
else:
  s.send('用户名不存在'.encode())
  user = IP + ':' + PORT

# 聊天窗口
root1 = tkinter.Tk()
root1.geometry("640x480")
root1.title('群聊')
root1.resizable(0,0)

# 消息界面
listbox = ScrolledText(root1)
listbox.place(x=5, y=0, width=640, height=320)
listbox.tag_config('tag1', foreground='red',backgroun="yellow")
listbox.insert(tkinter.END, '欢迎进入群聊,大家开始聊天吧!', 'tag1')

INPUT = tkinter.StringVar()
INPUT.set('')
entryIuput = tkinter.Entry(root1, width=120, textvariable=INPUT)
entryIuput.place(x=5,y=320,width=580,height=170)

# 在线用户列表
listbox1 = tkinter.Listbox(root1)
listbox1.place(x=510, y=0, width=130, height=320)


def send(*args):
	message = entryIuput.get() + '~' + user + '~' + chat
	s.send(message.encode())
	INPUT.set('')

sendButton = tkinter.Button(root1, text ="\n发\n\n\n送",anchor = 'n',command = send,font=('Helvetica', 18),bg = 'white')
sendButton.place(x=585,y=320,width=55,height=300)
root1.bind('<Return>', send)


def receive():
	global uses
	while True:
		data = s.recv(1024)
		data = data.decode()
		print(data)
		try:
			uses = json.loads(data)
			listbox1.delete(0, tkinter.END)
			listbox1.insert(tkinter.END, "当前在线用户")
			listbox1.insert(tkinter.END, "------Group chat-------")
			for x in range(len(uses)):
				listbox1.insert(tkinter.END, uses[x])
			users.append('------Group chat-------')
		except:
			data = data.split('~')
			message = data[0]
			userName = data[1]
			chatwith = data[2]
			message = '\n' + message
			if chatwith == '------Group chat-------':  # 群聊
				if userName == user:
					listbox.insert(tkinter.END, message)
				else:
					listbox.insert(tkinter.END, message)
			elif userName == user or chatwith == user: # 私聊
				if userName == user:
					listbox.tag_config('tag2', foreground='red')
					listbox.insert(tkinter.END, message, 'tag2')
				else:
					listbox.tag_config('tag3', foreground='green')
					listbox.insert(tkinter.END, message,'tag3')

			listbox.see(tkinter.END)
r = threading.Thread(target=receive)
r.start() # 开始线程接收信息

root1.mainloop()
s.close()

到此这篇关于Python实现网络聊天室的示例代码(支持多人聊天与私聊)的文章就介绍到这了,更多相关Python 网络聊天室内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python中的jquery PyQuery库使用小结
May 13 Python
Python写的创建文件夹自定义函数mkdir()
Aug 25 Python
浅谈Python的垃圾回收机制
Dec 17 Python
python+ffmpeg视频并发直播压力测试
Mar 06 Python
python smtplib发送带附件邮件小程序
May 22 Python
Python设置在shell脚本中自动补全功能的方法
Jun 25 Python
python pandas消除空值和空格以及 Nan数据替换方法
Oct 30 Python
keras 指定程序在某块卡上训练实例
Jun 22 Python
Keras: model实现固定部分layer,训练部分layer操作
Jun 28 Python
python实现过滤敏感词
May 08 Python
python数字类型和占位符详情
Mar 13 Python
Python OpenGL基本配置方式
May 20 Python
基于Python的接口自动化unittest测试框架和ddt数据驱动详解
Jan 27 #Python
python实现scrapy爬虫每天定时抓取数据的示例代码
Jan 27 #Python
使用bandit对目标python代码进行安全函数扫描的案例分析
Jan 27 #Python
用Python实现定时备份Mongodb数据并上传到FTP服务器
Jan 27 #Python
python re.match()用法相关示例
Jan 27 #Python
selenium+python实现基本自动化测试的示例代码
Jan 27 #Python
Python开发.exe小工具的详细步骤
Jan 27 #Python
You might like
PHP无敌近乎加密方式!
2010/07/17 PHP
thinkPHP通用控制器实现方法示例
2017/11/23 PHP
php设计模式之迭代器模式实例分析【星际争霸游戏案例】
2020/04/07 PHP
从新浪弄下来的全屏广告代码 与使用说明
2007/03/15 Javascript
jquery的Theme和Theme Switcher使用小结
2010/09/08 Javascript
jquery淡化版banner异步图片文字效果切换图片特效
2014/04/08 Javascript
js定时调用方法成功后并停止调用示例
2014/04/08 Javascript
js判断复选框是否选中及选中个数的实现代码
2016/05/30 Javascript
jQuery的each循环用法简单示例
2016/06/12 Javascript
js中获取键盘按下键值event.keyCode、event.charCode和event.which的兼容性详解
2017/03/15 Javascript
JS使用贪心算法解决找零问题示例
2017/11/27 Javascript
vue模仿网易云音乐的单页面应用
2019/04/24 Javascript
解决vue语法会有延迟加载显现{{xxx}}的问题
2019/11/14 Javascript
jQuery实现视频展示效果
2020/05/30 jQuery
关于IDEA中的.VUE文件报错 Export declarations are not supported by current JavaScript version
2020/10/17 Javascript
[47:21]Liquid vs TNC Supermajor 胜者组 BO3 第一场 6.4
2018/06/05 DOTA
python线程池(threadpool)模块使用笔记详解
2017/11/17 Python
python进行TCP端口扫描的实现
2018/12/21 Python
提升Python效率之使用循环机制代替递归函数
2019/07/23 Python
详解PyQt5中textBrowser显示print语句输出的简单方法
2020/08/07 Python
Python图像处理之膨胀与腐蚀的操作
2021/02/07 Python
python re模块常见用法例举
2021/03/01 Python
python绘制汉诺塔
2021/03/01 Python
纯CSS3发光分享按钮的实现教程
2014/09/06 HTML / CSS
使用HTML5的链接预取功能(link prefetching)给网站提速
2012/12/13 HTML / CSS
街头时尚在线:JESSICABUURMAN
2019/06/16 全球购物
JPA的优势都有哪些
2013/07/04 面试题
就业意向书
2014/07/29 职场文书
员工生日活动方案
2014/08/24 职场文书
初级党校心得体会
2014/09/11 职场文书
2015年试用期自我评价范文
2015/03/10 职场文书
2016应届毕业生自荐信范文
2016/01/28 职场文书
四年级语文教学反思
2016/03/03 职场文书
如何写好开幕词?
2019/06/24 职场文书
导游词之太湖
2019/10/08 职场文书
python实现简单的三子棋游戏
2022/04/28 Python