网站首页 > 技术文章 正文
利用tkinter,Thread,socket编写聊天工具界面版本
代码过多,只提供server上的源码,如有需要client端源码,可以加关注留言提供
client:
新支持功能:
1,注销账号。
2,添加新用户(固定)。
3,用户信息显示。
4,账号退出。
5,界面划分。
6,朋友账号显示。
7,聊天信息按钮(功能待实现)
8,Menu button的显示。
上版本支持功能:
1,web登录。
2,账号认证
3,账号注册
4,信息发送。
5,信息显示
server:
新增加功能:
1,账号新朋友添加功能。
2,账号老朋友记录。
3,注销功能时,删除server上账号信息。
4,添加朋友时判断。
上版本支持功能:
1,web启动server。
2,登录信息显示。
3,账号保存。
4,账号认证。
5,信息转发。
Server代码:
import tkinter as tk
import socket, threading
import pickle
from collections import defaultdict
import os
window = 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()
- 上一篇: 教你用Siri来控制电脑:真香
- 下一篇: 用vscode编辑调试Python代码
猜你喜欢
- 2024-12-25 Python 中的加密操作 (base64、MD5)
- 2024-12-25 Python技术开发证怎么考
- 2024-12-25 python实现登录12306网站查看火车票信息
- 2024-12-25 python:list(列表)常用操作
- 2024-12-25 用 Python 重构 God 类:万物皆有其位
- 2024-12-25 用vscode编辑调试Python代码
- 2024-12-25 教你用Siri来控制电脑:真香
- 2024-12-25 Python打包对比实测:Nuitka vs PyInstaller,谁更快更安全?
- 2024-12-25 Lolin S2 mini ESP32-S2 WiFi IoT板,可与Wemos D1 Mini扩展板配合使用
- 2024-12-25 Python vs C++ :最好的机器人语言
- 05-25Python 3.14 t-string 要来了,它与 f-string 有何不同?
- 05-25Python基础元素语法总结
- 05-25Python中的变量是什么东西?
- 05-25新手常见的python报错及解决方案
- 05-2511-Python变量
- 05-2510个每个人都是需要知道Python问题
- 05-25Python编程:轻松掌握函数定义、类型及其参数传递方式
- 05-25Python基础语法
- 257℃Python短文,Python中的嵌套条件语句(六)
- 257℃python笔记:for循环嵌套。end=""的作用,图形打印
- 256℃PythonNet:实现Python与.Net代码相互调用!
- 251℃Python操作Sqlserver数据库(多库同时异步执行:增删改查)
- 251℃Python实现字符串小写转大写并写入文件
- 106℃原来2025是完美的平方年,一起探索六种平方的算吧
- 90℃Python 和 JavaScript 终于联姻了!PythonMonkey 要火?
- 81℃Ollama v0.4.5-v0.4.7 更新集合:Ollama Python 库改进、新模型支持
- 最近发表
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)