李晗华 发表于 2021-5-25 17:17:38

Python有关线程的异常

异常:Tcl_AsyncDelete: async handler deleted by the wrong thread




程序:
import base64
import struct
from tkinter import *
import time
from tkinter import filedialog
import RSAalgorithm
import pickle
import socket
import threading
import tkinter.messagebox
import generateKey
import hashalg
import AESalgorithm
import json

# 使用tkinter建立GUI

IP = '127.0.0.1'
PORT = 4396
BUFF = 5120
FIP='127.0.0.1'
FPORT=7932


# CLIENTPUBLICs
# SERVERPUBLICs
# SERVERPRIVATEs
def initKey():
    global SERVERPUBLICs, SERVERPRIVATEs
    (SERVERPRIVATEs, SERVERPUBLICs) = generateKey.generateMyKey("./server/server")

def fileDecrypt(data):
    (message,encrykey)=pickle.loads(data)
    onceKey=RSAalgorithm.RsaDecrypt(encrykey, SERVERPRIVATEs)
    print("接收到的密钥",onceKey,type(onceKey))
    message=AESalgorithm.AesDecrypt(message,onceKey.decode('unicode_escape'))
    message=pickle.loads(message)
    content=base64.b64decode(message['Message'])
    print('传送的内容是',content)
    digest=message['digest']
    if RSAalgorithm.VerRsaSignal(content,digest,CLIENTPUBLICs):
      return content

def initFileListen():
    try:
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      # 绑定端口为9001
      s.bind((FIP, FPORT))
      # 设置监听数
      s.listen(10)
    except socket.error as msg:
      print(msg)
      sys.exit(1)
    print('Waiting connection...')

    while True:
      # 等待请求并接受(程序会停留在这一旦收到连接请求即开启接受数据的线程)
      conn, addr = s.accept()
      # 接收数据
      t = threading.Thread(target=deal_data, args=(conn, addr))
      t.start()


def deal_data(conn, addr):
    print('Accept new connection from {0}'.format(addr))
    txtMsgList.insert(END, '文件系统收到一个新的连接,地址来自 {0}'.format(addr), 'greencolor')
    # conn.settimeout(500)
    # 收到请求后的回复
    conn.send('你好,连接建立成功了'.encode('utf-8'))

    while True:
      # 申请相同大小的空间存放发送过来的文件名与文件大小信息
      fileinfo_size = struct.calcsize('128sl')
      # 接收文件名与文件大小信息
      buf = conn.recv(fileinfo_size)
      # 判断是否接收到文件头信息
      if buf:
            # 获取文件名和文件大小
            filename, filesize = struct.unpack('128sl', buf)
            fn = filename.strip(b'\00')
            fn = fn.decode()
            print('file new name is {0}, filesize if {1}'.format(str(fn), filesize))
            txtMsgList.insert(END, '收到的文件名字为 {0}, 文件大小为 {1}'.format(str(fn), filesize), 'greencolor')
            recvd_size = 0# 定义已接收文件的大小
            # 存储在该脚本所在目录下面
            fp = open('./' + str(fn), 'wb')
            print('start receiving...')
            txtMsgList.insert(END, '开始接受...', 'greencolor')
            # 将分批次传输的二进制流依次写入到文件
            while not recvd_size == filesize:
                if filesize - recvd_size > 1024:
                  lens=conn.recv(1024).decode('utf-8')
                  print("1.",lens,'\n')
                  lens=int(lens)
                  print('该段发送长度为',lens)
                  data = conn.recv(lens)
                  data=fileDecrypt(data)
                  recvd_size += len(data)
                else:
                  lens = conn.recv(1024).decode('utf-8')
                  print("1.", lens, '\n')
                  lens = int(lens)
                  print('该段发送长度为', lens)
                  data = conn.recv(lens)
                  data = fileDecrypt(data)
                  recvd_size = filesize
                conn.send('I have receive the past one'.encode('utf-8'))
                fp.write(data)
            fp.close()
            print('end receive...')
            txtMsgList.insert(END, '接收完毕...', 'greencolor')
      # 传输结束断开连接
      conn.close()
      break


