20243410 实验三《Python程序设计》实验报告

20243410 2025-2026-2 《Python程序设计》实验3报告

课程:《Python程序设计》
班级: 2434
姓名: 陈懿慜
学号:20243410
实验教师:王志强
实验日期:2026年4月27日
必修/选修: 公选课

1.实验内容

1.1实验内容
创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。

1.2实验要求
注意事项:
每人必须做一次客户端和一次服务端,且要和队友(标注学号姓名)互相通信。
要求1:
(1)创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
(2)要求发送方输入内容,加密后并传输;接收方收到密文并解密和显示。要求:发方和收方同时输出明文和明文。
(3)程序代码托管到码云。
(4)添加文件操作,有加分。(可选项)
要求2:使用LLM生成一个带图形界面的程序
(1)分析关键代码的功能和使用方法
(2)分析生成程序的优点
(3)给出运行过程和结果截图
(4)程序代码托管到码云。
注:在华为ECS服务器(OpenOuler系统)和物理机(Windows/Linux系统)上使用VIM、PDB、IDLE、Pycharm等工具编程实现

2. 实验过程及结果

2.1创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
我是20243410,故ip定为192.168.31.10
创建服务器

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = "192.168.31.10"
PORT = 4444
server.bind((HOST, PORT))
server.listen(10)
print("服务端已启动,支持多客户端连接!")

创建客户端

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = "192.168.31.10"
PORT = 4444
client.connect((HOST, PORT))
print("已连接服务端!输入exit退出聊天!")

2.2实现加密算法
采用简单的函数加密(类似凯撒密码)

key = 8
def encrypt(s):
return ''.join(chr(ord(c) + key) for c in s)
def decrypt(s):
return ''.join(chr(ord(c) - key) for c in s)
屏幕截图 2026-04-28 215734

2.3文件操作
同时保存明文、密文的聊天记录

filename = f"聊天记录和客户端{ip}_{port}.txt"
file = open(filename, "w", encoding="utf-8")
file.write("===== 聊天记录(明文 | 密文)=====\n")
file.write(f"[接收] 明文:{data} | 密文:{encrypt_data}\n")
file.write(f"[发送] 明文:{send_msg} | 密文:{encrypted_send}\n")
屏幕截图 2026-04-28 232039

2.3服务端同时连接多个服务器实现
通过引入threading函数实现

while True:
conn, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
屏幕截图 2026-04-28 233002
屏幕截图 2026-04-28 233013
屏幕截图 2026-04-28 233018

2.4对话代码展示

客户端和服务器类似

while True:
#接收密文
encrypt_data = conn.recv(1024).decode("utf-8")
if not encrypt_data or encrypt_data == encrypt("exit"):
print(f"{addr} 聊天结束")
file.close()
conn.close()
break
data = decrypt(encrypt_data)
print(f"客户端 {addr}:")
print(f" 明文:{data}")
print(f" 密文:{encrypt_data}")
file.write(f"[接收] 明文:{data} | 密文:{encrypt_data}\n")
# 发送消息
send_msg = input(f"回复 {addr}:")
encrypted_send = encrypt(send_msg)
conn.send(encrypted_send.encode("utf-8"))
print(f"已发送至 {addr}:")
print(f" 明文:{send_msg}")
print(f" 密文:{encrypted_send}")
file.write(f"[发送] 明文:{send_msg} | 密文:{encrypted_send}\n")
if send_msg == "exit":
print(f"{addr} 聊天结束")
file.close()
conn.close()
break

2.5完整代码和实验展示
服务器

点击查看代码
# 20243410 陈懿慜 2026年4月28日编写
#嗨嗨嗨哈,欢迎使用我的服务器
import socket
import threading

key = 8
def encrypt(s):
    return ''.join(chr(ord(c) + key) for c in s)
def decrypt(s):
    return ''.join(chr(ord(c) - key) for c in s)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = "192.168.31.10"
