在服务器端使用了字典来储存连接信息配对表。当两个人的配对表互相相同时配对成功,并通知连接成功。
视频功能只能运行在两台不同的电脑上,不然会出现视频端口被占用的问题!
接收文件、消息、视频内容均开了多线程,避免了干扰。

连接成功后,就将连接信息存入字典。

 '''连接成功后将连接信息添加到各个字典中'''self.selfID = selfIDself.SessionManege.messageConnTable[selfID] = self.messageConnself.SessionManege.fileConnTable[selfID] = self.fileConnself.SessionManege.videoConnTable[selfID] = self.videoConnself.SessionManege.pairTable[selfID] = targetID

cv2获取的图片使用下面代码转二进制流,不能 "tobytes()" 直接转二进制流,不然无法编码。

                byte_stream = cv2.imencode('.jpg', img)[1]

使用

                img =  cv2.imdecode(np.fromstring(byte_stream,np.uint8),cv2.IMREAD_COLOR)

再解码

直接上代码。
服务器端

import socket
import os
import hashlib
import threading,time
import jsonclass SessionManege(threading.Thread):messageConnTable = {}fileConnTable = {}videoConnTable = {}pairTable = {}def newSession(self, messageConn, fileConn,videoConn):chat_Session = MessageSession(messageConn, fileConn,videoConn,self)chat_Session.start()def close_messageConn(self,userID):self.messageConnTable.pop(userID)self.fileConnTable.pop(userID)self.videoConnTable.pop(userID)self.pairTable.pop(userID)print(userID,"连接关闭")class MessageSession(threading.Thread):def __init__(self, messageConn, fileConn, videoConn, SessionManege):super(MessageSession, self).__init__()self.messageConn = messageConnself.fileConn = fileConnself.videoConn = videoConnself.SessionManege = SessionManegedef pairTest(self,selfID,targetID):if selfID in self.SessionManege.messageConnTable:self.messageConn.send(json.dumps({'type': 'systemMassage','info': "用户名重复!"}).encode("utf-8"))return'''连接成功后将连接信息添加到各个字典中'''self.selfID = selfIDself.SessionManege.messageConnTable[selfID] = self.messageConnself.SessionManege.fileConnTable[selfID] = self.fileConnself.SessionManege.videoConnTable[selfID] = self.videoConnself.SessionManege.pairTable[selfID] = targetID'''返回信息'''if(self.SessionManege.messageConnTable.get(targetID)):self.targetmessageConn = self.SessionManege.messageConnTable.get(targetID)self.messageConn.send(json.dumps({'type': 'pairTestResult','success': True,}).encode("utf-8"))self.targetmessageConn.send(json.dumps({'type': 'pairTestResult','success': True,}).encode("utf-8"))return Trueelse :self.messageConn.send(json.dumps({'type': 'pairTestResult','success': False,}).encode("utf-8"))return Falsedef msgHandle(self,msg):data = json.loads(msg)if data['type'] == "Message":  #连接成功后从messageConnTable中获取targetID的messageConn        targetmessageConn = self.SessionManege.messageConnTable.get(data['targetID'])targetmessageConn.send(json.dumps({'type': 'Message','content': data['content'],}).encode("utf-8") )if data['type'] == "FileTransfer": #文件传输targetmessageConn = self.SessionManege.messageConnTable.get(data['targetID'])targetmessageConn.send(json.dumps({'type': 'FileTransfer',}).encode("utf-8") )fileTransfer = FileTransfer(data['selfID'],data['targetID'],self.SessionManege)fileTransfer.start()if data['type'] == "videoChat": #视频聊天targetmessageConn = self.SessionManege.messageConnTable.get(data['targetID'])targetmessageConn.send(json.dumps({'type': 'videoChat',}).encode("utf-8") )videoTransfer = VideoTransfer(data['selfID'],data['targetID'],self.SessionManege)if data['type'] == "PairTest":self.pairTest(data['selfID'],data['targetID'])def run(self):try:while True:msg = self.messageConn.recv(1024).decode('utf-8')if not msg:break   else :self.msgHandle(msg)except socket.error as e:print(e.args)passfinally:targetID = self.SessionManege.pairTable.get(self.selfID)targetmessageConn = self.SessionManege.messageConnTable.get(targetID)self.SessionManege.close_messageConn(self.selfID)targetmessageConn.send(json.dumps({'type': 'pairInterruption','Info': "对方中断退出会话",}).encode("utf-8"))self.messageConn.close()class FileTransfer(threading.Thread):def __init__(self, sendID, receiveID, SessionManege):super(FileTransfer, self).__init__()self.sendConn = SessionManege.fileConnTable[sendID]self.receiveConn = SessionManege.fileConnTable[receiveID]self.SessionManege = SessionManegedef receiveFile(self):while True:       try:fileInfo = self.sendConn.recv(1024)self.receiveConn.send(fileInfo)  # 向接收方发文件信息fileInfo = fileInfo.decode("utf-8").split("|")filename = fileInfo[0]file_size = (int)(fileInfo[1])# 2.接收文件内容self.receiveConn.recv(1024)self.sendConn.send("ready".encode("utf-8"))  # 向发送方回复就绪信号received_size = 0while received_size < file_size:size = 0  if file_size - received_size > 1024: # 每次只接收 1024size = 1024else:  # 最后一次接收size = file_size - received_sizedata = self.sendConn.recv(size)  #多次接收内容data_len = len(data)received_size += data_lenself.receiveConn.send(data)  # 向接收方转发文件except socket.error as e:print(e.args)def run(self):self.receiveFile()class VideoTransfer(threading.Thread):def __init__(self, sendID, receiveID, SessionManege):super(VideoTransfer, self).__init__()self.sendConn = SessionManege.videoConnTable[sendID]self.receiveConn = SessionManege.videoConnTable[receiveID]threading.Thread(target=self.receiveVideo,args=(self.sendConn,self.receiveConn)).start()self.receiveConn = SessionManege.videoConnTable[sendID]self.sendConn = SessionManege.videoConnTable[receiveID]threading.Thread(target=self.receiveVideo,args=(self.sendConn,self.receiveConn)).start()def receiveVideo(self,sendConn,receiveConn):while True:       try:image = sendConn.recv(1300000)receiveConn.sendall(image)except socket.error as e:print(e.args)if __name__ == '__main__':ip_port = "127.0.0.1"massage_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)massage_server.bind((ip_port, 8000))massage_server.listen(20)  file_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)file_server.bind((ip_port, 8001))file_server.listen(20) video_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)video_server.bind((ip_port, 8002))video_server.listen(20) sessionManege = SessionManege()print("监听开始..")try:while True:messageConn, addr = massage_server.accept()  # 等待连接fileConn, addr = file_server.accept()  # 等待连接videoConn, addr = video_server.accept()  # 等待连接# 利用handler来管理线程,实现线程之间的socket的相互通信sessionManege.newSession(messageConn, fileConn,videoConn)except socket.error:pass

