python网络编程QQ小程序

最近应课程要求,设计一个基于Python的网络程序,所实现的功能为:聊天、发送文件。

服务器运行截图:

 客户端运行截图: 

客户端代码: 

# -*- coding: utf-8 -*-
 
from tkinter import *
import socket
import threading 
import time

from tkinter.filedialog import askopenfilename


#===========================================================================
# 子界面类
class Window:
    def __init__(self,sub_page,resulttext):
        self.resulttext = resulttext
        self.sub_page=sub_page
        self.sub_page.title("正在聊天")
        self.sub_page.geometry('940x700')
        self.sub_page.resizable(width=False, height=False)  # 宽不可变, 高可变,默认为True
        self.label_text = Label(sub_page,text="聊天记录",  font=('楷体', 14)).place(x=0, y=10)

        self.text = Text(sub_page , height=20, width=59,   font=("楷体", 18))
        self.text.place(x=0, y=35)

        self.clean_Button = Button(sub_page,text ="清除聊天记录",default='active',command =self.qingchu,width=10,height=1).place(x=630,y=510) #定义按钮按下去就调用函数    
        self.label_send = Label(sub_page,text="发送消息处",font=('楷体', 14)).place(x=0, y=520)

        self.entrySend = Text(sub_page, height=5, width=51,font=('楷体', 20))
        self.entrySend.place(x=0, y=550)

        self.send_Button = Button(sub_page,text ="发送",default='active',command = self.send_mail,width=8,height=1).place(x=650,y=660) #定义按钮按下去就调用函数    
        self.shutdown_Button = Button(sub_page,text ="退出",default='active',command = self.shout_down,width=8,height=1).place(x=570,y=660) #定义按钮按下去就调用函数    

        self.label_log = Label(sub_page,text="发送本地文件处",font=('宋体', 20)).place(x=730, y=0)
        self.label_add = Label(sub_page,text="本地文件地址:",font=('宋体', 16)).place(x=750, y=50)

        self.file_add  = Text(sub_page , height=2, width=30, font=("楷体",10))
        self.file_add.place(x=720, y=80)

        self.send_choose = Button(sub_page,text ="本地文件选择",default='active',command = self.choicefile,width=12,height=1).place(x=780,y=120) #定义按钮按下去就调用函数    
        self.send_Document = Button(sub_page,text ="上传",default='active',command = self.shangchuan,width=6,height=2).place(x=800,y=160) #定义按钮按下去就调用函数    

        self.photo_1 = PhotoImage(file="QQxiu.png")
        self.image2_label = Label(sub_page,image= self.photo_1).place(x=710,y=220)
        
    def listen(self):
        self.ctr=control(self.edit)
        self.ctr.setDaemon(True)
        self.ctr.start()
    def close(self):
        self.ctr.stop()
        
    def qingchu(self):    #清除聊天记录
        self.text.delete(1.0,END)
        
    def send_mail(self): 
        self.resulttext = self.entrySend.get(0.0,END)
        self.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n'+'我:' + self.resulttext + '\n')
        self.entrySend.delete('0.0', END)
        tcp_socket.send(("0"+self.resulttext).encode()) #前面+0是为了说明发送的是文本而非文件

    def shout_down(self): # 销毁页面        
        sub_page.withdraw()
        root.update()
        root.deiconify()
        
    def shangchuan(self):
        self.filename = self.path.split("/")[-1]
        with open(self.path, 'r',encoding='UTF-8') as f:            
            tcp_socket.send(("1"+self.filename+"$$"+f.read()).encode()) #前面+1是为了说明发送的是文件而非文本
            self.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n' + "发送文件:"+self.filename+ '\n')

    def choicefile(self):        
        self.path = askopenfilename()
        self.file_add.insert(1.0,self.path)
    def jieshou(self):
        self.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n'+'他:' + self.resulttext + '\n')

#==========================================================================
def jieshou():#接受服务端发送数据
    while True:
        file_name = tcp_socket.recv(4096)
        rev = file_name.decode()
        print("接受到:")
        print(rev)
        if rev[0]=="0":
            window.resulttext = rev[1:]#此处修改实例变量的值,resulttext为聊天记录框的字符
            window.jieshou()#显示接收的消息            
        elif rev[0]=="1":           
            name =rev[1:].split("$$")[0]
            with open(name,'w')as file:
                file.write(rev[len(name)+3:])
            file.close()
            window.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n' + "接收到文件:"+name+ '\n')
            