PORT = 4444
server.bind((HOST, PORT))
server.listen(10)
print("服务端已启动,支持多客户端连接!")
print("每个客户端将生成独立的聊天记录文件")


def handle_client(conn, addr):
    print(f"新客户端连接:{addr}")
    ip, port = addr
    filename = f"聊天记录和客户端{ip}_{port}.txt"
    file = open(filename, "w", encoding="utf-8")
    file.write("===== 聊天记录(明文 | 密文)=====\n")
    try:
        while True:
            # 接收密文
            encrypt_data = conn.recv(1024).decode("utf-8")
            if not encrypt_data or encrypt_data == encrypt("exit"):
                print(f"{addr} 聊天结束")
                file.close()
                conn.close()
                break

            data = decrypt(encrypt_data)
            print(f"客户端 {addr}:")
            print(f"  明文:{data}")
            print(f"  密文:{encrypt_data}")

            file.write(f"[接收] 明文:{data} | 密文:{encrypt_data}\n")

            # 发送消息
            send_msg = input(f"回复 {addr}:")
            encrypted_send = encrypt(send_msg)
            conn.send(encrypted_send.encode("utf-8"))
            print(f"已发送至 {addr}:")
            print(f"  明文:{send_msg}")
            print(f"  密文:{encrypted_send}")

            file.write(f"[发送] 明文:{send_msg} | 密文:{encrypted_send}\n")

            if send_msg == "exit":
                print(f"{addr} 聊天结束")
                file.close()
                conn.close()
                break

    except:
        print(f"{addr} 异常断开")
        file.close()
        conn.close()


while True:
    conn, addr = server.accept()
    thread = threading.Thread(target=handle_client, args=(conn, addr))
    thread.start()

客户端

点击查看代码
# 20243410 陈懿慜 2026年4月28日编写
#嗨嗨嗨哈,欢迎使用我的客户端
import socket

key = 8
def encrypt(s):
    return ''.join(chr(ord(c) + key) for c in s)
def decrypt(s):
    return ''.join(chr(ord(c) - key) for c in s)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = "192.168.31.10"
PORT = 4444
client.connect((HOST, PORT))
print("已连接服务端!输入exit退出聊天!")

filename = f"聊天记录和服务端{HOST}_{PORT}.txt"
file = open(filename, "w", encoding="utf-8")
file.write("===== 聊天记录(明文 | 密文)=====\n")

try:
    while True:
        send_msg = input("我:")
        encrypted_msg = encrypt(send_msg)
        client.send(encrypted_msg.encode("utf-8"))
        print("已发送:")
        print(f"  明文:{send_msg}")
        print(f"  密文:{encrypted_msg}")
        file.write(f"[发送] 明文:{send_msg} | 密文:{encrypted_msg}\n")

        if send_msg == "exit":
            print("聊天结束\n")
            file.close()
            client.close()
            break
        data = client.recv(1024).decode("utf-8")

        if not data or data == encrypt("exit"):  # 匹配加密后的exit
            print("聊天结束")
            file.close()
            client.close()
            break

        decrypted_data = decrypt(data)
        print("\n服务端:")
        print(f"  明文:{decrypted_data}")
        print(f"  密文:{data}")

        file.write(f"[接收] 明文:{decrypted_data} | 密文:{data}\n")
except:
    print("连接异常断开")
    file.close()
    client.close()

和20243429付佳琪同学连接的图片
我是服务器(右边那台电脑)
微信图片_20260428215751_293_133
屏幕截图 2026-04-28 215734

他是服务器(右边那台电脑)
9671cae06a7737b942ecc5ac172855b5
屏幕截图 2026-04-28 215515

两个聊天记录文件
我是客户端
屏幕截图 2026-04-28 231320
我是服务端
屏幕截图 2026-04-28 232039

2.7ai生成的代码
服务器

点击查看代码
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, filedialog, messagebox
import datetime
import os


