本文最后更新于 2024-02-29,文章内容可能已经过时。

基于python开发的tcp单线程通讯程序,分为客户端和服务端,服务端需自行部署到服务器运行

目前程序处于测试阶段,很多功能尚未完善

使用须知:

1、连接服务器进入聊天界面后,请不要关闭最开始输入服务器ip的窗口,因为我并没有写保存ip信息的代码,你关了程序就报错,后续会补上

2、由于处于测试截断,聊天对话不会实时刷新,你发送消息后需要不断点击刷新服务器来同步服务器消息,且服务器只保存一条对话,如果刷新不及时可能会错过别人的消息

3、本程序没有用户登陆系统,辨别他人纯靠他人的ip

更新内容:

1、2023/6/25加入了刷新服务器功能,用于刷新通讯服务器的聊天信息到本地,实现与他人对话,暂时无法实现实时刷新,这需要借助多线程,后续更新中可能会添加

2、2023/6/25修改了程序的UI样式,使其显得不那么生硬

演示截图:

屎山源码:

客户端:

import socket
from tkinter import *
from tkinter.ttk import *
from tkinter import scrolledtext
import requests
import os
import random
print("\033[0;32;40m***************************调试终端****************************\033[0m")
print("这是程序的调试终端,所有操作信息会在这里显示,方便定位和修改错误")
print("我再在这里提醒一遍,一定一定不要关闭最开始的那个填写服务器的窗口,我没写保存服务器信息的代码,不然你关了会报错的")
print("连接服务器的时候会直接get你在输入服务器ip的那个窗口的内容,你关了,就get不到了就报错")
print("我之后会完善这一部分代码")
print("注意哦,本程序会在工作目录下创建多个配置txt文档,用于保存配置信息,请谨慎删除")
print("\033[0;32;40m从服务器获取初始数据并创建文件.....\033[0m")
#获取初始聊天文件数据
url = "https://meouy.top/video/chat.txt"
save_path = "oldchat.txt"
with open(save_path, "wb") as f:
    response = requests.get(url, stream=True)
    for chunk in response.iter_content(chunk_size=8192):
        if chunk:
            f.write(chunk)
print("\033[0;32;40m操作执行完成\033[0m")

def gonggao():
    #公告面板的GUI界面
    gonggao = Tk()
    gonggao.geometry("350x200")
    gonggao.title("公告")
    gonggao.attributes('-topmost', 'true')
    Label(gonggao,text="这是测试版本,不代表最终品质",font=("微软雅黑",15),foreground="red").grid(row=0,column=0,pady=5,padx=20)
    Label(gonggao,text="注意:测试版本未实现聊天数据实时刷新,请务必不\n断点击服务器刷新按钮来实现接收消息,服务器只保\n"
                       "存一条消息记录,如果你不持续点击刷新服务器按钮\n可能会错过消息,还有一定不要关闭第一个输入服务\n器"
                       "ip的窗口,因为时间原因我并没有写将ip保存\n的代码,你关了软件就无法get到服务器ip信息\n(作者qq:290162625)",font=("微软雅黑",10)).grid(row=1,column=0,pady=5)
    gonggao.mainloop()
def tcp():
    global chattext
    serverip = fip.get()
    serverport = fport.get()
    print("中转服务器ip:" + serverip + ":" + serverport)
    tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server = (serverip,int(serverport))
    tcpserver.connect(server)
    print("链接到服务器")
    put = open('userput.txt','r')
    #注意,userput变量名和下面的某个函数变量名相同,修改时请注意辨别
    userput = put.read()
    send = userput
    tcpserver.send(send.encode("GBK"))
    chattext.insert(END,"请求服务器操作成功完成,请不断点击刷新服务器来接收消息\n")
    tcpserver.close()
def oldfile():
    #顺便记录一下哈,终于在这里取得了突破性进展,通过判断新旧文件的差异来决定是否加载和刷新数据,真不容易啊,我自己写的代码我自己看都绕晕了
    #这是检测到新旧记录不同的时候执行的函数,避免旧文件无法正常发挥作用
    #注意,这个函数中的变量和againlog()和chat()这两个函数中的变量命名相同,之所以相同是因为各函数间不互通,所以修改的时候一定要加以辨别啊,不要再又被绕晕了!!
    oplog = open('chatlog.txt','r',encoding="utf-8")
    readlog = oplog.read()
    oldchat = open('oldchat.txt','w',encoding='utf-8')
    oldchat.write(readlog)
