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

学号 2025-2026-2 《Python程序设计》实验三报告

课程:《Python程序设计》
班级: 2523
姓名: 万书林
学号:20252307
实验教师:王志强
实验日期:2026年4月27日
必修/选修: 公选课

1.实验内容

(1)使用 Python 语言基于 TCP Socket 实现服务端与客户端网络通信程序
(2)实现明文输入→加密传输→接收解密功能,收发双方同时显示明文与密文(使用凯撒密码实现简单加密)
(3)加入文件操作,可保存聊天记录到文件
(5)使用 LLM 生成图形界面(GUI)版本,实现可视化加密聊天
(6)在 Windows 物理机上完成服务端与客户端通信,并与队友(学号:20252435,姓名:赵振为(其服务端ip为192.168.43.35))互相通信
(7)将所有代码托管至码云平台

2. 实验过程及结果

(1)程序设计源代码:
import socket
def caesar_encrypt_decrypt(text: str, shift: int) -> str:
result = []
for char in text:
if 32 <= ord(char) <= 126:
new_code = ord(char) + shift
if new_code > 126:
new_code -= 95
elif new_code < 32:
new_code += 95
result.append(chr(new_code))
return ''.join(result)
SHIFT = 3

创建TCP Socket对象(买手机)

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

HOST="0.0.0.0"#代表本机
PORT=8888
server.bind((HOST,PORT))#绑定(插卡)
server.listen(1)
print("服务器已经启动,等待客户端连接……")

conn,addr=server.accept()
print(f"已连接客户端:{addr}")

添加文件操作 - 打开记录文件

with open("record.txt", "a", encoding="utf-8") as f:
f.write(f"=== 聊天开始 - 客户端 {addr} 连接 ===\n")

while 1:

接收消息

data=conn.recv(1024).decode("utf-8")
if not data or data =="exit":
    print("聊天结束")
    # 记录聊天结束
    with open("record.txt", "a", encoding="utf-8") as f:
        f.write("=== 聊天结束 ===\n\n")
    break
plain_data = caesar_encrypt_decrypt(data, -SHIFT)
print(f"密文:{data}")
print(f"明文:{plain_data}")

# 记录接收到的消息
with open("record.txt", "a", encoding="utf-8") as f:
    f.write(f"[客户端] {plain_data}\n")

send_msg=input("我:")
encrypted_send = caesar_encrypt_decrypt(send_msg, SHIFT)
print(f"明文:{send_msg}")
print(f"密文:{encrypted_send}")
conn.send(encrypted_send.encode("utf-8"))

# 记录发送的消息
with open("record.txt", "a", encoding="utf-8") as f:
    f.write(f"[服务端] {send_msg}\n")

if send_msg=="exit":
    # 记录服务端主动结束聊天
    with open("record.txt", "a", encoding="utf-8") as f:
        f.write("=== 服务端结束聊天 ===\n\n")
    break

conn.close()
server.close()

import socket
import datetime
def caesar_encrypt_decrypt(text: str, shift: int) -> str:
result = []
for char in text:
if 32 <= ord(char) <= 126:
new_code = ord(char) + shift
if new_code > 126:
new_code -= 95
elif new_code < 32:
new_code += 95
result.append(chr(new_code))
return ''.join(result)
SHIFT = 3
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = "192.168.43.35"
PORT = 8888
client.connect((HOST, PORT))
print("已连接服务端!输入exit退出聊天!")

添加文件操作 - 打开记录文件(追加模式)

with open("record.txt", "a", encoding="utf-8") as f:
f.write(f"=== 聊天开始 - 连接服务端 {HOST}:{PORT} ===\n")

while True:
#发送数据
send_msg=input("我:")
encrypted_send = caesar_encrypt_decrypt(send_msg, SHIFT)
print(f"明文:{send_msg}")
print(f"密文:{encrypted_send}")
client.send(encrypted_send.encode("utf-8"))

# 记录发送的消息
with open("record.txt", "a", encoding="utf-8") as f:
    f.write(f"[客户端] {send_msg}\n")

if send_msg=="exit":
    # 记录客户端主动结束聊天
    with open("record.txt", "a", encoding="utf-8") as f:
        f.write("=== 客户端结束聊天 ===\n\n")
    break

#接收数据
data=client.recv(1024).decode("utf-8")
if not data or data=="exit":
    print("聊天结束")
    # 记录聊天结束
    with open("record.txt", "a", encoding="utf-8") as f:
        f.write("=== 聊天结束 ===\n\n")
    break
plain_data = caesar_encrypt_decrypt(data, -SHIFT)
print(f"\n密文:{data}")
print(f"明文:{plain_data}")