class XORCipher:
    def __init__(self, key):
        self.key = key.encode('utf-8')

    def encrypt(self, data):
        if isinstance(data, str):
            data = data.encode('utf-8')
        return bytes([b ^ self.key[i % len(self.key)] for i, b in enumerate(data)])

    def decrypt(self, data):
        return self.encrypt(data)  # 异或加密解密是同一个操作


class ServerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Socket服务端 (内置加密)")
        self.root.geometry("800x600")

        self.clients = {}  # {client_socket: (address, nickname, cipher)}
        self.running = False
        self.server_key = "MySecretKey2026"  # 默认密钥
        self.cipher_suite = XORCipher(self.server_key)

        # 顶部控制栏
        control_frame = tk.Frame(root)
        control_frame.pack(pady=10, fill=tk.X)

        tk.Label(control_frame, text="端口:").pack(side=tk.LEFT, padx=5)
        self.port_entry = tk.Entry(control_frame, width=10)
        self.port_entry.insert(0, "8888")
        self.port_entry.pack(side=tk.LEFT, padx=5)

        tk.Label(control_frame, text="密钥:").pack(side=tk.LEFT, padx=5)
        self.key_entry = tk.Entry(control_frame, width=20)
        self.key_entry.insert(0, self.server_key)
        self.key_entry.pack(side=tk.LEFT, padx=5)

        self.start_btn = tk.Button(control_frame, text="启动服务", command=self.start_server, bg="#4CAF50", fg="white")
        self.start_btn.pack(side=tk.LEFT, padx=5)

        self.stop_btn = tk.Button(control_frame, text="停止服务", command=self.stop_server, bg="#f44336", fg="white",
                                  state=tk.DISABLED)
        self.stop_btn.pack(side=tk.LEFT, padx=5)

        # 中间分割
        paned_window = tk.PanedWindow(root, orient=tk.HORIZONTAL)
        paned_window.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        # 左侧:客户端列表
        client_frame = tk.Frame(paned_window)
        paned_window.add(client_frame, width=200)

        tk.Label(client_frame, text="在线客户端", font=("Arial", 10, "bold")).pack(pady=5)
        self.client_listbox = tk.Listbox(client_frame)
        self.client_listbox.pack(fill=tk.BOTH, expand=True)

        # 右侧:消息区域
        msg_frame = tk.Frame(paned_window)
        paned_window.add(msg_frame)

        tk.Label(msg_frame, text="消息日志(明文/密文Hex)", font=("Arial", 10, "bold")).pack(pady=5)
        self.log_text = scrolledtext.ScrolledText(msg_frame, state=tk.DISABLED)
        self.log_text.pack(fill=tk.BOTH, expand=True)

        # 底部:广播消息
        broadcast_frame = tk.Frame(root)
        broadcast_frame.pack(pady=10, fill=tk.X, padx=10)

        tk.Label(broadcast_frame, text="广播消息:").pack(side=tk.LEFT)
        self.broadcast_entry = tk.Entry(broadcast_frame)
        self.broadcast_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        self.broadcast_entry.bind("<Return>", lambda e: self.broadcast_message())

        tk.Button(broadcast_frame, text="发送", command=self.broadcast_message, bg="#2196F3", fg="white").pack(
            side=tk.LEFT)
        tk.Button(broadcast_frame, text="保存日志", command=self.save_log, bg="#FF9800", fg="white").pack(side=tk.LEFT,
                                                                                                          padx=5)

    def start_server(self):
        try:
            port = int(self.port_entry.get())
            self.server_key = self.key_entry.get()
            self.cipher_suite = XORCipher(self.server_key)

            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind(('0.0.0.0', port))
            self.server_socket.listen(5)
            self.running = True

            self.start_btn.config(state=tk.DISABLED)
            self.stop_btn.config(state=tk.NORMAL)
            self.log_message("系统", f"服务端启动,端口 {port},密钥已更新")

            threading.Thread(target=self.accept_clients, daemon=True).start()
        except Exception as e:
            messagebox.showerror("错误", f"启动失败: {str(e)}")

    def stop_server(self):
        self.running = False
        for client in list(self.clients.keys()):
            try:
                client.close()
            except:
                pass
        self.clients.clear()
        self.client_listbox.delete(0, tk.END)
        try:
            self.server_socket.close()
        except:
            pass
        self.start_btn.config(state=tk.NORMAL)
        self.stop_btn.config(state=tk.DISABLED)
        self.log_message("系统", "服务端已停止")

    def accept_clients(self):
        while self.running:
            try:
                client_socket, client_address = self.server_socket.accept()
                # 接收昵称
                nickname = client_socket.recv(1024).decode('utf-8')
                # 每个客户端用相同的密钥加密
                client_cipher = XORCipher(self.server_key)
                self.clients[client_socket] = (client_address, nickname, client_cipher)
                self.client_listbox.insert(tk.END, f"{nickname} ({client_address[0]}:{client_address[1]})")
                self.log_message("系统", f"客户端 {nickname} 已连接")

                threading.Thread(target=self.handle_client, args=(client_socket,), daemon=True).start()
            except:
                break

    def handle_client(self, client_socket):
        address, nickname, cipher = self.clients[client_socket]
        while self.running:
            try:
                encrypted_data = client_socket.recv(4096)
                if not encrypted_data:
                    break

                # 解密
                decrypted_data = cipher.decrypt(encrypted_data).decode('utf-8')

                if decrypted_data.startswith("FILE:"):
                    self.receive_file(client_socket, decrypted_data[5:], nickname, cipher)
                else:
                    self.log_message(nickname, f"密文: {encrypted_data.hex()}\n明文: {decrypted_data}")
                    self.forward_message(encrypted_data, client_socket)
            except Exception as e:
                self.log_message("系统", f"客户端 {nickname} 错误: {str(e)}")
                break

        if client_socket in self.clients:
            del self.clients[client_socket]
            self.client_listbox.delete(0, tk.END)
            for addr, nick, _ in self.clients.values():
                self.client_listbox.insert(tk.END, f"{nick} ({addr[0]}:{addr[1]})")
            self.log_message("系统", f"客户端 {nickname} 已断开")
        client_socket.close()

    def receive_file(self, client_socket, filename, nickname, cipher):
        self.log_message("系统", f"接收 {nickname} 的文件: {filename}")
        # 接收文件大小
        encrypted_size = client_socket.recv(1024)
        file_size = int(cipher.decrypt(encrypted_size).decode('utf-8'))

        # 接收文件内容
        encrypted_content = b""
        while len(encrypted_content) < file_size:
            packet = client_socket.recv(4096)
            if not packet:
                break
            encrypted_content += packet

        # 解密保存
        content = cipher.decrypt(encrypted_content)
        save_path = os.path.join("server_files", filename)
        os.makedirs("server_files", exist_ok=True)
        with open(save_path, 'wb') as f:
            f.write(content)

        self.log_message("系统", f"文件已保存到 {save_path}")

    def forward_message(self, encrypted_data, exclude_socket):
        for client in self.clients.keys():
            if client != exclude_socket:
                try:
                    client.send(encrypted_data)
                except:
                    pass

    def broadcast_message(self):
        message = self.broadcast_entry.get()
        if not message:
            return
        full_msg = f"[广播] {message}"
        encrypted_msg = self.cipher_suite.encrypt(full_msg)
        self.log_message("广播", f"密文: {encrypted_msg.hex()}\n明文: {full_msg}")
        for client in self.clients.keys():
            try:
                client.send(encrypted_msg)
            except:
                pass
        self.broadcast_entry.delete(0, tk.END)

    def log_message(self, sender, content):
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.log_text.config(state=tk.NORMAL)
        self.log_text.insert(tk.END, f"[{timestamp}] {sender}:\n{content}\n\n")
        self.log_text.config(state=tk.DISABLED)
        self.log_text.see(tk.END)

    def save_log(self):
        file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])
        if file_path:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(self.log_text.get(1.0, tk.END))
            messagebox.showinfo("成功", "日志已保存")


