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调用命令行进度条的方法
May 05 Python
python爬虫爬取淘宝商品信息(selenum+phontomjs)
Feb 24 Python
python监控文件并且发送告警邮件
Jun 21 Python
详解Django中类视图使用装饰器的方式
Aug 12 Python
python实现汉诺塔算法
Mar 01 Python
Python编程中flask的简介与简单使用
Dec 28 Python
Python定义函数功能与用法实例详解
Apr 08 Python
一步步教你用python的scrapy编写一个爬虫
Apr 17 Python
Python处理session的方法整理
Aug 29 Python
Python单链表原理与实现方法详解
Feb 22 Python
pip安装tensorflow的坑的解决
Apr 19 Python
python 实现rolling和apply函数的向下取值操作
Jun 08 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
ecshop 批量上传(加入自定义属性)
2012/03/20 PHP
PHP+ajaxfileupload+jcrop插件完美实现头像上传剪裁
2014/06/09 PHP
PHP微信开发之文本自动回复
2016/06/23 PHP
php使用 readfile() 函数设置文件大小大小的方法
2017/08/11 PHP
不使用中间变量,交换int型的 a, b两个变量的值。
2010/10/29 Javascript
xss文件页面内容读取(解决)
2010/11/28 Javascript
JavaScript中对象属性的添加和删除示例
2014/05/12 Javascript
innerHTML属性,outerHTML属性,textContent属性,innerText属性区别详解
2015/03/13 Javascript
JavaScript中getUTCMinutes()方法的使用详解
2015/06/10 Javascript
seajs模块之间依赖的加载以及模块的执行
2016/10/21 Javascript
详解使用JS如何制作简单的ASCII图与单极图
2017/03/31 Javascript
JavaScript中发出HTTP请求最常用的方法
2018/07/12 Javascript
vue监听用户输入和点击功能
2019/09/27 Javascript
vue使用showdown并实现代码区域高亮的示例代码
2019/10/17 Javascript
在项目vue中使用echarts的操作步骤
2020/09/07 Javascript
编写Python脚本来获取Google搜索结果的示例
2015/05/04 Python
Python自动生产表情包
2017/03/17 Python
对python .txt文件读取及数据处理方法总结
2018/04/23 Python
pyqt5实现绘制ui,列表窗口,滚动窗口显示图片的方法
2019/06/20 Python
Python编程学习之如何判断3个数的大小
2019/08/07 Python
使用Rasterio读取栅格数据的实例讲解
2019/11/26 Python
python 实现简单的FTP程序
2019/12/27 Python
python3安装OCR识别库tesserocr过程图解
2020/04/02 Python
使用Keras构造简单的CNN网络实例
2020/06/29 Python
Python直接赋值及深浅拷贝原理详解
2020/09/05 Python
CSS3 文字动画效果
2020/11/12 HTML / CSS
美国正版电视节目和电影在线观看:Hulu
2018/05/24 全球购物
德国游戏机商店:Konsolenkost
2019/12/08 全球购物
Lancer Skincare官方网站:抗衰老皮肤护理
2020/11/20 全球购物
阅兵口号
2014/06/19 职场文书
单位在职证明书
2014/09/11 职场文书
jQuery ajax - getScript() 方法和getJSON方法
2021/05/14 jQuery
浅谈Redis的几个过期策略
2021/05/27 Redis
springBoot基于webSocket实现扫码登录
2021/06/22 Java/Android
Redis中缓存穿透/击穿/雪崩问题和解决方法
2021/12/04 Redis
Python 数据可视化神器Pyecharts绘制图像练习
2022/02/28 Python