客户端:

import os,io,socket,json,cv2,threading,time
import numpy as np
import tkinter as tk
import tkinter.scrolledtext as tst
from tkinter.messagebox import *
from tkinter.filedialog import *
from tkinter.simpledialog import *
from PIL import Image,ImageTkclass Application(tk.Frame):#定义GUI应用程序类,派生于Frame类def __init__(self, master,sessionManege):  #构造函数,master为父窗口tk.Frame.__init__(self, master)#调用父类的构造函数self.root = masterself.createWidgets()self.sessionManege = sessionManegeself.clientReceiveThread = ClientReceiveThread(self.sessionManege.message_conn,self)self.clientReceiveThread.start()def createWidgets(self):tk.Label(self.root,text="本人ID:",width=6).place(x=1,y=1)self.selfID = tk.Entry(self.root,width=20)self.selfID.place(x=80,y =1)tk.Label(self.root,text="对方ID:",width=6).place(x=240,y=1)self.targetID = tk.Entry(self.root,width=20)self.targetID.place(x=300,y =1)self.IDSubmit = tk.Button(self.root,text='连通测试',width = 8,command=self.pairTest).place(x=450,y=1)self.chatRecord = tst.ScrolledText(self.root, width=80, height=20)#创建Text组件self.chatRecord.place(x=1,y=30)self.sendBtn = tk.Button(root,text="发送文件",width=8,command=self.sendFile)self.sendBtn.place(x=1,y=300)self.sendBtn = tk.Button(root,text="视频聊天",width=8,command = self.videoCharApply)self.sendBtn.place(x=100 ,y=300)self.chatMessage = tst.ScrolledText(self.root, width=80, height=10)#创建Text组件self.chatMessage.place(x=1,y=340)self.sendBtn = tk.Button(root,text="发送",width=8,command=self.sendMessage)self.sendBtn.place(x=500,y=480)def pairTest(self):     #进行配对测试selfID = self.selfID.get()targetID = self.targetID.get()self.sessionManege.testPair(selfID,targetID)def pairCheck(self):    #检查是否已经成功建立连接if self.sessionManege.piarState == False:tk.messagebox.showwarning("警告:",'您还未建立可靠连接!')return Truedef sendMessage(self): #发送消息if self.pairCheck():returncontent = self.chatMessage.get(1.0, tk.END).strip()  if  content =="":returnself.sessionManege.sendMessage(content,self.selfID.get(),self.targetID.get())self.chatMessage.delete(1.0,tk.END)Message = "己方:\n"+content+"\n\n"self.chatRecord.insert("insert", Message)self.chatRecord.see(END)def sendFile(self):     #发送文件if self.pairCheck():returnfilePath = tk.filedialog.askopenfilename(filetypes=[('文本文件','.txt'),('所有文件','.*')])Message = "己方:\n 发送文件"+filePath+"\n\n"self.chatRecord.insert("insert", Message)self.chatRecord.see(END)selfID = self.selfID.get()targetID = self.targetID.get()jsDict = {'type': 'FileTransfer','selfID': selfID,'targetID':targetID}js = json.dumps(jsDict)self.sessionManege.message_conn.sendall( bytes(js,'utf-8'))threading.Thread(target=self.sendFileThread,args=(filePath,)).start()def sendFileThread(self,filePath): #文件发送的线程sendResult = self.sessionManege.sendFile(filePath)def receiveFile(self):threading.Thread(target=self.receiveFileThread,args=()).start()def receiveFileThread(self):filePath = self.sessionManege.receiveFile()fileName = os.path.basename(filePath)Message = "通知:\n 已成功接受文件"+fileName+",存放在D:\Receice Files\n\n"self.chatRecord.insert("insert", Message)self.chatRecord.see(END)def videoCharApply(self):if self.pairCheck():returnMessage = "己方:\n 发送视频通话请求\n\n"self.chatRecord.insert("insert", Message)self.chatRecord.see(END)selfID = self.selfID.get()targetID = self.targetID.get()jsDict = {'type': 'videoChat','selfID': selfID,'targetID':targetID}js = json.dumps(jsDict)self.sessionManege.message_conn.sendall( bytes(js,'utf-8'))self.videoChat()def videoChat(self):   top = Toplevel()   #创建Application的对象实例top.title("视频聊天:")top1 = videoFrame(top,self.sessionManege)class videoFrame():#定义GUI应用程序类,派生于Frame类def __init__(self,toplevel,sessionManege):  #构造函数,master为父窗口self.top = toplevelself.createWidgets()self.video_conn = sessionManege.video_connself.camera = cv2.VideoCapture(0)    #摄像头threading.Thread(target=self.sendVideo,args=(self.video_conn,)).start() threading.Thread(target=self.receiveVideo,args=(self.video_conn,)).start() self.top.protocol("WM_DELETE_WINDOW", self.s_destroy)def createWidgets(self):self.panel = Label(self.top)  # initialize image panelself.panel.pack(padx=10, pady=10)self.top.config(cursor="arrow")def s_destroy(self):self.camera.release()cv2.destroyAllWindows()self.top.destroy()def receiveVideo(self,video_conn): while True:try:byte_stream = video_conn.recv(1300000) #1228800img =  cv2.imdecode(np.fromstring(byte_stream,np.uint8),cv2.IMREAD_COLOR) print(type(img))cv2image = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA)#转换颜色从BGR到RGBAprint(type(cv2image))current_image = Image.fromarray(cv2image)#将图像转换成Image对象               imgtk = ImageTk.PhotoImage(image=current_image)self.panel.imgtk = imgtkself.panel.config(image=imgtk)except cv2.error as e:print(e.args)continuedef sendVideo(self,video_conn): while True:try:success, img = self.camera.read()  # 从摄像头读取照片cv2.waitKey(10)byte_stream = cv2.imencode('.jpg', img)[1]#这里可以获取一下byte_stream的长度,然后在服务器端口的image = sendConn.recv(1300000)设置大小video_conn.sendall(byte_stream)  # 发送数据         except socket.error as e:print(e.args)continue
class SessionManege:message_conn = socket.socket(socket.AF_INET,socket.SOCK_STREAM)file_conn = socket.socket(socket.AF_INET,socket.SOCK_STREAM)video_conn = socket.socket(socket.AF_INET,socket.SOCK_STREAM)piarState = False def __init__(self):ip_port = "127.0.0.1"message_port = (ip_port, 8000)file_port = (ip_port, 8001)video_port = (ip_port, 8002)self.message_conn.connect(message_port)  self.file_conn.connect(file_port)  self.video_conn.connect(video_port)  def testPair(self,selfID,targetID):jsDict = {'type': 'PairTest','selfID': selfID,'targetID':targetID}js = json.dumps(jsDict)self.message_conn.sendall( bytes(js,'utf-8'))def sendMessage(self,content,selfID,targetID):jsDict = {'type': 'Message','content': content,'selfID':selfID,'targetID':targetID}js = json.dumps(jsDict)self.message_conn.sendall( bytes(js,'utf-8'))def sendFile(self,filePath):size = os.stat(filePath).st_size  #获取文件大小fileName = os.path.basename(filePath)fileInfo = fileName +"|"+str(size)self.file_conn.send(fileInfo.encode("utf-8")) # 2.发送文件内容self.file_conn.recv(1024)  # 接收确认f = open(filePath, "rb")has_sent = 0while has_sent!= size :data = f.read(1024)self.file_conn.sendall(data)  # 发送数据has_sent+=len(data)f.close()def receiveFile(self):server_response = self.file_conn.recv(1024)fileInfo = server_response.decode("utf-8").split("|")filename = fileInfo[0]file_size = (int)(fileInfo[1])# 2.接收文件内容self.file_conn.send("ready".encode("utf-8"))  # 回复就绪信号filePath = "D:\\Receice Files\\"+ filename f = open(filePath, "wb")received_size = 0while received_size < file_size:size = 0  if file_size - received_size > 1024: # 每次只接收 1024size = 1024else:  # 最后一次接收size = file_size - received_sizedata = self.file_conn.recv(size)  #多次接收内容data_len = len(data)received_size += data_lenf.write(data)f.close()return filenameclass ClientReceiveThread(threading.Thread):def __init__(self,message_conn,application):super(ClientReceiveThread, self).__init__()self.message_conn = message_connself.application = applicationdef run(self):self.receive_msg()def receive_msg(self):while True:msg = self.message_conn.recv(1024).decode('utf-8')if not msg:breakjs = json.loads(msg)self.msgHandle(js)def msgHandle(self,js):if js["type"] == "Message":Message = "对方:\n"+js["content"]+"\n\n"self.application.chatRecord.insert("insert", Message)if js["type"] == "FileTransfer":self.application.receiveFile()if js["type"] == "videoChat":message = "对方打开视频通讯:\n"self.application.chatRecord.insert("insert",message)self.application.videoChat()if js["type"] == "pairTestResult":if(js["success"]):self.application.sessionManege.piarState = Trueself.application.chatRecord.insert("insert", "系统消息:连接成功,可以开始聊天!\n")else :self.application.chatRecord.insert("insert", "系统消息:正在等待对方上线......\n")if js["type"] == "pairInterruption":self.application.sessionManege.pairState = Falseself.application.chatRecord.insert("insert", "系统消息:对方已中断连接.....\n")if js["type"] == "systemMassage":message = "系统消息:"+js["info"]+"\n"self.application.chatRecord.insert("insert",message)self.application.chatRecord.see(END)if __name__ == "__main__":root = tk.Tk()                 #创建1个Tk根窗口组件rootroot.title('实时通信')     #设置窗口标题   sw = root.winfo_screenwidth()sh = root.winfo_screenheight()ww = 600wh = 510x = (sw-ww) / 2y = (sh-wh) / 2root.geometry("%dx%d+%d+%d" %(ww,wh,x,y))sessionManege = SessionManege()app = Application(root,sessionManege)   #创建Application的对象实例app.mainloop()                #调用组件的mainloop方法,进入事件循环