if __name__ == "__main__":
    root = tk.Tk()
    app = ServerGUI(root)
    root.mainloop()
客户端
点击查看代码
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, filedialog, messagebox, simpledialog, colorchooser, font
import datetime
import os


class XORCipher:
    def __init__(self, key):
        self.key = key.encode('utf-8')

    def encrypt(self, data):
        if isinstance(data, str):
            data = data.encode('utf-8')
        return bytes([b ^ self.key[i % len(self.key)] for i, b in enumerate(data)])

    def decrypt(self, data):
        return self.encrypt(data)


class ClientGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Socket客户端 (内置加密)")
        self.root.geometry("900x700")

        self.client_socket = None
        self.connected = False
        self.cipher_suite = None
        self.nickname = ""

        # 菜单栏
        menubar = tk.Menu(root)
        root.config(menu=menubar)
        settings_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="设置", menu=settings_menu)
        settings_menu.add_command(label="字体设置", command=self.change_font)
        settings_menu.add_command(label="背景颜色", command=self.change_bg_color)
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="帮助", menu=help_menu)
        help_menu.add_command(label="使用说明", command=self.show_help)

        # 连接栏
        connect_frame = tk.Frame(root)
        connect_frame.pack(pady=10, fill=tk.X)

        tk.Label(connect_frame, text="昵称:").pack(side=tk.LEFT, padx=5)
        self.nickname_entry = tk.Entry(connect_frame, width=15)
        self.nickname_entry.insert(0, "用户" + str(os.getpid())[-4:])
        self.nickname_entry.pack(side=tk.LEFT, padx=5)

        tk.Label(connect_frame, text="服务端IP:").pack(side=tk.LEFT, padx=5)
        self.ip_entry = tk.Entry(connect_frame, width=15)
        self.ip_entry.insert(0, "127.0.0.1")
        self.ip_entry.pack(side=tk.LEFT, padx=5)

        tk.Label(connect_frame, text="端口:").pack(side=tk.LEFT, padx=5)
        self.port_entry = tk.Entry(connect_frame, width=10)
        self.port_entry.insert(0, "8888")
        self.port_entry.pack(side=tk.LEFT, padx=5)

        tk.Label(connect_frame, text="密钥:").pack(side=tk.LEFT, padx=5)
        self.key_entry = tk.Entry(connect_frame, width=20)
        self.key_entry.insert(0, "MySecretKey2026")
        self.key_entry.pack(side=tk.LEFT, padx=5)

        self.connect_btn = tk.Button(connect_frame, text="连接", command=self.connect_server, bg="#4CAF50", fg="white")
        self.connect_btn.pack(side=tk.LEFT, padx=5)

        self.disconnect_btn = tk.Button(connect_frame, text="断开", command=self.disconnect_server, bg="#f44336",
                                        fg="white", state=tk.DISABLED)
        self.disconnect_btn.pack(side=tk.LEFT, padx=5)

        # 中间分割
        paned_window = tk.PanedWindow(root, orient=tk.HORIZONTAL)
        paned_window.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        # 左侧表情
        emoji_frame = tk.Frame(paned_window)
        paned_window.add(emoji_frame, width=100)
        tk.Label(emoji_frame, text="表情", font=("Arial", 10, "bold")).pack(pady=5)
        self.emoji_list = ["😀", "😂", "😍", "😎", "😢", "😡", "👍", "❤️", "🎉", "🔥"]
        for emoji in self.emoji_list:
            btn = tk.Button(emoji_frame, text=emoji, font=("Arial", 16), command=lambda e=emoji: self.insert_emoji(e))
            btn.pack(pady=2)

        # 右侧消息区
        msg_frame = tk.Frame(paned_window)
        paned_window.add(msg_frame)

        tk.Label(msg_frame, text="明文消息", font=("Arial", 10, "bold")).pack(pady=2)
        self.plain_text = scrolledtext.ScrolledText(msg_frame, height=15)
        self.plain_text.pack(fill=tk.BOTH, expand=True)

        tk.Label(msg_frame, text="密文消息(Hex)", font=("Arial", 10, "bold")).pack(pady=2)
        self.cipher_text = scrolledtext.ScrolledText(msg_frame, height=8, font=("Courier", 9))
        self.cipher_text.pack(fill=tk.BOTH, expand=True)

        # 底部输入
        input_frame = tk.Frame(root)
        input_frame.pack(pady=10, fill=tk.X, padx=10)

        self.msg_entry = tk.Entry(input_frame)
        self.msg_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        self.msg_entry.bind("<Return>", lambda e: self.send_message())

        tk.Button(input_frame, text="发送", command=self.send_message, bg="#2196F3", fg="white").pack(side=tk.LEFT)
        tk.Button(input_frame, text="发送文件", command=self.send_file, bg="#9C27B0", fg="white").pack(side=tk.LEFT,
                                                                                                       padx=5)
        tk.Button(input_frame, text="保存记录", command=self.save_chat, bg="#FF9800", fg="white").pack(side=tk.LEFT,
                                                                                                       padx=5)

    def connect_server(self):
        try:
            self.nickname = self.nickname_entry.get()
            if not self.nickname:
                messagebox.showwarning("警告", "请输入昵称")
                return

            key = self.key_entry.get()
            self.cipher_suite = XORCipher(key)

            ip = self.ip_entry.get()
            port = int(self.port_entry.get())

            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.client_socket.connect((ip, port))
            self.client_socket.send(self.nickname.encode('utf-8'))

            self.connected = True
            self.connect_btn.config(state=tk.DISABLED)
            self.disconnect_btn.config(state=tk.NORMAL)
            self.log_message("系统", "已连接到服务端")

            threading.Thread(target=self.receive_messages, daemon=True).start()
        except Exception as e:
            messagebox.showerror("错误", f"连接失败: {str(e)}")

    def disconnect_server(self):
        self.connected = False
        if self.client_socket:
            try:
                self.client_socket.close()
            except:
                pass
        self.connect_btn.config(state=tk.NORMAL)
        self.disconnect_btn.config(state=tk.DISABLED)
        self.log_message("系统", "已断开连接")

    def receive_messages(self):
        while self.connected:
            try:
                encrypted_data = self.client_socket.recv(4096)
                if not encrypted_data:
                    break

                decrypted_data = self.cipher_suite.decrypt(encrypted_data).decode('utf-8')
                self.log_message("收到", f"密文: {encrypted_data.hex()}\n明文: {decrypted_data}")
            except Exception as e:
                if self.connected:
                    self.log_message("系统", f"接收错误: {str(e)}")
                break
        self.disconnect_server()

    def send_message(self):
        if not self.connected:
            messagebox.showwarning("警告", "未连接")
            return

        message = self.msg_entry.get()
        if not message:
            return

        full_msg = f"{self.nickname}: {message}"
        encrypted_msg = self.cipher_suite.encrypt(full_msg)
        self.client_socket.send(encrypted_msg)
        self.log_message("发送", f"密文: {encrypted_msg.hex()}\n明文: {full_msg}")
        self.msg_entry.delete(0, tk.END)

    def send_file(self):
        if not self.connected:
            messagebox.showwarning("警告", "未连接")
            return

        file_path = filedialog.askopenfilename()
        if not file_path:
            return

        filename = os.path.basename(file_path)
        self.log_message("系统", f"发送文件: {filename}")

        try:
            # 发送文件头
            file_header = f"FILE:{filename}"
            encrypted_header = self.cipher_suite.encrypt(file_header)
            self.client_socket.send(encrypted_header)

            # 发送文件大小
            file_size = os.path.getsize(file_path)
            encrypted_size = self.cipher_suite.encrypt(str(file_size))
            self.client_socket.send(encrypted_size)

            # 发送文件内容
            with open(file_path, 'rb') as f:
                content = f.read()
            encrypted_content = self.cipher_suite.encrypt(content)
            self.client_socket.send(encrypted_content)

            self.log_message("系统", f"文件发送成功")
        except Exception as e:
            messagebox.showerror("错误", f"发送失败: {str(e)}")

    def insert_emoji(self, emoji):
        self.msg_entry.insert(tk.END, emoji)

    def log_message(self, type, content):
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.plain_text.insert(tk.END, f"[{timestamp}] {type}:\n{content}\n\n")
        self.plain_text.see(tk.END)
        if "密文:" in content:
            cipher_part = content.split("密文:")[1].split("\n")[0]
            self.cipher_text.insert(tk.END, f"[{timestamp}] {type}: {cipher_part}\n")
            self.cipher_text.see(tk.END)

    def save_chat(self):
        file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])
        if file_path:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write("=== 明文记录 ===\n")
                f.write(self.plain_text.get(1.0, tk.END))
                f.write("\n=== 密文记录 ===\n")
                f.write(self.cipher_text.get(1.0, tk.END))
            messagebox.showinfo("成功", "记录已保存")

    def change_font(self):
        size = simpledialog.askinteger("字体", "输入大小:", initialvalue=10)
        if size:
            self.plain_text.config(font=("Arial", size))
            self.cipher_text.config(font=("Courier", size - 2))

    def change_bg_color(self):
        color = colorchooser.askcolor()[1]
        if color:
            self.plain_text.config(bg=color)
            self.cipher_text.config(bg=color)

    def show_help(self):
        help_text = "1. 服务端先启动,设置密钥\n2. 客户端输入相同密钥连接\n3. 可发送消息、文件、表情\n4. 支持保存记录和个性化设置"
        messagebox.showinfo("帮助", help_text)


