利用tkinter,Thread,socket編寫聊天工具介面版本
client:
新支援功能:
1,登出賬號。
2,新增新使用者(固定)。
3,使用者資訊顯示。
4,賬號退出。
5,介面劃分。
6,朋友賬號顯示。
8,Menu button的顯示。
上版本支援功能:
1,web登入。
2,賬號認證
3,賬號註冊
4,資訊傳送。
5,資訊顯示
server:
新增加功能:
1,賬號新朋友新增功能。
2,賬號老朋友記錄。
4,新增朋友時判斷。
上版本支援功能:
1,web啟動server。
2,登入資訊顯示。
3,賬號儲存。
4,賬號認證。
Server程式碼:
import tkinter as tkimport socket, threadingimport picklefrom collections import defaultdictimport oswindow = tk.Tk() # 建立主視窗window.title('Fiona Server')window.geometry("400x400+200+20")users = {} # 使用者字典,也可以連線資料庫def run(ck, ca): userName = ck.recv(1024).decode() # 接受客戶端傳送的資訊以1k作為單位這裡接受到的資訊為byte型別 users[userName.split("登入")[0]] = ck # 解碼並儲存使用者的資訊 with open("usrs_info.pickle", "rb") as usr_file: exist_usrs_info = pickle.load(usr_file) if "登入" in userName: account = userName.split("登入") exist_usrs_info = defaultdict(str, exist_usrs_info) if exist_usrs_info[account[0]] == account[1]: ck.sendall("登入成功,可以嗨了\n".encode()) info = account[0] + "登入成功\n" users[userName.split("登入")[0]] = ck print(users) elif exist_usrs_info[account[0]] != account[1]: ck.sendall("密碼認證失敗\n".encode()) ck.close() info = account[0] + "認證失敗\n" else: ck.sendall("沒有你的賬號,請先註冊\n".encode()) ck.close() elif "註冊" in userName: account = userName.split("註冊") exist_usrs_info[account[0]] = account[1] with open("usrs_info.pickle", "wb") as usr_file: pickle.dump(exist_usrs_info, usr_file) ck.sendall("註冊成功,請重新登入\n".encode()) print("open1") f = open("{user}_friend_info.txt".format(user=account[0]),"ab+") f.write(("Old Friend List :\n;").encode()) f.close() ck.close() info = account[0] + "註冊成功\n" print(users) elif not userName: ck.close() print(users) text.insert(tk.INSERT, info) while True: rData = ck.recv(1024) # 接受客戶端傳送的資訊以1k作為單位這裡接受到的資訊為byte型別 dataStr = rData.decode("utf-8") if "del" in dataStr: account = dataStr.split("del") if exist_usrs_info[account[0]] == account[1]: del exist_usrs_info[account[0]] with open("usrs_info.pickle", "wb") as usr_file: pickle.dump(exist_usrs_info, usr_file) if os.path.exists("{user}_friend_info.txt".format(user=account[0])): print("The file exist") os.remove("{user}_friend_info.txt".format(user=account[0])) else: print("The file does not exist") ck.close() else: break elif "getoldfriend" in dataStr: account = dataStr.split("getoldfriend") print(account[0]) print("open1") with open("{user}_friend_info.txt".format(user=account[0]), "r") as usr_file: your_friend_info = usr_file.read() print(your_friend_info) ck.sendall(your_friend_info.encode()) elif "addfriend" in dataStr: account = dataStr.split("addfriend") f = open("{user}_friend_info.txt".format(user=account[0]), "rb+") data = f.read().decode() if ";"+account[1]+";" in data: ck.sendall("朋友{account}已經存在,不需要新增!\n".format(account=account[1]).encode()) else: with open("usrs_info.pickle", "rb") as usr_file: exist_usrs_info = pickle.load(usr_file) if account[1] in exist_usrs_info: f.write(("{account};".format(account=account[1])).encode()) ck.sendall("朋友: {account} 已新增!\n".format(account=account[1]).encode()) else: ck.sendall("朋友: {account}不存在!\n".format(account=account[1]).encode()) f.close() else: infolist = dataStr.split(":") # 分割字串從而得到所要傳送的使用者名稱和客戶端所傳送的資訊 users[infolist[0]].send((userName + ":" + infolist[1] + "\n").encode("utf-8")) # 要傳送資訊的客戶端向目標客戶端傳送資訊def start(): ipStr = eip.get() # 從輸入端中獲取ip portStr = eport.get() # 從輸入端中獲取埠,注意埠取得時候不能被佔用(可以取8080,9876,等) server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socked所準守ipv4或ipv6,和相關協議的 server.bind((ipStr, int(portStr))) # 繫結ip和埠號!!!1:注意輸入的埠號是str型而這裡的要傳入int型 server.listen(10) # 設定監聽,和設定連線的最大的數量 printStr = "伺服器啟動成功\n" # ,是否連線成功 text.insert(tk.INSERT, printStr) # 顯示在資訊視窗中 while True: # 這裡用死迴圈是因為模擬的伺服器要一直執行 ck, ca = server.accept() # 接受所連線的客戶端的資訊 t = threading.Thread(target=run, args=(ck, ca)) # 每連線一個客戶端就開啟一個執行緒 t.start() # 開啟執行緒def startSever(): s = threading.Thread(target=start) # 啟用一個執行緒開啟伺服器 s.start() # 開啟執行緒# 下面是關於介面的操作labelIp = tk.Label(window, text='Server IP').grid(row=0, column=0)labelPort = tk.Label(window, text='Connect port').grid(row=1, column=0)eip = tk.Variable()eport = tk.Variable()eip.set("192.168.68.202")eport.set(8001)entryIp = tk.Entry(window, textvariable=eip).grid(row=0, column=1)entryPort = tk.Entry(window, textvariable=eport).grid(row=1, column=1)button = tk.Button(window, text="啟動", command=startSever).grid(row=2, column=0)text = tk.Text(window, height=5, width=30)labeltext = tk.Label(window, text='連線訊息').grid(row=3, column=0)text.grid(row=200, column=1)window.mainloop()