使用python开发多人一对一聊天系统(文字聊天,视频通讯,文件传输)相关推荐

  1. 用免费开发的华为近距离通信能力,打造优质文件传输体验

    点击视频查看,近距离通信服务在文件传输场景中的应用 颠覆传统的文件传输能力 日常生活中,有时会遇到需要跟朋友传递.分享几百M或者几个G大文件的场景,传统的方式有几种: 1.拷贝到电脑,然后再拷贝给手机 ...

  2. Python命令行创建http服务器,局域网内的文件传输好助手

    python拥有创建http服务器的包,一个命令即可创建一个http server 服务器 但是python2与python3的命令稍有不同 1.python2 使用 python -m Simple ...

  3. python tcp黏包和struct模块解决方法,大文件传输方法及MD5校验

    https://www.cnblogs.com/zaizai1573/p/10230973.html 一.TCP协议 粘包现象 和解决方案 黏包现象 让我们基于tcp先制作一个远程执行命令的程序(命令 ...

  4. 基于python 开发 微信机器人自动回复 app

    基于python 开发 微信机器人自动回复 app # coding:utf-8 __author__ = "zhou" # create by zhou on 2020/3/3 ...

  5. 当程序员的一个人无聊时,甚至用Python开发出机器人看他们聊天

    当程序员的一个人独孤的时候,甚至可以用Python开发出两个机器人看他们聊天 当你无聊的时候,可能会刷一下手机看一下新闻,看看电视剧,发发呆. 但是当程序员无聊起来的时候,甚至可以用Python开发两 ...

  6. python开发的游戏手机上玩_利用Python开发游戏脚本,就凭一个设定,玩家直接起飞!...

    前言 最近在玩儿公主连结,之前也玩儿过阴阳师这样的游戏,这样的游戏都会有个初始号这样的东西,或者说是可以肝的东西. 当然,作为一名程序员,肝这种东西完全可以用写代码的方式帮我们自动完成.游戏脚本其实并 ...

  7. 电脑向linux板卡传文件,ARM 开发板嵌入式linux系统与主机PC通过串口传输文件

    ARM 开发板嵌入式linux系统与主机PC通过串口传输文件 本来以为按以下两篇文章就可以几步轻松搞定这个问题,没想到遇到两个小麻烦: 1,我用的xp虚拟机下redhat9.0做主机,按照下面第一篇文 ...

  8. Python妙用:使用一行代码下载视频

    "如何用一行Python代码下载<后浪>等全网视频" 01 基于Python开发 是的,这款下载工具包是基于Python开发的,实际它不只支持视频下载,还支持图片.音乐 ...

  9. tftpd32、虚拟机、PC机、开发板之间的文件传输

    问题:如何在电脑虚拟机上的Linux C程序下载到开发板呢? 首先,虚拟机上安装Linux系统 Linux上的操作有: 编辑好Hello.c源程序 接着编译,因为最后是要在开发板执行程序,所以使用编译 ...

  10. 一对一聊天系统开发直播源码搭建方便你我他

    你还在热衷观看直播或者从事直播吗?你了解的直播方式有多少种呢?一对多的直播市场让你感到麻木了吗?直播行业如火如荼,一对多显然不再是领导直播市场的佼佼者,那么直播行业的未来是什么呢?我们可以听业内人士讲 ...