if __name__ == "__main__":
    root = tk.Tk()
    app = ClientGUI(root)
    root.mainloop()
交互照片

屏幕截图 2026-04-29 091654

2.8 ai代码分析
这是一套基于 Python 原生库实现的加密 Socket 通信系统,包含服务端和客户端,无需安装任何第三方依赖。系统采用图形界面(GUI)设计,支持多客户端并发连接、加密消息传输、加密文件传输、聊天记录保存、个性化设置等功能。
2.8.1核心加密模块 (XORCipher)
使用 Python 内置的异或加密算法

点击查看代码
class XORCipher:
    def __init__(self, key):
        # 将字符串密钥转换为字节数组,用于后续的字节级运算
        self.key = key.encode('utf-8')
    
    def encrypt(self, data):
        # 统一处理输入:如果是字符串,先转为字节;如果已经是字节(如文件内容),直接使用
        if isinstance(data, str):
            data = data.encode('utf-8')
        
        # 核心加密逻辑:
        # 1. 循环使用密钥字节 (i % len(self.key))
        # 2. 对每个数据字节进行异或运算 (b ^ key_byte)
        # 3. 将结果重新组装为字节数组
        return bytes([b ^ self.key[i % len(self.key)] for i, b in enumerate(data)])
    
    def decrypt(self, data):
        # 异或加密的核心特性:A ^ B ^ B = A
        # 因此解密和加密是完全相同的操作,直接复用encrypt方法
        return self.encrypt(data)

