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基于smtplib实现异步发送邮件服务
May 28 Python
Python的Asyncore异步Socket模块及实现端口转发的例子
Jun 14 Python
Python简单实现Base64编码和解码的方法
Apr 29 Python
Python探索之创建二叉树
Oct 25 Python
对python中的 os.mkdir和os.mkdirs详解
Oct 16 Python
Python文件读写常见用法总结
Feb 22 Python
Python3打包exe代码2种方法实例解析
Feb 17 Python
python中tab键是什么意思
Jun 18 Python
基于python判断字符串括号是否闭合{}[]()
Sep 21 Python
如何用PyPy让你的Python代码运行得更快
Dec 02 Python
Python try except else使用详解
Jan 12 Python
Flask中jinja2的继承实现方法及实例
Mar 03 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
require(),include(),require_once()和include_once()的异同
2007/01/02 PHP
php表单请求获得数据求和示例
2014/05/15 PHP
PHP实现获取图片颜色值的方法
2014/07/11 PHP
老生常谈PHP面向对象之解释器模式
2017/05/17 PHP
PHP使用Session实现上传进度功能详解
2019/08/06 PHP
javascript检测浏览器flash版本的实现代码
2011/12/06 Javascript
禁用页面部分JavaScript方法的具体实现
2013/07/31 Javascript
jquery.autocomplete修改实现键盘上下键自动填充示例
2013/11/19 Javascript
javascript动态添加、修改、删除对象的属性与方法详解
2014/01/27 Javascript
window.print打印指定div指定网页指定区域的方法
2014/08/04 Javascript
客户端验证用户名和密码的方法详解
2016/06/16 Javascript
Angular.js中$apply()和$digest()的深入理解
2016/10/13 Javascript
浅谈webpack 自动刷新与解析
2018/04/09 Javascript
超好用的jQuery分页插件jpaginate用法示例【附源码下载】
2018/12/06 jQuery
初试vue-cli使用HBuilderx打包app的坑
2019/07/17 Javascript
vue中的v-if和v-show的区别详解
2019/09/01 Javascript
原生javascript实现类似vue的数据绑定功能示例【观察者模式】
2020/02/24 Javascript
小程序自定义圆形进度条
2020/11/17 Javascript
python调用fortran模块
2016/04/08 Python
Windows下的Jupyter Notebook 安装与自定义启动(图文详解)
2018/02/21 Python
python+opencv实现摄像头调用的方法
2019/06/22 Python
python3使用print打印带颜色的字符串代码实例
2019/08/22 Python
树莓派安装OpenCV3完整过程的实现
2019/10/10 Python
pandas实现excel中的数据透视表和Vlookup函数功能代码
2020/02/14 Python
使用Django xadmin 实现修改时间选择器为不可输入状态
2020/03/30 Python
Keras 快速解决OOM超内存的问题
2020/06/11 Python
python与idea的集成的实现
2020/11/20 Python
英国男女奢华内衣和泳装购物网站:Figleaves
2017/01/28 全球购物
美国领先的水果篮送货公司和新鲜水果供应商:The Fruit Company
2018/02/13 全球购物
医学生实习自我鉴定
2013/09/27 职场文书
财务学生的职业生涯发展
2014/02/11 职场文书
2015年医生个人工作总结
2015/04/25 职场文书
用Python爬取某乎手机APP数据
2021/06/15 Python
解决vue中provide inject的响应式监听
2022/04/19 Vue.js
高通2023 年将发布高性能PC处理器
2022/04/29 数码科技
SQL Server2019安装的详细步骤实战记录(亲测可用)
2022/06/10 SQL Server