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语言编程创建服务端和客户端
image
image
2.客户端和服务端进行通信
(1)寻找合作对象
(2)与合作对象连接相同网络,并在终端查看IP地址;
image
(3)与合作对象修改相同IP地址
image
(4)作为服务端运行代码并对话
c426f05896b15a85109da27c5d8bb5ba
(5)作为客户端运行代码并对话
38d72339d2bd2b9a5e6d706152b01ea4

项目二:使用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('', lambda e: self.broadcast_message())

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('', lambda e: self.send_message())
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.运行过程和结果截图展示
服务端
9533fde5c696c06f3bfbda44b411de18
客户端
722cfbe48d1522da82668e3e58056379

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

  • 问题1:连接过程中出现无法连接错误
  • 问题1解决方案:通过检查发现代码中IP地址未与实际统一,修改后解决
  • 问题2:LLM生成代码难以理解
  • 问题2解决方案:利用AI自己进行分析解释

其他(感悟、思考等)

1.实验过程需要保证网络,IP地址等各个部分不出错才能成功,这让我明白我们做实验一定要耐心细致,同时面对实验中的困难,两个人共同研究,互帮互助也让我明白团队协作的重要。
2.此次实验代码复杂,提醒我要努力学习,了解各个部分代码的作用,这样才有利于我们更好使用相关程序。

参考资料

  • ...
posted @ 2026-05-05 14:42  2YH  阅读(10)  评论(0)    收藏  举报