def againlog():
    global chattext
    url = "https://meouy.top/video/chat.txt"
    # 定义文件保存路径
    save_path = "chatlog.txt"
    # 使用requests库下载文件并保存到本地
    with open(save_path, "wb") as f:
        response = requests.get(url, stream=True)
        for chunk in response.iter_content(chunk_size=8192):
            if chunk:
                f.write(chunk)
    #下面为文件的读取操作,注意oplog和readlog变量和chat()函数中变量是一样的,但是因为函数之间不互通所以用相同名称变量,修改时一定要注意辨别
    #刷新聊天框
    oplog = open('chatlog.txt', 'r', encoding='utf-8')
    readlog = oplog.read()
    oldchat = open('oldchat.txt','r',encoding='utf-8')
    readold = oldchat.read()
    if readlog == readold:
        print("\033[0;32;40m服务器文件与本地文件相同,不执行刷新操作\033[0m")
    else:
        print("检测到数据更新,下面为新旧数据对比")
        print(readlog)
        print(readold)
        print("调用自定义函数,执行刷新操作...")
        oldfile()
        chattext.insert(END, readlog + '\n')
def chat():
    serverip = fip.get()
    def fu():
        #套壳函数,用于中间过渡获取用户输入然后写入文件执行tcp发送函数
        #我之所以这么麻烦的写入文件是因为为了更好的检查程序中运行的错误
        userget = userput.get()
        input = open('userput.txt','w')
        input.write(userget)
        input.close()
        tcp()

    windows1.quit()
    global chattext
    chat = Tk()
    chat.title("聊天")
    chat.geometry("800x520")
    #创建FRAME(左边的聊天消息窗口)ltk
    ltk = Frame(chat)
    #一些图形化配置
    ltk.grid(row=0,column=0)
    chattext = scrolledtext.ScrolledText(ltk,width=60,height=40)
    chattext.grid(row=0,column=0)
    chattext.insert(END,"初始化聊天....完成\n")
    chattext.insert(END,"版本:1.0.0\n")
    #为用户填写的服务器运行ping检测
    chattext.insert(END,"检查服务器连通性....")
    print("服务器ip:" + serverip)
    ping = os.popen('ping '+ serverip + " -n 1",'r')
    cmdread = ping.read()
    chattext.insert(END,str(cmdread) + '\n')
    chattext.insert(END,"请通过上方ping测试结果来判断服务器是否正常,请确保目标服务器已经部署tcp服务端\n")

    #创建Frame(右边的控制面板)mb
    mb = Frame(chat)
    mb.grid(row=0,column=1)
    Label(mb,text="聊天工具面板",font=("微软雅黑",15)).grid(row=0,column=0)
    Button(mb,text="服务器刷新",command=againlog).grid(row=1,column=0,pady=8)
    userput = Entry(mb)
    Label(mb,text="请输入要发送的内容:",font=("微软雅黑",10)).grid(row=2,column=0,pady=8)
    userput.grid(row=2,column=1)
    Button(mb,text="发送",command=fu).grid(row=3,column=1)
    gonggao()
    chat.mainloop()

windows1 = Tk()

windows1.title('python实现tcp协议聊天示例')
windows1.geometry('350x150')
Label(windows1,text="请填入中转服务器ip:",font=("微软雅黑",10)).grid(row=0,column=0,padx=5,pady=4)
Label(windows1,text="请填入通信端口:",font=("微软雅黑",10)).grid(row=1,column=0,pady=3,padx=5)
Button(windows1,text="连接服务器",command=chat).grid(row=2,column=1,pady=10)
fip = Entry(windows1)
fport = Entry(windows1)
fport.grid(row=1,column=1)
fip.grid(row=0,column=1)
windows1.mainloop()

服务端:

服务端暂不展示