def lianjie():   #登录连接
    IP = ipentry.get()
    PORT = int(portentry.get())
    ADDR = (IP,PORT)  
    try:
        tcp_socket.connect(ADDR)
        sub_page.deiconify()
        root.withdraw()
        t1 = threading.Thread(target=jieshou )
        t1.start()
    except Exception as error:
        print(error)    #打印网络连接错误类型

      
#=====================================================================================================
#主界面
root = Tk() #设定底板
root.geometry("320x300")
root.title("用户端APP")
root.resizable(width=False, height=False)  # 宽不可变, 高可变,默认为True

ip = StringVar()
ip.set("127.0.0.1")
lianjie_state = StringVar()
lianjie_state.set("请连接网络")
port = IntVar()
port.set("8888")
global fileurl1
fileurl1 = StringVar()
global resulttext
resulttext = str()  


photo = PhotoImage(file="QQ1.png")
image_label = Label(root,compound='center',image= photo).place(x=120,y=10)

iplabel = Label(root, text="输入ip:",font="Helvetica -15 bold").place(x=60,y=130)
ipentry = Entry(root,textvariable=ip,width=15)
ipentry.place(x=120,y=130)

portlabel = Label(root,text="输入端口:",font="Helvetica -15 bold").place(x=40,y=160) #文字标签字体
portentry = Entry(root, textvariable=port,width=15) #输入框内容和值 宽度
portentry.place(x=120,y=160)

ok = Button(root,text ="连接",default='active',command = lianjie,width=8,height=2).place(x=60,y=200) #定义按钮按下去就调用函数    
quitscan= Button(root,text="退出", default='active',command=quit, width=8,height=2,bg = 'red').place(x=200,y=200)
####################################################################################################################################
# 用窗口类创建子页面
sub_page=Toplevel()
sub_page.withdraw()
window = Window(sub_page,resulttext) # 入口参数为(页面底板,以及传送套接字符)

global tcp_socket
tcp_socket =socket.socket(socket.AF_INET,socket.SOCK_STREAM) 

# 页面循环
sub_page.mainloop()        
root.mainloop()
####################################################################################################################################

服务器代码:

# -*- coding: utf-8 -*-
 
from tkinter import *
from socketserver import BaseRequestHandler,ThreadingTCPServer
import threading 
import time
import socket
from tkinter.scrolledtext import ScrolledText
from tkinter.filedialog import askopenfilename

def start():
    page.deiconify()
    root.withdraw()
    
def connect():
    IP = ipentry.get()
    PORT = int(portentry.get())
    ADDR = (IP,PORT)
    tcp_socket.bind(ADDR)
    tcp_socket.listen(10)
    global client_socket
    client_socket,client_addr = tcp_socket.accept()
    while True:
        # 利用accept获取分套接字以及客户端的地址
        
        # 接收客户端的数据
        file_name = client_socket.recv(4096)
        rev=file_name.decode()
        if rev[0]=="0":
            window.resulttext = rev[1:]#此处修改实例变量的值,resulttext为聊天记录框的字符
            window.jieshou()#显示接收的消息
        elif rev[0]=="1":
            name =rev[1:].split("$$")[0]
            with open(name,'w')as file:
                file.write(rev[len(name)+3:])
            file.close()
            window.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n' + "接收到文件:"+name+ '\n')