2.8.2服务端功能模块
用多线程函数,进行后台运行,daemon设置为守护线程,当主程序退出时线程自动结束
更新UI状态


        self.start_btn.config(state=tk.DISABLED)
        self.stop_btn.config(state=tk.NORMAL)
        self.log_message("系统", f"服务端启动,端口 {port},密钥已更新")

2.8.3文件处理

 #  判断数据类型:
            #    - 如果以"FILE:"开头,说明是文件传输
            #    - 否则是普通文本消息
            if decrypted_data.startswith("FILE:"):
                # 提取文件名(去掉"FILE:"前缀)
                filename = decrypted_data[5:]
                self.receive_file(client_socket, filename, nickname, cipher)
            else:
                # 记录日志(同时显示密文Hex和明文)
                self.log_message(nickname, f"密文: {encrypted_data.hex()}\n明文: {decrypted_data}")
                # 转发给其他所有客户端
                self.forward_message(encrypted_data, client_socket)
        except Exception as e:
            self.log_message("系统", f"客户端 {nickname} 错误: {str(e)}")
            break

2.8.4个性化设置


def change_font(self):
    # 弹出对话框让用户输入字体大小
    size = simpledialog.askinteger("字体", "输入大小:", initialvalue=10)
    if size:
        # 修改明文区字体(Arial)
        self.plain_text.config(font=("Arial", size))
        # 修改密文区字体(Courier等宽字体,适合显示Hex)
        self.cipher_text.config(font=("Courier", size-2))