# 记录接收到的消息
with open("record.txt", "a", encoding="utf-8") as f:
    f.write(f"[服务端] {plain_data}\n")

client.close()
(2)实验结果:(与20252435赵振为合作)
我作为服务端:
ScreenShot_2026-04-27_215049_265
通信成功,加密成功
我作为客户端:
ScreenShot_2026-04-27_220601_500
通信成功,加密成功
(3)利用LLM完成的GUI版本
源代码:import tkinter as tk
from tkinter import scrolledtext, messagebox
import socket
import threading

def caesar_encrypt_decrypt(text: str, shift: int) -> str:
"""凯撒加密解密函数"""
result = []
for char in text:
if 32 <= ord(char) <= 126:
new_code = ord(char) + shift
if new_code > 126:
new_code -= 95
elif new_code < 32:
new_code += 95
result.append(chr(new_code))
else:
result.append(char)
return ''.join(result)

class ChatGUI:
def init(self):
self.SHIFT = 3
self.client_socket = None
self.is_server = False
self.running = True

    # 创建主窗口
    self.root = tk.Tk()
    self.root.title("安全聊天程序 - 图形界面版")
    self.root.geometry("600x500")
    self.root.configure(bg='#f0f0f0')
    
    self.setup_gui()
    
def setup_gui(self):
    """设置图形界面"""
    # 连接设置框架
    connection_frame = tk.Frame(self.root, bg='#e0e0e0', pady=10)
    connection_frame.pack(fill=tk.X, padx=10, pady=5)
    
    tk.Label(connection_frame, text="选择角色:", bg='#e0e0e0').grid(row=0, column=0, padx=5)
    
    self.role_var = tk.StringVar(value="client")
    tk.Radiobutton(connection_frame, text="客户端", variable=self.role_var, 
                  value="client", bg='#e0e0e0').grid(row=0, column=1, padx=5)
    tk.Radiobutton(connection_frame, text="服务端", variable=self.role_var, 
                  value="server", bg='#e0e0e0').grid(row=0, column=2, padx=5)
    
    tk.Label(connection_frame, text="IP地址:", bg='#e0e0e0').grid(row=1, column=0, padx=5, pady=5)
    self.ip_entry = tk.Entry(connection_frame, width=15)
    self.ip_entry.insert(0, "127.0.0.1")
    self.ip_entry.grid(row=1, column=1, padx=5, pady=5)
    
    tk.Label(connection_frame, text="端口:", bg='#e0e0e0').grid(row=1, column=2, padx=5)
    self.port_entry = tk.Entry(connection_frame, width=10)
    self.port_entry.insert(0, "8888")
    self.port_entry.grid(row=1, column=3, padx=5)
    
    self.connect_btn = tk.Button(connection_frame, text="连接", command=self.toggle_connection,
                               bg='#4CAF50', fg='white', font=('Arial', 10, 'bold'))
    self.connect_btn.grid(row=1, column=4, padx=10)
    
    # 聊天显示区域
    chat_frame = tk.Frame(self.root, bg='white')
    chat_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
    
    self.chat_display = scrolledtext.ScrolledText(chat_frame, height=20, width=70,
                                                 state='disabled', bg='#fafafa')
    self.chat_display.pack(fill=tk.BOTH, expand=True)
    
    # 消息输入区域
    input_frame = tk.Frame(self.root, bg='#f0f0f0')
    input_frame.pack(fill=tk.X, padx=10, pady=5)
    
    tk.Label(input_frame, text="输入消息:", bg='#f0f0f0').pack(side=tk.LEFT)
    
    self.message_entry = tk.Entry(input_frame, width=50)
    self.message_entry.pack(side=tk.LEFT, padx=5)
    self.message_entry.bind('<Return>', lambda event: self.send_message())
    
    self.send_btn = tk.Button(input_frame, text="发送", command=self.send_message,
                            bg='#2196F3', fg='white', state='disabled')
    self.send_btn.pack(side=tk.LEFT, padx=5)
    
    # 状态栏
    self.status_var = tk.StringVar(value="准备就绪")
    status_bar = tk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, 
                         anchor=tk.W, bg='#e0e0e0')
    status_bar.pack(fill=tk.X, side=tk.BOTTOM)
    
def toggle_connection(self):
    """切换连接状态"""
    if self.connect_btn['text'] == "连接":
        self.start_connection()
    else:
        self.disconnect()

def start_connection(self):
    """开始连接"""
    try:
        port = int(self.port_entry.get())
        ip = self.ip_entry.get()
        
        if self.role_var.get() == "server":
            self.start_server(ip, port)
        else:
            self.connect_to_server(ip, port)
            
    except ValueError:
        messagebox.showerror("错误", "端口号必须是数字!")
    except Exception as e:
        messagebox.showerror("错误", f"连接失败: {str(e)}")

