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
通信成功,加密成功
修改ip地址后的通信截图:
image

(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('', 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
image

实现了图形化,但是个人认为图形化界面有些老套,不够美观

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

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

其他(感悟、思考等)

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

posted @ 2026-05-06 14:41  wm129  阅读(10)  评论(4)    收藏  举报