20254110 2025-2026-2 《Python程序设计》实验3报告
20254110 2025-2026-2 《Python程序设计》实验3报告
课程:《Python程序设计》
班级: 2541
姓名: 杨永恒
学号:20254110
实验教师:王志强
实验日期:2026年4月28日
必修/选修: 专选课
1.实验内容
创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。
项目一
(1)创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
(2)要求发送方输入内容,并传输;接收方收到信息并显示。
项目二:使用LLM生成一个带图形界面的程序
(1)分析关键代码的功能和使用方法
(2)分析生成程序的优点
(3)给出运行过程和结果截图
2. 实验过程及结果
项目一
1.用Python语言编程创建服务端和客户端


2.客户端和服务端进行通信
(1)寻找合作对象
(2)与合作对象连接相同网络,并在终端查看IP地址;

(3)与合作对象修改相同IP地址

(4)作为服务端运行代码并对话

(5)作为客户端运行代码并对话

项目二:使用LLM生成一个带图形界面的程序
1.使用LLM生成程序
服务端:
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, messagebox
from datetime import datetime
class ServerGUI:
def init(self, host='172.20.10.10', port=8888):
self.host = host
self.port = port
self.server_socket = None
self.clients = [] # 存储客户端连接
self.client_addresses = {} # 存储客户端地址
创建主窗口
self.window = tk.Tk()
self.window.title(f"TCP服务器 - {host}:{port}")
self.window.geometry("600x500")
创建界面组件
self.create_widgets()
def create_widgets(self):
"""创建GUI组件"""
# 状态栏
self.status_frame = tk.Frame(self.window)
self.status_frame.pack(fill=tk.X, padx=5, pady=5)
self.status_label = tk.Label(self.status_frame, text="服务器未启动",
fg="red", font=("Arial", 10))
self.status_label.pack(side=tk.LEFT)
self.client_count_label = tk.Label(self.status_frame, text="客户端数: 0",
font=("Arial", 10))
self.client_count_label.pack(side=tk.RIGHT)
控制按钮
self.control_frame = tk.Frame(self.window)
self.control_frame.pack(fill=tk.X, padx=5, pady=5)
self.start_btn = tk.Button(self.control_frame, text="启动服务器",
command=self.start_server, bg="green", fg="white")
self.start_btn.pack(side=tk.LEFT, padx=5)
self.stop_btn = tk.Button(self.control_frame, text="停止服务器",
command=self.stop_server, bg="red", fg="white",
state=tk.DISABLED)
self.stop_btn.pack(side=tk.LEFT, padx=5)
消息显示区域
self.log_frame = tk.LabelFrame(self.window, text="通信日志", padx=5, pady=5)
self.log_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.log_area = scrolledtext.ScrolledText(self.log_frame, height=20,
width=70, font=("Consolas", 10))
self.log_area.pack(fill=tk.BOTH, expand=True)
消息发送区域
self.send_frame = tk.Frame(self.window)
self.send_frame.pack(fill=tk.X, padx=5, pady=5)
self.msg_entry = tk.Entry(self.send_frame, font=("Arial", 10))
self.msg_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
self.msg_entry.bind('
self.send_btn = tk.Button(self.send_frame, text="广播消息",
command=self.broadcast_message, state=tk.DISABLED)
self.send_btn.pack(side=tk.RIGHT)
def log_message(self, message, msg_type="INFO"):
"""记录日志消息"""
timestamp = datetime.now().strftime("%H:%M:%S")
color_tags = {"INFO": "black", "ERROR": "red", "SUCCESS": "green",
"MESSAGE": "blue"}
self.log_area.insert(tk.END, f"[{timestamp}] ", "timestamp")
self.log_area.insert(tk.END, f"[{msg_type}] ", msg_type)
self.log_area.insert(tk.END, f"{message}\n", color_tags.get(msg_type, "black"))
self.log_area.see(tk.END)
配置文本颜色
self.log_area.tag_config("timestamp", foreground="gray")
self.log_area.tag_config("INFO", foreground="black")
self.log_area.tag_config("ERROR", foreground="red")
self.log_area.tag_config("SUCCESS", foreground="green")
self.log_area.tag_config("MESSAGE", foreground="blue")
def update_client_count(self):
"""更新客户端数量显示"""
self.client_count_label.config(text=f"客户端数: {len(self.clients)}")
def start_server(self):
"""启动服务器"""
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.host, self.port))
self.server_socket.listen(5)
self.server_socket.settimeout(1) # 设置超时以便能响应停止命令
启动接受连接的线程
self.accept_thread = threading.Thread(target=self.accept_clients, daemon=True)
self.accept_thread.start()
self.start_btn.config(state=tk.DISABLED)
self.stop_btn.config(state=tk.NORMAL)
self.send_btn.config(state=tk.NORMAL)
self.status_label.config(text="服务器运行中", fg="green")
self.log_message(f"服务器已启动,监听 {self.host}:{self.port}", "SUCCESS")
except Exception as e:
self.log_message(f"启动服务器失败: {e}", "ERROR")
messagebox.showerror("错误", f"无法启动服务器: {e}")
def accept_clients(self):
"""接受客户端连接的线程"""
while self.server_socket:
try:
client_socket, client_address = self.server_socket.accept()
为新客户端创建线程
client_thread = threading.Thread(
target=self.handle_client,
args=(client_socket, client_address),
daemon=True
)
client_thread.start()
self.clients.append(client_socket)
self.client_addresses[client_socket] = client_address
self.update_client_count()
self.log_message(f"新客户端连接: {client_address[0]}:{client_address[1]}",
"SUCCESS")
发送欢迎消息
welcome_msg = f"欢迎连接到服务器!当前在线人数: {len(self.clients)}"
client_socket.send(welcome_msg.encode('utf-8'))
except socket.timeout:
continue
except Exception as e:
if self.server_socket: # 服务器还在运行
self.log_message(f"接受连接错误: {e}", "ERROR")
break
def handle_client(self, client_socket, client_address):
"""处理客户端消息"""
try:
while True:
data = client_socket.recv(1024)
if not data:
break
message = data.decode('utf-8')
self.log_message(f"来自 {client_address[0]}:{client_address[1]}: {message}",
"MESSAGE")
广播消息给所有客户端
self.broadcast_to_clients(f"{client_address[1]}: {message}", client_socket)
except Exception as e:
self.log_message(f"客户端 {client_address[1]} 连接错误: {e}", "ERROR")
finally:
# 清理断开连接的客户端
if client_socket in self.clients:
self.clients.remove(client_socket)
del self.client_addresses[client_socket]
self.update_client_count()
self.log_message(f"客户端 {client_address[1]} 已断开连接", "INFO")
client_socket.close()
def broadcast_to_clients(self, message, sender_socket=None):
"""广播消息给所有客户端"""
disconnected_clients = []
for client in self.clients:
if client != sender_socket: # 不发送给发送者
try:
client.send(message.encode('utf-8'))
except:
disconnected_clients.append(client)
清理断开连接的客户端
for client in disconnected_clients:
if client in self.clients:
self.clients.remove(client)
self.update_client_count()
def broadcast_message(self):
"""从GUI广播消息"""
message = self.msg_entry.get().strip()
if message and self.clients:
broadcast_msg = f"[服务器广播]: {message}"
self.broadcast_to_clients(broadcast_msg)
self.log_message(f"服务器广播: {message}", "INFO")
self.msg_entry.delete(0, tk.END)
elif not self.clients:
self.log_message("没有客户端连接,无法广播消息", "ERROR")
def stop_server(self):
"""停止服务器"""
try:
# 关闭所有客户端连接
for client in self.clients[:]:
try:
client.close()
except:
pass
self.clients.clear()
self.client_addresses.clear()
关闭服务器socket
if self.server_socket:
self.server_socket.close()
self.server_socket = None
self.start_btn.config(state=tk.NORMAL)
self.stop_btn.config(state=tk.DISABLED)
self.send_btn.config(state=tk.DISABLED)
self.status_label.config(text="服务器已停止", fg="red")
self.update_client_count()
self.log_message("服务器已停止", "SUCCESS")
except Exception as e:
self.log_message(f"停止服务器错误: {e}", "ERROR")
def run(self):
"""运行GUI主循环"""
self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
self.window.mainloop()
def on_closing(self):
"""关闭窗口时的清理工作"""
self.stop_server()
self.window.destroy()
if name == "main":
server = ServerGUI(host='172.20.10.10', port=8888)
server.run()
客户端:
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, messagebox, simpledialog
from datetime import datetime
class ClientGUI:
def init(self):
self.client_socket = None
self.connected = False
连接参数
self.server_host = '172.20.10.3'
self.server_port = 8888
创建主窗口
self.window = tk.Tk()
self.window.title("TCP客户端")
self.window.geometry("550x450")
self.create_widgets()
def create_widgets(self):
"""创建GUI组件"""
# 连接设置框架
self.conn_frame = tk.LabelFrame(self.window, text="连接设置", padx=5, pady=5)
self.conn_frame.pack(fill=tk.X, padx=5, pady=5)
tk.Label(self.conn_frame, text="服务器IP:").grid(row=0, column=0, sticky=tk.W)
self.host_entry = tk.Entry(self.conn_frame, width=15)
self.host_entry.insert(0, "172.20.10.3")
self.host_entry.grid(row=0, column=1, padx=5)
tk.Label(self.conn_frame, text="端口:").grid(row=0, column=2, sticky=tk.W)
self.port_entry = tk.Entry(self.conn_frame, width=6)
self.port_entry.insert(0, "8888")
self.port_entry.grid(row=0, column=3, padx=5)
self.connect_btn = tk.Button(self.conn_frame, text="连接服务器",
command=self.connect_server, bg="blue", fg="white")
self.connect_btn.grid(row=0, column=4, padx=5)
self.disconnect_btn = tk.Button(self.conn_frame, text="断开连接",
command=self.disconnect_server,
bg="red", fg="white", state=tk.DISABLED)
self.disconnect_btn.grid(row=0, column=5, padx=5)
状态显示
self.status_frame = tk.Frame(self.window)
self.status_frame.pack(fill=tk.X, padx=5, pady=5)
self.status_label = tk.Label(self.status_frame, text="未连接",
fg="red", font=("Arial", 10))
self.status_label.pack(side=tk.LEFT)
消息显示区域
self.msg_frame = tk.LabelFrame(self.window, text="聊天记录", padx=5, pady=5)
self.msg_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.msg_area = scrolledtext.ScrolledText(self.msg_frame, height=20,
width=65, font=("Consolas", 10))
self.msg_area.pack(fill=tk.BOTH, expand=True)
消息输入区域
self.send_frame = tk.Frame(self.window)
self.send_frame.pack(fill=tk.X, padx=5, pady=5)
self.msg_entry = tk.Entry(self.send_frame, font=("Arial", 10))
self.msg_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
self.msg_entry.bind('
self.msg_entry.config(state=tk.DISABLED)
self.send_btn = tk.Button(self.send_frame, text="发送消息",
command=self.send_message, state=tk.DISABLED)
self.send_btn.pack(side=tk.RIGHT)
def log_message(self, message, msg_type="INFO"):
"""记录消息到聊天区域"""
timestamp = datetime.now().strftime("%H:%M:%S")
color_tags = {"INFO": "black", "ERROR": "red", "SUCCESS": "green",
"RECEIVED": "blue", "SENT": "purple"}
self.msg_area.insert(tk.END, f"[{timestamp}] ", "timestamp")
self.msg_area.insert(tk.END, f"[{msg_type}] ", msg_type)
self.msg_area.insert(tk.END, f"{message}\n", color_tags.get(msg_type, "black"))
self.msg_area.see(tk.END)
配置文本颜色
self.msg_area.tag_config("timestamp", foreground="gray")
self.msg_area.tag_config("INFO", foreground="black")
self.msg_area.tag_config("ERROR", foreground="red")
self.msg_area.tag_config("SUCCESS", foreground="green")
self.msg_area.tag_config("RECEIVED", foreground="blue")
self.msg_area.tag_config("SENT", foreground="purple")
def connect_server(self):
"""连接到服务器"""
try:
self.server_host = self.host_entry.get()
self.server_port = int(self.port_entry.get())
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((self.server_host, self.server_port))
self.connected = True
启动接收消息的线程
self.receive_thread = threading.Thread(target=self.receive_messages, daemon=True)
self.receive_thread.start()
self.connect_btn.config(state=tk.DISABLED)
self.disconnect_btn.config(state=tk.NORMAL)
self.send_btn.config(state=tk.NORMAL)
self.msg_entry.config(state=tk.NORMAL)
self.status_label.config(text="已连接", fg="green")
self.log_message(f"成功连接到服务器 {self.server_host}:{self.server_port}",
"SUCCESS")
except Exception as e:
self.log_message(f"连接服务器失败: {e}", "ERROR")
messagebox.showerror("错误", f"无法连接到服务器: {e}")
def receive_messages(self):
"""接收服务器消息的线程"""
try:
while self.connected:
data = self.client_socket.recv(1024)
if not data:
break
message = data.decode('utf-8')
self.log_message(message, "RECEIVED")
except Exception as e:
if self.connected:
self.log_message(f"接收消息错误: {e}", "ERROR")
finally:
self.disconnect_server()
def send_message(self):
"""发送消息到服务器"""
message = self.msg_entry.get().strip()
if message and self.connected:
try:
self.client_socket.send(message.encode('utf-8'))
self.log_message(message, "SENT")
self.msg_entry.delete(0, tk.END)
except Exception as e:
self.log_message(f"发送消息失败: {e}", "ERROR")
self.disconnect_server()
elif not self.connected:
self.log_message("未连接到服务器,无法发送消息", "ERROR")
def disconnect_server(self):
"""断开服务器连接"""
if self.connected:
self.connected = False
if self.client_socket:
try:
self.client_socket.close()
except:
pass
self.client_socket = None
self.connect_btn.config(state=tk.NORMAL)
self.disconnect_btn.config(state=tk.DISABLED)
self.send_btn.config(state=tk.DISABLED)
self.msg_entry.config(state=tk.DISABLED)
self.status_label.config(text="未连接", fg="red")
self.log_message("已断开与服务器的连接", "INFO")
def on_closing(self):
"""关闭窗口时的清理"""
self.disconnect_server()
self.window.destroy()
def run(self):
"""运行客户端主循环"""
self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
self.window.mainloop()
if name == "main":
client = ClientGUI()
client.run()
2.分析生成程序的优点
(1)用户界面简介明了
(2)服务端能同时处理多个客户端,客户端能异步接收消息
(3)良好的错误处理能力
(4)服务器地址和端口可动态配置
3.运行过程和结果截图展示
服务端

客户端

3. 实验过程中遇到的问题和解决过程
- 问题1:连接过程中出现无法连接错误
- 问题1解决方案:通过检查发现代码中IP地址未与实际统一,修改后解决
- 问题2:LLM生成代码难以理解
- 问题2解决方案:利用AI自己进行分析解释
其他(感悟、思考等)
1.实验过程需要保证网络,IP地址等各个部分不出错才能成功,这让我明白我们做实验一定要耐心细致,同时面对实验中的困难,两个人共同研究,互帮互助也让我明白团队协作的重要。
2.此次实验代码复杂,提醒我要努力学习,了解各个部分代码的作用,这样才有利于我们更好使用相关程序。
参考资料
- ...
浙公网安备 33010602011771号