def start_server(self, host, port):
    """启动服务端"""
    def server_thread():
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.bind((host, port))
            self.server_socket.listen(1)
            
            self.root.after(0, lambda: self.update_status(f"服务端已启动,等待客户端连接..."))
            
            self.client_socket, addr = self.server_socket.accept()
            self.is_server = True
            self.running = True
            
            self.root.after(0, lambda: self.connection_established(f"客户端 {addr} 已连接"))
            self.receive_messages()
            
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", f"服务器错误: {str(e)}"))
    
    threading.Thread(target=server_thread, daemon=True).start()
    self.connect_btn.config(text="断开", bg='#f44336')
    self.ip_entry.config(state='disabled')
    self.port_entry.config(state='disabled')

def connect_to_server(self, host, port):
    """连接服务端"""
    try:
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect((host, port))
        self.is_server = False
        self.running = True
        
        self.connection_established(f"已连接到服务端 {host}:{port}")
        threading.Thread(target=self.receive_messages, daemon=True).start()
        
        self.connect_btn.config(text="断开", bg='#f44336')
        self.ip_entry.config(state='disabled')
        self.port_entry.config(state='disabled')
        
    except Exception as e:
        messagebox.showerror("错误", f"连接失败: {str(e)}")

def connection_established(self, message):
    """连接建立后的处理"""
    self.send_btn.config(state='normal')
    self.message_entry.config(state='normal')
    self.update_status(message)
    self.display_message("系统", f"{message},开始聊天吧!", "system")

def disconnect(self):
    """断开连接"""
    self.running = False
    if self.client_socket:
        try:
            self.client_socket.close()
        except:
            pass
    if hasattr(self, 'server_socket'):
        try:
            self.server_socket.close()
        except:
            pass
    
    self.connect_btn.config(text="连接", bg='#4CAF50')
    self.send_btn.config(state='disabled')
    self.ip_entry.config(state='normal')
    self.port_entry.config(state='normal')
    self.update_status("已断开连接")
    self.display_message("系统", "连接已断开", "system")

def send_message(self):
    """发送消息"""
    message = self.message_entry.get().strip()
    if not message:
        return
    
    if message.lower() == 'exit':
        self.disconnect()
        return
    
    try:
        encrypted_msg = caesar_encrypt_decrypt(message, self.SHIFT)
        self.client_socket.send(encrypted_msg.encode('utf-8'))
        
        self.display_message("我", message, "sent")
        self.message_entry.delete(0, tk.END)
        
    except Exception as e:
        messagebox.showerror("错误", f"发送失败: {str(e)}")

def receive_messages(self):
    """接收消息的线程函数"""
    while self.running:
        try:
            data = self.client_socket.recv(1024).decode('utf-8')
            if not data:
                break
            
            if data.lower() == 'exit':
                self.root.after(0, self.disconnect)
                break
            
            plain_data = caesar_encrypt_decrypt(data, -self.SHIFT)
            sender = "服务端" if self.is_server else "客户端"
            self.root.after(0, lambda: self.display_message(sender, plain_data, "received"))
            
        except:
            if self.running:
                self.root.after(0, self.disconnect)
            break

def display_message(self, sender, message, msg_type):
    """在聊天区域显示消息"""
    self.chat_display.config(state='normal')
    
    # 设置不同消息类型的颜色
    if msg_type == "sent":
        tag = "sent"
        prefix = "我: "
        color = "#0066cc"
    elif msg_type == "received":
        tag = "received"
        prefix = f"{sender}: "
        color = "#cc6600"
    else:
        tag = "system"
        prefix = "系统: "
        color = "#666666"
    
    # 配置标签样式
    self.chat_display.tag_config(tag, foreground=color)
    
    # 插入消息
    self.chat_display.insert(tk.END, prefix + message + "\n", tag)
    self.chat_display.config(state='disabled')
    self.chat_display.see(tk.END)

def update_status(self, message):
    """更新状态栏"""
    self.status_var.set(message)

def run(self):
    """运行程序"""
    self.root.mainloop()

if name == "main":
app = ChatGUI()
app.run()
运行效果:
image
实现了图形化,但是个人认为图形化界面有些老套,不够美观

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

  • 问题1:与队友联机时,多次失败
  • 问题1解决方案:调试网络,用一方笔记本的热点互联,最后成功

其他(感悟、思考等)

socket技术为我们的通信做出了巨大贡献,我们现在使用的微信,QQ等软件都是这样技术的结果
AI生成代码能力很强,编写的GUI效果好,速度快

参考资料

posted @ 2026-05-06 14:40  wm129  阅读(6)  评论(0)    收藏  举报