#===========================================================================
# 子界面类
class Window:
    def __init__(self,sub_page,resulttext):
        self.resulttext = resulttext
        self.sub_page=sub_page
        self.sub_page.title("正在聊天")
        self.sub_page.geometry('940x700')
        self.sub_page.resizable(width=False, height=False)  # 宽不可变, 高可变,默认为True
        
        self.label_text = Label(sub_page,text="聊天记录",  font=('楷体', 14)).place(x=0, y=10)

        self.text = Text(sub_page , height=20, width=59,   font=("楷体", 18))
        self.text.place(x=0, y=35)

        self.clean_Button = Button(sub_page,text ="清除聊天记录",default='active',command =self.qingchu,width=10,height=1).place(x=630,y=510) #定义按钮按下去就调清除聊天记录用函数    
        self.label_send = Label(sub_page,text="发送消息处",font=('楷体', 14)).place(x=0, y=520)

        self.entrySend = Text(sub_page, height=5, width=51,font=('楷体', 20))
        self.entrySend.place(x=0, y=550)

        self.send_Button = Button(sub_page,text ="发送",default='active',command = self.send_mail,width=8,height=1).place(x=650,y=660) #定义按钮按下去就调用发送函数    
        self.shutdown_Button = Button(sub_page,text ="退出",default='active',command = self.shout_down,width=8,height=1).place(x=570,y=660) #定义按钮按下去就调用退出函数    

        self.label_log = Label(sub_page,text="发送本地文件处",font=('宋体', 20)).place(x=730, y=0)
        self.label_add = Label(sub_page,text="本地文件地址:",font=('宋体', 16)).place(x=750, y=50)

        self.file_add  = Text(sub_page , height=2, width=30, font=("楷体",10))
        self.file_add.place(x=720, y=80)

        self.send_choose = Button(sub_page,text ="本地文件选择",default='active',command = self.choicefile,width=12,height=1).place(x=780,y=120) #定义按钮按下去就调本地文件选择用函数    
        self.send_Document = Button(sub_page,text ="上传",default='active',command = self.shangchuan,width=6,height=2).place(x=800,y=160) #定义按钮按下去就调用上传文件函数    

        self.photo_1 = PhotoImage(file="QQxiu1.png")  #加载QQ秀图片
        self.image2_label = Label(sub_page,image= self.photo_1).place(x=710,y=220)

    def listen(self):
        self.ctr=control(self.edit)
        self.ctr.setDaemon(True)
        self.ctr.start()
    def close(self):
        self.ctr.stop()
    def qingchu(self):    #清除聊天记录
        self.text.delete(1.0,END)

    def send_mail(self): 
        self.resulttext = self.entrySend.get(0.0,END)
        self.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n'+'我:' + self.resulttext + '\n')
        self.entrySend.delete('0.0', END)
        client_socket.send(("0"+self.resulttext).encode()) #前面+0是为了说明发送的是文本而非文件

    def shout_down(self):   # 退出函数,作用销毁子聊天页面        
        self.sub_page.destroy()
    def shangchuan(self):
        self.filename = self.path.split("/")[-1]
        with open(self.path, 'r',encoding="utf-8") as f:            
            client_socket.send(("1"+self.filename+"$$"+f.read()).encode()) #前面+1是为了说明发送的是文件而非文本
            self.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n' + "发送文件:"+self.filename+ '\n')

    def choicefile(self):        
        self.path = askopenfilename()
        self.file_add.insert(1.0,self.path)
    def jieshou(self):
        self.text.insert(END,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n'+'他:' + self.resulttext  + '\n')


        
#==========================================================================
# 主界面     
root = Tk() #设定底板
root.geometry("600x540")
root.title("服务器端")
root.resizable(width=False, height=False)

global ip
ip = StringVar()
ip.set("127.0.0.1")
global port
port = IntVar()
port.set("8888")
global cmd
cmd = StringVar()
global fileurl1
fileurl1 = StringVar()
global resulttext
resulttext = str()

title_label = Label(root,text="服务器端",bg = 'yellow',font="宋体 -30 bold").place(x=240,y=20)

iplabel = Label(root,text="服务器ip:",font="宋体 -20 bold").place(x=30,y=70)

ipentry = Entry(root,textvariable=ip,width=40,state="readonly")
ipentry.place(x=140,y=70)
    
portlabel = Label(root,text="服务器端口:",font="宋体 -20 bold").place(x=10,y=100)

portentry = Entry(root,textvariable=port,width=40,state="readonly")
portentry.place(x=140,y=100)


photo = PhotoImage(file="QQ.jpg")
image_label = Label(root,compound='center',image= photo)
image_label.place(x=137,y=125)

warnlabel = Label(root,text="请合理安排上网时长,避免沉迷于网络",font="宋体 -20 bold").place(x=120,y=500)

startscan = Button(root,text="登录", default='active',command=start, width=8,height=1).place(x=20,y=500)
quitscan = Button(root,text="退出", default='active',command=quit, width=8,height=1).place(x=520,y=500)
#===================================================================================
#子页面
global tcp_socket 
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创造窗口类对象
page = Toplevel()
page.withdraw()
window = Window(page,resulttext)
# 开启网络接收新线程
t1 = threading.Thread(target=connect) 
t1.start()
# 页面循环
page.mainloop()
root.mainloop()

###############################################################################################################

运行还需要几张图片,所以我贴上完整的百度云链接:https://pan.baidu.com/s/1p5nrMgW24RoYd7PdMjyb8Q 
提取码:52dk 
 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值