def mainPage():
    def sendMsg(Sock):# 发送消息
      strMsg = "我:" + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '\n'
      txtMsgList.insert(END, strMsg, 'greencolor')
      Mes = txtMsg.get('0.0', END)
      txtMsgList.insert(END, Mes)
      print(Mes)
      onceKey = AESalgorithm.genKey()# 一次一密 密钥
      print("oncekey", onceKey)
      digest = RSAalgorithm.RsaSignal(Mes, SERVERPRIVATEs)# 先hash再签名# 生成消息摘要
      message = {'Message': Mes, 'digest': digest.decode("utf-8")}# 把消息和摘要打包
      message = json.dumps(message)# 转成json字符串
      message = AESalgorithm.AesEncrypt(message, onceKey)# 合并加密
      encrykey = RSAalgorithm.RsaEncrypt(onceKey, CLIENTPUBLICs)# 用服务器公钥加密一次密钥
      txtMsg.delete('0.0', END)
      Message = pickle.dumps()# 序列化消息,用于传输
      Sock.send(Message)

    def RecvMsg(Sock, test):
      global CLIENTPUBLICs
      while True:
            Message = Sock.recv(BUFF)# 收到文件
            (message, encrykey) = pickle.loads(Message)
            mykey = RSAalgorithm.RsaDecrypt(encrykey, SERVERPRIVATEs)# 用私钥解密获得一次密钥
            decryMes = AESalgorithm.AesDecrypt(message, mykey.decode('utf-8'))# 用一次密钥解密消息,获得包含消息内容和摘要的json
            decryMes = json.loads(decryMes)# 将json转换为python字典
            content = decryMes['Message']
            digest = decryMes['digest'].encode('utf-8')
            if RSAalgorithm.VerRsaSignal(content, digest, CLIENTPUBLICs):
                strMsg = "对方:" + time.strftime("%Y-%m-%d %H:%M:%S",
                                             time.localtime()) + "通过数字签名认证,本次密钥为" + mykey.decode('utf-8') + '\n'
                txtMsgList.insert(END, strMsg, 'greencolor')
                txtMsgList.insert(END, content + '\n')


    def cancelMsg():# 取消信息
      txtMsg.delete('0.0', END)

    def sendMsgEvent(event, Sock):# 发送消息事件
      if event.keysym == 'Up':
            sendMsg(Sock)

    def UploadAction(event=None):
      filename = filedialog.askopenfilename()
      print('Selected:', filename)

    def addSysTip(mes):
      global txtMsgList
      txtMsgList.insert(END, "系统消息:" + mes)

    def exchangePublicKey(dir):
      global ConSock, txtMsgList
      with open(dir, 'rb') as fi:
            publicKey = fi.read()
      # print(publicKey)
      has = hashalg.hash_sha256(publicKey)
      Message = pickle.dumps()
      try:
            ConSock.send(Message)
            txtMsgList.insert(END, "发送公钥成功\n")
      except:
            txtMsgList.insert(END, "密钥发送失败,正在尝试重新发送...\n")
            exchangePublicKey(dir)

    def verifyKey(Sock):
      global txtMsgList, CLIENTPUBLICs
      while True:
            Message = Sock.recv(BUFF)
            # print("shoudao:",Message)
            (publickey, hash_256) = pickle.loads(Message)
            if hash_256 == hashalg.hash_sha256(publickey):
                txtMsgList.insert(END, "公钥完整性验证完成,可以开始传输文件\n")
                CLIENTPUBLICs = publickey
                txtMsgList.insert(END, "收到公钥\n" + CLIENTPUBLICs.decode('utf-8') + "\n")
                # print("publicc:", CLIENTPUBLICs)
                break
            else:
                txtMsgList.insert(END, "验证失败\n")

    def cnct():
      global txtMsgList, ConSock
      HOSTIP = '127.0.0.1'
      ServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      ServerSock.bind((HOSTIP, PORT))
      ServerSock.listen(8)
      print("本机IP地址为", HOSTIP, "端口号为", PORT, ",正在监听中")
      txtMsgList.insert(END, "系统消息:" + "本机IP地址为" + HOSTIP + "端口号为" + str(PORT) + ",正在监听中\n")
      ConSock, addr = ServerSock.accept()
      print('连接成功')
      txtMsgList.insert(END, "系统消息:连接成功\n")
      exchangePublicKey("./server/serverpublic.pem")
      verifyKey(ConSock)
      thread_rev = threading.Thread(target=RecvMsg, args=(ConSock, None))
      thread_rev.start()
      return ConSock

    def setIpWindows():
      def setNewIP(newip, newport):
            print(newip, newport)
            global IP
            IP = str(newip)
            global PORT
            PORT = int(newport)
            set.destroy()
            try:
                cnct()
            except:
                addSysTip("连接异常,ip或端口不可访问")
                tkinter.messagebox.showwarning('连接失败', '连接异常,ip或端口不可访问\n')
                print("连接异常,ip或端口不可访问\n")

      set = Tk()
      set.title('设置ip地址和端口号')
      set.geometry('350x200')
      set.resizable(0, 0)
      # ip
      Label(set, text='IP地址:').place(x=10, y=10)
      ent1 = Entry(set)
      ent1.place(x=150, y=10)
      # port
      Label(set, text='端口号:').place(x=10, y=50)
      ent2 = Entry(set)
      ent2.place(x=150, y=50)
      bt_connect = Button(set, text='连接', command=lambda: setNewIP(ent1.get(), ent2.get()))
      bt_connect.place(x=150, y=130)
      set.mainloop()

    def start():
      global app, frmLT, frmLC, frmLB, txtMsgList, txtMsg, btnSend, btnCancel, btnFile, btnSet
      # 创建窗口
      app = Tk()
      app.title('Server')
      app.resizable(0, 0)

      # 创建frame容器
      frmLT = Frame(width=200, height=150, bg='white')
      frmLC = Frame(width=200, height=50, bg='white')
      frmLB = Frame(width=200, height=30)
      # frmRT = Frame(width = 200, height = 500)

      # 创建控件
      txtMsgList = Text(frmLT)
      txtMsgList.tag_config('greencolor', foreground='#008C00')# 创建tag
      txtMsg = Text(frmLC)
      txtMsg.bind("<KeyPress-Up>", sendMsgEvent)
      btnSend = Button(frmLB, text='发送', width=8, command=lambda: sendMsg(ServerSocket))
      btnCancel = Button(frmLB, text='取消', width=8, command=cancelMsg)
      btnFile = Button(frmLB, text='上次文件', width=8, command=UploadAction)
      btnSet = Button(frmLB, text='设置ip', width=8, command=setIpWindows)
      # btnFile.pack()
      # imgInfo = PhotoImage(file = "timg-2.gif")
      # lblImage = Label(frmRT, image = imgInfo)
      # lblImage.image = imgInfo

      # 窗口布局
      frmLT.grid(row=0, column=0, columnspan=2, padx=1, pady=3)
      frmLC.grid(row=1, column=0, columnspan=2, padx=1, pady=3)
      frmLB.grid(row=2, column=0, columnspan=2)
      # frmRT.grid(row = 0, column = 2, rowspan = 3, padx =2, pady = 3)

      # 固定大小
      frmLT.grid_propagate(0)
      frmLC.grid_propagate(0)
      frmLB.grid_propagate(0)
      # frmRT.grid_propagate(0)

      btnSend.grid(row=2, column=0)
      btnCancel.grid(row=2, column=1)
      btnFile.grid(row=2, column=2)
      btnSet.grid(row=2, column=3)
      # lblImage.grid()
      txtMsgList.grid()
      txtMsg.grid()
      # 主事件循环
      app.mainloop()

    thread_gui = threading.Thread(target=start)
    thread_gui.start()

    ServerSocket = cnct()
    # try:
    #   ServerSocket=cnct()
    # except:
    #   addSysTip("连接异常,ip或端口不可访问")
    #   tkinter.messagebox.showwarning('连接失败', '连接异常,ip或端口不可访问,点击设置按钮重新设置\n')
    #   print("连接异常,ip或端口不可访问\n")


def main():
    initKey()
    thread_1=threading.Thread(target=initFileListen)
    # thread_2=threading.Thread(target=mainPage)
    mainPage()
    thread_1.start()
    # thread_2.start()


if __name__ == "__main__":
    main()

nahongyan1997 发表于 2021-6-23 15:48:18

只会线程不会异步

z5560636 发表于 2021-6-25 13:38:49

global txtMsgList, ConSock

这个没看到定义全局的地方啊
页: [1]
查看完整版本: Python有关线程的异常