最新文章

  1. yii2手动添加图片处理插件Imagine
  2. mysql桥梁表_以JDBC为桥梁入门MySQL数据库基础
  3. BZOJ4543 POI2014 Hotel加强版 【长链剖分】【DP】*
  4. (三)CSS【不多说了,前端面试 CSS 是必考知识,不过关直接回家】
  5. 相互引用的初始化过程
  6. 计算机组成原理整机实验报告,计算机组成原理加器实验报告.doc
  7. PowerDesigner中列表显示TABLE的NAME而不是CODE
  8. 【Python3网络爬虫开发实战】3.1-使用urllib
  9. 天律的云端大数据分析挖掘之旅
  10. jq使用教程05_ 新手也能用的安装版本,30秒点选即可安装完成,不需配置Python环境
  11. 《Effective Ruby:改善Ruby程序的48条建议》一第2条:所有对象的值都可能为nil
  12. 作为面试官,我是怎么快速判断程序员能力的?
  13. ArcGIS for Android Runtime100 基本操作(四)——GPS定位
  14. GitHub微信防撤回项目 for Mac
  15. 免费的DDoS防火墙有哪些
  16. 银行卡Bin和Logo
  17. Google Chrome开发者工具-移动仿真:网络带宽控制
  18. 王禹偁:万壑有声含晚籁,数峰无语立斜阳
  19. 产品模块化设计的前世今生
  20. 如何使用星际文件传输网络(IPFS)搭建区块链服务(一)

热门文章

  1. 【长篇博文】Docker学习笔记与深度学习环境的搭建和部署(一)
  2. 802.1Q VLAN 简介
  3. Pythonic写法
  4. 如何在 IDE 中将程序打成 jar 包 Library handing 三种方式讲解 如何编写 MANIFEST.MF
  5. 京东充值系统现漏洞 被恶意盗刷
  6. 导向滤波-Guided Image Filtering
  7. 卡西欧计算器计算一元二次方正组
  8. Pandas中,使用reindex方法报错:index must be monotonic increasing or decreasing的分析
  9. 简单体验阿里巴巴在线java诊断工具Arthas
  10. 如何用matlab画超越方程组的图像,【求助】超越方程组的fsolve解法