def change_bg_color(self):
    # 弹出颜色选择器
    color = colorchooser.askcolor()[1]  # 返回值:((R,G,B), '#Hex')
    if color:
        # 同时修改两个文本区的背景色
        self.plain_text.config(bg=color)
        self.cipher_text.config(bg=color)

2.8.5发送表情包

self.emoji_list = ["😀", "😂", "😍", "😎", "😢", "😡", "👍", "❤️", "🎉", "🔥"]
for emoji in self.emoji_list:
    btn = tk.Button(emoji_frame, text=emoji, command=lambda e=emoji: self.insert_emoji(e))

2.8.6发送文件功能
通过发送文件名,数据大小,以字节流的形式发送文件,再在另一端合成文件,实现文件传输。

# 发送文件头
encrypted_header = self.cipher_suite.encrypt(f"FILE:{filename}")
self.client_socket.send(encrypted_header)

# 发送文件大小
encrypted_size = self.cipher_suite.encrypt(str(file_size))

# 发送文件内容
encrypted_content = self.cipher_suite.encrypt(content)

2.9 ai代码的优点对比
1.图形化 GUI 界面,操作直观人性化
2.拓展加密文件传输功能
3.自带广播通信 + 在线用户监控,功能更丰富
4.完整日志持久化,数据可保存追溯
5.程序容错性强,运行稳定不易崩溃
6.代码模块化分层,结构清晰易读
7.有发送表情包功能,更利于沟通

