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 相关文章推荐
在Windows8上的搭建Python和Django环境
Jul 03 Python
利用Python绘制数据的瀑布图的教程
Apr 07 Python
Python使用Scrapy爬虫框架全站爬取图片并保存本地的实现代码
Mar 04 Python
用PyInstaller把Python代码打包成单个独立的exe可执行文件
May 26 Python
Python深拷贝与浅拷贝用法实例分析
May 05 Python
详解python编译器和解释器的区别
Jun 24 Python
Django之编辑时根据条件跳转回原页面的方法
Aug 21 Python
如何给Python代码进行加密
Jan 10 Python
利用python3筛选excel中特定的行(行值满足某个条件/行值属于某个集合)
Sep 04 Python
Django nginx配置实现过程详解
Sep 10 Python
Python中threading库实现线程锁与释放锁
May 17 Python
pytorch 实现在测试的时候启用dropout
May 27 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
《OVERLORD》第四季,终于等到你!
2020/03/02 日漫
PHP输出控制功能在简繁体转换中的应用
2006/10/09 PHP
PHP队列用法实例
2014/11/05 PHP
windows7下php开发环境搭建图文教程
2015/01/06 PHP
代码生成器 document.write()
2007/04/15 Javascript
ImageFlow可鼠标控制图片滚动
2008/01/30 Javascript
JQuery实现倒计时按钮的实现代码
2012/03/23 Javascript
javascript学习笔记(三) String 字符串类型介绍
2012/06/19 Javascript
js控制表单不能输入空格的小例子
2013/11/20 Javascript
AngularJS + Node.js + MongoDB开发的基于高德地图位置的通讯录
2015/01/02 Javascript
实例代码详解javascript实现窗口抖动及qq窗口抖动
2016/01/04 Javascript
JS运动相关知识点小结(附弹性运动示例)
2016/01/08 Javascript
基于JavaScript实现TAB标签效果
2016/01/12 Javascript
实现React单页应用的方法详解
2016/08/02 Javascript
详解angular2 控制视图的封装模式
2018/12/27 Javascript
微信小程序实现多个按钮的颜色状态转换
2019/02/15 Javascript
详解微信小程序的不同函数调用的几种方法
2019/05/08 Javascript
vue中提示$index is not defined错误的解决方式
2020/09/02 Javascript
Electron+vue从零开始打造一个本地播放器的方法示例
2020/10/27 Javascript
vant 中van-list的用法说明
2020/11/11 Javascript
关于angular 8.1使用过程中的一些记录
2020/11/25 Javascript
Bootstrap FileInput实现图片上传功能
2021/01/28 Javascript
JS相册图片抖动放大展示效果的示例代码
2021/01/29 Javascript
Ruby使用eventmachine为HTTP服务器添加文件下载功能
2016/04/20 Python
Python增量循环删除MySQL表数据的方法
2016/09/23 Python
python3实现跳一跳点击跳跃
2018/01/08 Python
Python中模块(Module)和包(Package)的区别详解
2019/08/07 Python
浅析python函数式编程
2020/09/26 Python
最新版 Windows10上安装Python 3.8.5的步骤详解
2020/11/28 Python
详解CSS3中字体平滑处理和抗锯齿渲染
2017/03/29 HTML / CSS
关于读书的活动方案
2014/08/14 职场文书
大学生毕业个人总结
2015/02/15 职场文书
财政局个人年终总结
2015/03/03 职场文书
2015军训通讯稿大全
2015/07/18 职场文书
李清照的诗词赏析(20首)
2019/08/22 职场文书
nginx请求限制配置方法
2021/07/09 Servers