qq1
客户端
from PyQt5.QtWidgets import QApplication,QMainWindow,\ QPushButton,QPlainTextEdit,QMessageBox,QLineEdit,QTextBrowser,\ QLabel,QGridLayout,QComboBox,QGraphicsOpacityEffect,QWidget from PyQt5.QtCore import Qt from PyQt5.QtGui import QPixmap,QFont,QIcon #qtwidgets是控件的包。qapplication是提供图形界面的底层管理功能,qplaintextedit纯文本编辑框 from socket import * from touxiang_jpg import img as touxiang from backimage1_jpg import img as backimage1 from jiemian1_jpg import img as jiemian1 from backimage2_jpg import img as backimage2 from jiemian2_jpg import img as jiemian2 import os,time,random import threading import base64 serveIP='188.131.183.5' picture1 = open('touxiang.jpg', 'wb') picture1.write(base64.b64decode(touxiang)) picture2 = open('backimage1.jpg', 'wb') picture2.write(base64.b64decode(backimage1)) picture3 = open('jiemian1.jpg', 'wb') picture3.write(base64.b64decode(jiemian1)) picture4 = open('backimage2.jpg', 'wb') picture4.write(base64.b64decode(backimage2)) picture5 = open('jiemian2.jpg', 'wb') picture5.write(base64.b64decode(jiemian2)) #用那个图片的py文件去导出生成图片文件 class LoginUi(): def __init__(self): self.window = QWidget() # 将window定义为主窗口对象 self.window.setFixedSize(640, 360) self.window.resize(640, 360) # 设置窗口的像素大小 self.window.move(550, 350) # 定义窗口的起始位置 self.window.setWindowTitle('克莱比的通讯台') #设置窗口左上角的图标 icon = QIcon() icon.addPixmap(QPixmap("touxiang.jpg"), QIcon.Normal, QIcon.Off) self.window.setWindowIcon(icon) #设置透明度的变量op和op1 op=QGraphicsOpacityEffect() op.setOpacity(0.65) op1=QGraphicsOpacityEffect() op1.setOpacity(0.65) #设置背景图片 switch=random.choice(['a','b']) if switch=='a': self.image1 = QPixmap('jiemian1.jpg') if switch=='b': self.image1 = QPixmap('jiemian2.jpg') self.text1 = QLabel(self.window) self.text1.setGeometry(0, 0, 640, 360) #前两位是相对于窗口左上角的坐标,后两位是本对象所占有的像素点 self.text1.setPixmap(self.image1) self.text1.setScaledContents(True) # 设置左上角的头像图标 self.image2 = QPixmap('touxiang.jpg') self.text2 = QLabel(self.window) self.text2.setGeometry(10, 10, 113, 108) self.text2.setPixmap(self.image2) self.text2.setScaledContents(True) self.userNametextEdit = QLineEdit(self.window) # textEdit定义为window对象里面的纯文本框 self.userNametextEdit.setPlaceholderText('请输入账号') # 纯文本框里面的内置提示文本 self.userNametextEdit.resize(300, 30) #resize设置本对象的像素点 self.userNametextEdit.move(150, 100) #本对象相对窗口左上角的坐标位置 self.userNametextEdit.setAutoFillBackground(True) self.userNametextEdit.setGraphicsEffect(op) #输入用户处文本透明 self.passWtextEdit = QLineEdit(self.window) # textEdit定义为window对象里面的纯文本框 self.passWtextEdit.setPlaceholderText('请输入密码') # 纯文本框里面的内置提示文本 self.passWtextEdit.resize(300, 30) self.passWtextEdit.move(150, 150) self.passWtextEdit.setGraphicsEffect(op1) #输入用户处文本透明 self.passWtextEdit.setAutoFillBackground(True) self.loginbutton = QPushButton('登录', self.window) #登录按钮 self.loginbutton.resize(140, 30) self.loginbutton.move(150, 200) self.loginbutton.clicked.connect(self.loguihandleCalc) #登录按钮一旦被点击将会触发loguihandlecalc函数 self.state='not login' #初始的登陆状态是未登录 self.helptext= QLabel(self.window) #这一部分是设置文本超链接的模块 self.helptext.move(40,280) self.helptext.setFont(QFont("Roman times",12,QFont.Bold)) #设置字体的字形,字体大小,字体加粗 self.helptext.setText('<a href="https://www.cnblogs.com/zqh962903415/">' 'design by zqh,如果需要帮助或者想骂开发者,请点击这里</a>') #设置超链接 self.helptext.setOpenExternalLinks(True) #开启超链接 def loguihandleCalc(self): print('登录按钮被点击了') username = self.userNametextEdit.text() password = self.passWtextEdit.text() print('用户输入的账户', username) print('用户输入的密码', password) if username == 'zqh' and password == 'zqh': self.state = 'login' self.window.close() elif username == 'zqh1' and password == 'zqh1': self.state = 'login' self.window.close() elif username == 'zqh2' and password == 'zqh2': self.state = 'login' self.window.close() elif username == 'pyj' and password == 'pyj': self.state = 'login' self.window.close() else: QMessageBox.about(self.window, '账户密码不正确', '账户或者密码不正确') # 弹出信息框 def read_state(self): return self.state def read_user(self): return self.userNametextEdit.text() class mainui(): def __init__(self): self.window = QWidget() # 将window定义为主窗口对象 self.window.resize(800,700) # 设置窗口的像素大小 self.window.setWindowTitle('克莱比的通讯台') self.sendtarget = 0 self.sendFileTarget=0 #设置窗口左上角的图标 icon = QIcon() icon.addPixmap(QPixmap("touxiang.jpg"), QIcon.Normal, QIcon.Off) self.window.setWindowIcon(icon) switch=random.choice(['a','b']) if switch=='a': self.backimage = QPixmap('backimage1.jpg') if switch=='b': self.backimage = QPixmap('backimage2.jpg') self.text1 = QLabel(self.window) self.text1.setGeometry(0, 0,1920,1080) self.text1.setPixmap(self.backimage) self.text1.setScaledContents(True) grid=QGridLayout() op=QGraphicsOpacityEffect() op.setOpacity(0.5) op1=QGraphicsOpacityEffect() op1.setOpacity(0.5) self.showText = QTextBrowser(self.window) self.showText.setGraphicsEffect(op) self.showText.setAutoFillBackground(True) self.onlinemessage=QLabel("在线用户",self.window) self.sendchoice=QComboBox(self.window) self.loginmessage=QLabel("design by zqh",self.window) self.loginmessage1=QLabel("您没能连接上服务器奥",self.window) self.sendtext=QPlainTextEdit(self.window) self.sendtext.setGraphicsEffect(op1) self.sendbutton = QPushButton('发送消息',self.window) self.sendbutton1 = QPushButton('清空显示屏',self.window) self.sendbutton2 = QPushButton('发送文件',self.window) #按钮的触发事件 self.sendbutton.clicked.connect(self.sendButtonClic) self.sendbutton1.clicked.connect(self.clearScreenClic) self.sendbutton2.clicked.connect(self.sendFileButtonClic) grid.setSpacing(10) grid.addWidget(self.showText,1,0) grid.addWidget(self.onlinemessage,1,1,1,1) grid.addWidget(self.sendchoice,1,1,3,1) grid.addWidget(self.loginmessage1,2,0) grid.addWidget(self.loginmessage,2,1) grid.addWidget(self.sendtext,3,0,3,1) #占据伸缩比为5行1列 grid.addWidget(self.sendbutton,3,1,1,1) #占据比例为5行1列 grid.addWidget(self.sendbutton1, 3, 1, 2, 1) # 占据比例为5行1列 grid.addWidget(self.sendbutton2, 3, 1, 3, 1) # 占据比例为5行1列 self.window.setLayout(grid) def sendButtonClic(self): print('发送按钮被点击了') self.sendtarget=1 def sendFileButtonClic(self): print('发送文件按钮被点击了') self.sendFileTarget=1 def clearScreenClic(self): print('清空显示屏按钮被点击了') self.showText.clear() def client(): ip_port = (serveIP, 35038) devicenum = 5 buffer_size = 1024 tcp_client = socket(AF_INET, SOCK_STREAM) # 第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_client.connect(ip_port) # while 1: tcp_client.send(bytes('me online', encoding='utf-8')) #向服务端发出:我在线上 data=tcp_client.recv(buffer_size) #等待接收服务器的回应 print('服务器向在线状况器发出',data.decode('utf8')) if data.decode('utf8')=='conn_allow': #如果服务器有回应 tcp_client.send(name.encode('utf8')) #发送本客户端用户的用户名 window2.loginmessage1.setText('欢迎用户%s的登陆' % name) window2.loginmessage.setText('design by zqh') onlielist_copy = [] #建立在线人数表副本,用于防止重复向选择框加入用户名 while 1: str_onlinelist=tcp_client.recv(buffer_size) #接受字符串形式的onlinelist,里面放着其他的在线用户的用户名 onlielist=eval(str_onlinelist.decode('utf8')) #将字符串形式的onlinelist转换回列表 # print('onlielist',onlielist) # print('onlielist_copy',onlielist_copy) #____今天到这下面一句,三个关掉一个之后传过来的只剩一个在onlielist里面,接下来要制定这种特殊情况去删掉这个已经关掉的 if onlielist == ['0']: # 如果接收到的是['0'],也就是说只有本用户在线 onlielist_copy.clear() window2.sendchoice.clear() else: if onlielist != onlielist_copy: window2.sendchoice.clear() onlielist_copy.clear() for i in onlielist: #便厉onlinelist if i not in onlielist_copy: #如果那个在线用户不在在线人数表副本里就往下 window2.sendchoice.addItem(i) #将在线用户的名字放进选择框 onlielist_copy.append(i) #将在线用户的名字放进副本,这样防止选择框里多次加同样的名字 if onlielist != onlielist_copy: pass #这里是发送消息器 def msclient(): ip_port = (serveIP, 35040) devicenum = 5 buffer_size = 1024 tcp_client = socket(AF_INET, SOCK_STREAM) # 第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_client.connect(ip_port) tcp_client.send('msclient online'.encode('utf8')) # 向服务端发出:消息器在线上 data=tcp_client.recv(buffer_size) #等待服务端发来请求名字 print('服务器向消息服务发出',data.decode('utf8')) tcp_client.send(name.encode('utf8')) #发送自己的用户名 while 1: if window2.sendtarget == 1: # 发送标志位是1时进行发送。平常发送标志位都是0,只有发送消息的按钮被按下的时候才会变1 targetuser=window2.sendchoice.currentText() #检测下拉选择框的内容 if targetuser != '': #如果下拉选择框非空 Text = window2.sendtext.toPlainText() # 获取文本框内容 ms_format='我对'+targetuser+'说:'+ Text+'\n' window2.showText.append(ms_format) messagelist=[targetuser,Text] tcp_client.send(str(messagelist).encode('utf8')) #发送‘我对xxx说xxx’ window2.sendtext.clear() #然后清空输入框 window2.sendtarget = 0 #将发送标志位变成0 if targetuser == '': #如果发送标志位是空的话 print('wucaozuo') window2.sendtarget = 0 # 将发送标志位变成0 if window2.sendtarget == 0: #发送位是1时跳过 time.sleep(0.5) #这里是消息接收客户端 def msclientRec(): ip_port = (serveIP, 35042) devicenum = 5 buffer_size = 1024 tcp_client = socket(AF_INET, SOCK_STREAM) # 第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_client.connect(ip_port) tcp_client.send('msrec online'.encode('utf8')) # 向服务端发出:接受器在线 data=tcp_client.recv(buffer_size) #等待服务器的消息,服务器会发来’请求用户名' print('服务器向在接收器发出',data.decode('utf8')) tcp_client.send(name.encode('utf8')) #把自己的用户名发上客户端 while 1: ms=tcp_client.recv(buffer_size) #循环接收客户端发来的消息,然后将其放进框 ms=ms.decode('utf8') window2.showText.append(ms) def fileSend(): ip_port = (serveIP, 35044) devicenum = 5 buffer_size = 1024 tcp_client = socket(AF_INET, SOCK_STREAM) # 第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_client.connect(ip_port) tcp_client.send('filesend online'.encode('utf8')) # 向服务端发出:文件发送器在线 data = tcp_client.recv(buffer_size) # 等待服务器的消息,服务器会发来’请求用户名' print('服务器向文件服务发出', data.decode('utf8')) tcp_client.send(name.encode('utf8')) # 把自己的用户名发上客户端 while 1: while window2.sendFileTarget != 0: filepath=window2.sendtext.toPlainText() if os.path.exists(filepath): print('有这个文件') targetuser = window2.sendchoice.currentText() # 检测下拉选择框的内容 if targetuser != '': # 如果下拉选择框非空 cut = os.path.split(filepath) filename=cut[1] filesize=os.stat(filepath).st_size if filesize>5120000: window2.showText.append('文件过大,钱少服务器带宽低,发送的文件请不超过5mb') window2.sendtext.clear() # 然后清空输入框 else: #发送文件操作全在这里 filelist=[] filelist=[targetuser,filename,filesize,name] window2.sendtext.clear() # 然后清空输入框 tcp_client.send(str(filelist).encode('utf8')) #发送文件信息序列 reply=tcp_client.recv(buffer_size) #接收服务器端的回应 print(reply.decode('utf8')) f = open(filepath, 'rb') # 打开本地的那个文件,用二进制来读取 has_send=0 window2.showText.append('正在开始进行文件传输') while has_send < filesize: data1 = f.read(1024) # 用二进制读出来然后进行发送 tcp_client.send(data1) has_send = has_send + len(data1) f.close() window2.showText.append('文件传输成功') print('传输成功') window2.sendFileTarget = 0 if targetuser == '': # 如果发送标志位是空的话 print('没选中人,无操作') window2.sendFileTarget = 0 else: window2.showText.append('路径有误 该路径下并没有相应的文件') window2.sendtext.clear() # 然后清空输入框 window2.sendFileTarget = 0 else: time.sleep(0.2) continue def fileRec(): ip_port = (serveIP, 35046) devicenum = 5 buffer_size = 1024 tcp_client = socket(AF_INET, SOCK_STREAM) # 第一个参数代表基于网络通信,第二个参数代表基于tcp协议 tcp_client.connect(ip_port) tcp_client.send('fileRec online'.encode('utf8')) # 向服务端发出:文件发送器在线 data = tcp_client.recv(buffer_size) # 等待服务器的消息,服务器会发来’请求用户名' print('服务器向文件接收器发出', data.decode('utf8')) tcp_client.send(name.encode('utf8')) # 把自己的用户名发上客户端 while 1: filelist=tcp_client.recv(buffer_size) filelist_res=eval(filelist.decode('utf8')) filename=filelist_res[0] filesize = filelist_res[1] origin_user=filelist_res[2] window2.showText.append('%s正在向你传输文件%s,请耐心等待' %(origin_user,filename)) f = open(os.path.join(os.getcwd(), filename), 'wb') has_receive = 0 while has_receive < filesize: # 当已经接收到的字节数小于标识里的文件长度时 data1 = tcp_client.recv(1024) # 不断进行接收,一次1024就能收掉一个字节的数据 f.write(data1) # 将接收到的写入 has_receive = has_receive + len(data1) f.close() window2.showText.append('文件传输成功,接收到的文件在与本程序同一个文件夹内') print('传输成功') app = QApplication([]) window1=LoginUi() window1.window.show() # 展示框界面. app.exec_() # 进入底层程序死循环 readback=window1.read_state() name=window1.read_user() print(readback,name) if readback == 'login': app1 = QApplication([]) window2 =mainui() filsend_sev=threading.Thread(target=fileSend, args=()) filsend_sev.daemon=1 filsend_sev.start() filsend_Rec=threading.Thread(target=fileRec, args=()) filsend_Rec.daemon=1 filsend_Rec.start() show_online_people = threading.Thread(target=client, args=()) show_online_people.daemon=1 ms_server = threading.Thread(target=msclient, args=()) ms_server.daemon=1 msrec_server = threading.Thread(target=msclientRec, args=()) msrec_server.daemon=1 ms_server.start() show_online_people.start() msrec_server.start() window2.window.show() app1.exec_() # 进入底层程序死循环 picture1.close() picture2.close() picture3.close() picture4.close() picture5.close() os.remove(os.path.join(os.getcwd(), 'touxiang.jpg')) os.remove(os.path.join(os.getcwd(), 'jiemian1.jpg')) os.remove(os.path.join(os.getcwd(), 'backimage1.jpg')) os.remove(os.path.join(os.getcwd(), 'jiemian2.jpg')) os.remove(os.path.join(os.getcwd(), 'backimage2.jpg'))
服务端
import socketserver from socket import * import time,os import threading buffer_size=1024 online_people=[] ms_online_people={} ms_rigerster=[] file_rigerster=[] serveIP='127.0.0.1' class Myserver(socketserver.BaseRequestHandler): def handle(self): print('检测在线状况服务器接入:',self.request) print('检测在线状况服务器地址:', self.client_address) try: msg = self.request.recv(buffer_size) # 接收上线的客户端的消息 print('客户端发来的消息是', msg.decode('utf8')) # if not msg: break # 这里用于如果客户端强行断开不断发空就跳出 if msg.decode('utf8') == 'me online': self.request.send('conn_allow'.encode('utf-8')) # 发送允许客户端连线 username = self.request.recv(buffer_size) online_people.append({username.decode('utf8'): self.client_address}) #将所有在线的人放进online_people列表 onlinelist=[] #onlinelist放置的是除了本用户以外其他在线用户的名字 while 1: # print('onlinelist',onlinelist) # print('online_people',online_people) if len(online_people)>=len(onlinelist)+1: #当在线总人数列表(包含自己)>=在线总人数列表时 # print('zheli') pass #肯定为保持状态或者新增上线人口,直接过 if len(online_people)<len(onlinelist)+1: #当在线总人数列表(包含自己)<在线总人数列表时 print('有人下线') #说明肯定有人下线 for people in onlinelist: ret=[] for person in online_people: ret.append(list(person.keys())[0]) #在ret列表里放置了在线总人数的所有用户名 if people not in ret: #如果onlinelist的某个人没有在ret里,说明他下线了,把他从onlinelist踢出去 onlinelist.remove(people) #以下为主要部分,循环发送onlinelist(除了本用户以外其他在线用户的名字)来让客户端确定谁在线谁离线 if len(online_people) >= 2: # 当在线人数大于2人时 for i in online_people: # 便利online_people列表 if list(i.keys())[0] != username.decode( 'utf8'): # online_people的细化单元是字典{名字:ip},找出里面不是当前用户的名字 onlinelist.append(list(i.keys())[0]) # 将那些在线的并且不是本用户的名字放进onlinelist onlinelist = list(set(onlinelist)) # 将onlinelist去重 # print('zhengque') self.request.send(str(onlinelist).encode('utf-8')) # 将onlielist(其他在线用户的用户名)发送给客户端 time.sleep(2) else: self.request.send(str(['0']).encode('utf-8')) # 如果在线人数只有用户自己,则发送['0'] time.sleep(2) except Exception as e: print('%s已经断开' %username.decode('utf8')) online_people.remove({username.decode('utf8'): self.client_address}) print('将此用户移除后的在线人数列表',online_people) def set_message_serv(): class MessageServer(socketserver.BaseRequestHandler): def handle(self): time.sleep(0.2) print('有消息服务接入:',self.request) print('消息服务地址:', self.client_address) try: msg = self.request.recv(buffer_size) # 接收上线的客户端的消息 print('客户端发来的消息是',msg.decode('utf8')) self.request.send('request username'.encode('utf8')) name = self.request.recv(buffer_size) name=name.decode('utf8') print(name) ms_online_people.update({name:self.client_address}) print(ms_online_people) while 1: messagelist = self.request.recv(buffer_size) messagelist = eval(messagelist.decode('utf8')) #转换回消息列表[对谁说,说什么] # if messagelist == [] or messagelist=='': # continue # print(messagelist,type(messagelist)) time.sleep(0.5) format=name+'对你说: '+messagelist[1] +'\n' print(format) ms_rigerster.append([messagelist[0],format]) print(ms_rigerster) except Exception as e: pass ms=socketserver.ThreadingTCPServer((serveIP, 35040),MessageServer) #threading是多线程 #myserver是通信循环 ms.serve_forever() def set_message_rec(): class MessageServer1(socketserver.BaseRequestHandler): def handle(self): time.sleep(0.4) print('有接收服务接入:', self.request) print('接收服务地址:', self.client_address) data=self.request.recv(buffer_size) print('客户端发来的消息是',data.decode('utf8')) self.request.send('requir name'.encode('utf8')) name = self.request.recv(buffer_size) name=name.decode('utf8') print(name) while 1: if ms_rigerster!=[]: for ms in ms_rigerster: if ms[0] == name: self.request.send(ms[1].encode('utf8')) ms_rigerster.remove(ms) else: pass time.sleep(0.4) pass msrec = socketserver.ThreadingTCPServer((serveIP, 35042), MessageServer1) # threading是多线程 # myserver是通信循环 msrec.serve_forever() def set_fil_server(): class fileServer(socketserver.BaseRequestHandler): def handle(self): time.sleep(0.6) print('有文件服务接入:', self.request) print('文件服务地址:', self.client_address) data = self.request.recv(buffer_size) print('客户端发来的消息是', data.decode('utf8')) self.request.send('requir name'.encode('utf8')) name = self.request.recv(buffer_size) #接收客户端发来的客户端的名字 name = name.decode('utf8') while 1: filelist = self.request.recv(buffer_size) #接收发过来的文件信息序列[发送给的目标用户,文件名,文件长度,发件人] filelist_res=eval(filelist.decode('utf8')) #将二进制的文件信息序列恢复成列表状态 filename=filelist_res[1]#提取出文件的名字信息 filesize=filelist_res[2] #提取出文件的长度信息 print(filelist_res) self.request.send('file trans can begin'.encode('utf8')) #向对方发出可以进行文件传输的信号 f = open(os.path.join(os.getcwd(),filename), 'wb') has_receive=0 while has_receive < filesize: # 当已经接收到的字节数小于标识里的文件长度时 data1 = self.request.recv(1024) # 不断进行接收,一次1024就能收掉一个字节的数据 f.write(data1) # 将接收到的写入 has_receive = has_receive + len(data1) f.close() if filelist_res not in file_rigerster: file_rigerster.append(filelist_res) print('当前的待传输列表是', file_rigerster) fil = socketserver.ThreadingTCPServer((serveIP, 35044), fileServer) # threading是多线程 # myserver是通信循环 fil.serve_forever() def set_fil_recv(): class fileRecServer(socketserver.BaseRequestHandler): def handle(self): time.sleep(0.8) print('有文件接收器接入:', self.request) print('文件接收器地址:', self.client_address) data = self.request.recv(buffer_size) print('客户端发来的消息是', data.decode('utf8')) self.request.send('requir name'.encode('utf8')) name = self.request.recv(buffer_size) name = name.decode('utf8') while 1: if file_rigerster !=[]: for i in file_rigerster: if i[0] == name: print('开始向目标用户发文件') filename = i[1] # 提取出文件的名字信息 filesize = i[2] # 提取出文件的长度信息 origin_user=i[3] filelist=[filename,filesize,origin_user] self.request.send(str(filelist).encode('utf8')) f = open(os.path.join(os.getcwd(),filename), 'rb') # 打开本地的那个文件,用二进制来读取 has_send = 0 while has_send < filesize: data1 = f.read(1024) # 用二进制读出来然后进行发送 self.request.send(data1) has_send = has_send + len(data1) f.close() print('传输成功') file_rigerster.remove(i) #从服务器端的文件寄存器中删掉这条发送指令,防止重复发送 os.remove(os.path.join(os.getcwd(),filename)) else: time.sleep(0.2) continue fil = socketserver.ThreadingTCPServer((serveIP, 35046), fileRecServer) # threading是多线程 # myserver是通信循环 fil.serve_forever() if __name__=='__main__': file_Recv=threading.Thread(target=set_fil_recv,args=()) file_Recv.start() file_server=threading.Thread(target=set_fil_server,args=()) file_server.start() ms_server = threading.Thread(target=set_message_serv, args=()) ms_server.start() ms_rec = threading.Thread(target=set_message_rec, args=()) ms_rec.start() s=socketserver.ThreadingTCPServer((serveIP, 35038),Myserver) #threading是多线程 s.serve_forever() #链接循环
https://files.cnblogs.com/files/zqh962903415/克莱比的通讯台.rar

浙公网安备 33010602011771号