我的代码和ai生成的根本不是一个级别的,缺点明显,功能单一,结构混乱,容易崩溃

2.10代码上传云

我的仓库

屏幕截图 2026-04-29 213756
屏幕截图 2026-04-29 213802
屏幕截图 2026-04-29 213807
屏幕截图 2026-04-29 213812

3. 实验过程中遇到的问题和解决过程

  • 问题1:多个客户端不可以同时连接我的服务器
  • 问题1解决方案:通过询问ai解决办法,发现引进threading解决多线程的问题
  • 问题2:不知道怎么设置IP地址,与同学连接不上
  • 问题2解决方案:通过学习B站教程,逐步跟着学习,解决问题
  • 问题3:与同学ping连接不成功
  • 问题3解决方案:通过Windows报错,关闭防火墙解决问题
  • ...

其他(感悟、思考等)

本次 Socket 网络通信实验,让我直观理解了 TCP 套接字的通信原理,明白了服务端监听、客户端连接、数据收发的完整网络交互流程。以往只掌握基础Python语法,本次实验结合了网络编程、数据加密、多线程、文件读写等多个知识点,让我学会将零散的语法知识结合起来,实现完整的功能项目。
实验过程中也让我意识到网络通信的细节和难点,单线程服务端存在很大局限性,无法满足多用户使用需求,而多线程可以有效解决并发问题,这也让我理解了后台服务并发运行的底层逻辑。同时简单的加密算法让我了解到网络数据传输的安全性意义,原始明文传输存在风险,简单加密即可有效保护通信数据。
通过和同学互相搭建服务端与客户端完成联机测试,提升了我的实操能力与排错思维。本次实验不仅巩固了Python编程能力,也让我对计算机网络通信机制有了更深刻的认知,为后续网络编程学习打下了良好基础。

参考资料

posted @ 2026-04-29 21:45  山阁老  阅读(23)  评论(4)    收藏  举报