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

(2)在cmd里用ipconfig查看IP地址,并在操作面板里修改自己的IP地址;
(3)与队友(20254114刘小萌)一起修改代码里的服务器IP地址与端口号,并运行程序:
我作为服务端,HOST填我的IP,运行并等待对方连接,连接上即可进行跨设备通讯,成果如下图:

我作为客户端,HOST填队友的IP,运行并连接上对方,通讯结果如下图:

(4)代码托管地址:https://gitee.com/ping2127/python-games-ping2127/blob/master/SockeServer.py
要求2:
(1)让deepseek生成一个带图形界面的程序,以服务端为例,代码如下:
点击查看代码
# gui_server_stable.py - 稳定版服务端
# 实验三:Socket编程技术
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, messagebox
from datetime import datetime
import time
class StableServer:
def __init__(self):
"""初始化服务端"""
# ==========================================
# 👇 修改这里的信息
# ==========================================
self.student_name = "浦馨宇"
self.student_id = "20254119"
self.partner_name = "刘小萌"
self.partner_id = "20254114"
# ==========================================
# 创建窗口
self.window = tk.Tk()
self.window.title(f"服务端-{self.student_name}")
self.window.geometry("650x700")
# 网络设置
self.server_socket = None
self.client_socket = None
self.client_address = None
self.is_running = False
self.is_connected = False
# 重连设置
self.reconnect_attempts = 0 # 当前重连次数
self.max_reconnect = 10 # 最大重连次数
# 创建界面
self.setup_ui()
self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
self.window.after(500, self.show_my_ip)
def setup_ui(self):
"""设置界面"""
# 标题
title_frame = tk.Frame(self.window)
title_frame.pack(pady=10)
tk.Label(title_frame, text="Socket实验-服务端(稳定版)",
font=("Arial", 14, "bold")).pack()
tk.Label(title_frame,
text=f"姓名: {self.student_name} 学号: {self.student_id}",
font=("Arial", 10)).pack()
# IP显示
ip_frame = tk.Frame(self.window, relief=tk.RIDGE, borderwidth=2)
ip_frame.pack(pady=10, padx=20, fill=tk.X)
tk.Label(ip_frame, text="📡 本机IP(告诉队友)",
font=("Arial", 10, "bold"), fg="red").pack(pady=5)
self.ip_label = tk.Label(ip_frame, text="获取中...",
font=("Arial", 12), fg="blue")
self.ip_label.pack(pady=5)
# 控制区
control_frame = tk.Frame(self.window)
control_frame.pack(pady=10)
self.start_btn = tk.Button(control_frame, text="▶ 启动服务器",
command=self.toggle_server,
width=15, height=2, bg="lightgreen")
self.start_btn.pack(side=tk.LEFT, padx=10)
tk.Label(control_frame, text="端口:").pack(side=tk.LEFT)
self.port_entry = tk.Entry(control_frame, width=8)
self.port_entry.insert(0, "8888")
self.port_entry.pack(side=tk.LEFT, padx=5)
# 连接信息
info_frame = tk.Frame(self.window)
info_frame.pack(pady=5)
self.conn_info_label = tk.Label(info_frame, text="", fg="gray")
self.conn_info_label.pack()
# 消息显示区
tk.Label(self.window, text="通信记录:",
font=("Arial", 10, "bold")).pack(anchor=tk.W, padx=20)
self.msg_area = scrolledtext.ScrolledText(
self.window, height=18, width=70, state='disabled')
self.msg_area.pack(padx=20, pady=5)
# 发送区
send_frame = tk.Frame(self.window)
send_frame.pack(padx=20, pady=5, fill=tk.X)
self.msg_entry = tk.Entry(send_frame, width=55, font=("Arial", 11))
self.msg_entry.pack(side=tk.LEFT, padx=5)
self.msg_entry.bind('<Return>', self.send_message)
self.send_btn = tk.Button(send_frame, text="发送",
command=self.send_message,
width=8, bg="lightblue", state='disabled')
self.send_btn.pack(side=tk.LEFT, padx=5)
# 状态栏
self.status_label = tk.Label(self.window, text="🔴 服务器未启动",
font=("Arial", 10), fg="red")
self.status_label.pack(pady=10)
def show_my_ip(self):
"""显示本机IP"""
try:
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
# 获取真实IP
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
real_ip = s.getsockname()[0]
s.close()
except:
real_ip = local_ip
self.ip_label.config(
text=f"IP: {real_ip} 端口: {self.port_entry.get()}")
except Exception as e:
self.ip_label.config(text=f"获取失败: {e}")
def log_message(self, message, msg_type="系统"):
"""显示消息"""
self.msg_area.config(state='normal')
time_str = datetime.now().strftime("%H:%M:%S")
colors = {
"接收": ("📩 队友:", "blue"),
"发送": ("📤 我:", "green"),
"成功": ("✅", "green"),
"错误": ("❌", "red"),
"警告": ("⚠️", "orange")
}
if msg_type in colors:
prefix, color = colors[msg_type]
self.msg_area.insert(tk.END, f"[{time_str}] {prefix} {message}\n", msg_type)
self.msg_area.tag_config(msg_type, foreground=color)
else:
self.msg_area.insert(tk.END, f"[{time_str}] ℹ️ {message}\n")
self.msg_area.see(tk.END)
self.msg_area.config(state='disabled')
def toggle_server(self):
"""切换服务器状态"""
if not self.is_running:
self.start_server()
else:
self.stop_server()
def start_server(self):
"""启动服务器"""
try:
port = int(self.port_entry.get())
# 创建socket,设置更多选项
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 设置keepalive(保持连接)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
self.server_socket.bind(('0.0.0.0', port))
self.server_socket.listen(5)
self.is_running = True
self.start_btn.config(text="⏹ 停止服务器", bg="lightcoral")
self.port_entry.config(state='disabled')
self.status_label.config(text="🟢 服务器运行中-等待连接...", fg="green")
self.show_my_ip()
self.log_message("=" * 50, "系统")
self.log_message(f"服务器启动成功!端口: {port}", "成功")
self.log_message(f"服务端: {self.student_name}({self.student_id})", "系统")
self.log_message(f"等待队友 {self.partner_name} 连接...", "系统")
self.log_message("=" * 50, "系统")
# 启动接受连接的线程
accept_thread = threading.Thread(target=self.accept_clients, daemon=True)
accept_thread.start()
except Exception as e:
messagebox.showerror("启动失败", f"错误: {e}")
def stop_server(self):
"""停止服务器"""
self.is_running = False
self.is_connected = False
# 关闭客户端连接
if self.client_socket:
try:
self.client_socket.shutdown(socket.SHUT_RDWR)
self.client_socket.close()
except:
pass
self.client_socket = None
# 关闭服务器
if self.server_socket:
try:
self.server_socket.close()
except:
pass
self.server_socket = None
self.start_btn.config(text="▶ 启动服务器", bg="lightgreen")
self.send_btn.config(state='disabled')
self.port_entry.config(state='normal')
self.conn_info_label.config(text="")
self.status_label.config(text="🔴 服务器已停止", fg="red")
self.log_message("服务器已停止", "系统")
def accept_clients(self):
"""接受客户端连接(循环接受,支持重连)"""
while self.is_running:
try:
self.server_socket.settimeout(1)
# 如果已有连接,跳过
if self.is_connected and self.client_socket:
time.sleep(0.5)
continue
# 接受新连接
client_socket, address = self.server_socket.accept()
# 设置客户端socket选项
client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
client_socket.settimeout(30) # 30秒超时
self.client_socket = client_socket
self.client_address = address
self.is_connected = True
self.reconnect_attempts = 0
self.log_message(f"队友已连接!地址: {address}", "成功")
self.conn_info_label.config(
text=f"已连接: {address[0]}:{address[1]}", fg="green")
self.status_label.config(text="🟢 队友在线-可以聊天!", fg="green")
self.send_btn.config(state='normal')
self.msg_entry.focus()
# 启动接收线程
receive_thread = threading.Thread(
target=self.receive_messages,
args=(client_socket, address),
daemon=True
)
receive_thread.start()
# 启动心跳线程
heartbeat_thread = threading.Thread(
target=self.send_heartbeat,
args=(client_socket,),
daemon=True
)
heartbeat_thread.start()
except socket.timeout:
continue
except Exception as e:
if self.is_running:
self.log_message(f"接受连接出错: {e}", "错误")
time.sleep(1)
def send_heartbeat(self, client_socket):
"""发送心跳包保持连接"""
while self.is_connected and self.is_running:
try:
# 每10秒发送一个心跳包
time.sleep(10)
if self.is_connected:
client_socket.send(b'HEARTBEAT')
except:
break
def receive_messages(self, client_socket, address):
"""接收客户端消息"""
buffer = "" # 消息缓冲区
while self.is_connected and self.is_running:
try:
data = client_socket.recv(1024)
if not data:
# 连接断开
break
message = data.decode('utf-8')
# 过滤心跳包
if message == "HEARTBEAT":
continue
# 显示消息
self.log_message(message, "接收")
except socket.timeout:
# 超时,继续等待
continue
except ConnectionResetError:
self.log_message("连接被重置", "警告")
break
except Exception as e:
self.log_message(f"接收错误: {e}", "错误")
break
# 处理断开
self.handle_disconnect(address)
def handle_disconnect(self, address):
"""处理客户端断开"""
self.is_connected = False
if self.client_socket:
try:
self.client_socket.close()
except:
pass
self.client_socket = None
self.send_btn.config(state='disabled')
self.conn_info_label.config(text="")
if self.is_running:
self.log_message(f"队友 {address} 断开连接", "警告")
self.log_message("等待队友重新连接...", "系统")
self.status_label.config(text="🟡 队友断开-等待重连...", fg="orange")
def send_message(self, event=None):
"""发送消息"""
if not self.is_connected or not self.client_socket:
messagebox.showwarning("未连接", "请等待队友连接后再发送消息")
return
message = self.msg_entry.get().strip()
if not message:
return
try:
# 发送消息
self.client_socket.send(message.encode('utf-8'))
# 显示发送的消息
self.log_message(message, "发送")
# 清空输入框
self.msg_entry.delete(0, tk.END)
except ConnectionResetError:
self.log_message("发送失败-连接断开", "错误")
self.handle_disconnect(self.client_address if self.client_address else "未知")
except Exception as e:
self.log_message(f"发送失败: {e}", "错误")
def on_closing(self):
"""关闭窗口"""
if messagebox.askokcancel("退出", "确定要退出吗?"):
self.stop_server()
self.window.destroy()
def run(self):
"""运行"""
self.window.mainloop()
if __name__ == "__main__":
server = StableServer()
server.run()
(2)分析关键代码的功能及用法:
①导入的库:
import socket # 网络通信核心库,创建TCP/UDP连接
import threading # 多线程库,让程序同时做多件事
import tkinter as tk # GUI图形界面库,创建窗口按钮等
from tkinter import scrolledtext, messagebox # 滚动文本框+弹窗
from datetime import datetime # 获取当前时间,用于消息时间提示
import time # 时间相关,用于延时等待
②心跳保活,防止通讯一段时间不用就自己断开
while self.is_connected:
time.sleep(10) # 等10秒
client_socket.send(b'HEARTBEAT') # 发心跳包
message = data.decode('utf-8')
# 过滤心跳包,在接受信息之后不显示心跳包的内容,保持通讯界面简洁
if message == "HEARTBEAT":
continue
③搭建界面
# 标题区域
title_frame = tk.Frame(self.window) # 创建一个框架(容器)
title_frame.pack(pady=10) # 放到窗口里,上下留10像素间距
# 创建标签(显示文字)
tk.Label(title_frame, text="Socket实验-服务端(稳定版)",
font=("Arial", 14, "bold")).pack()
④创建TCP服务器,大部分已在前面分析过,所以着重分析LLM新增的
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# SO_REUSEADDR: 允许重用地址,避免"端口被占用"错误
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
# SO_KEEPALIVE: 保持连接活跃,防止长时间不通信断连
(3)运行过程和结果:
我做服务端:

我做客户端

可以看到V1.0程序最大的缺陷是没给服务端添加发送信息的功能,改进的V3.0结果如下:

(4)分析LLM代码的优点:
①从运行窗口变为可视化窗口,窗口界面上会实时显示连接状态,操作易懂简便;
②可以自动获取本机的IP地址,不需要再自己查一遍;
③bind绑定的元组变成('0.0.0.0', port),可以监听所有网络接口;同时可以在窗口上直接输入IP地址和改端口号,不用每换一个人就改一遍代码;
④具备心跳保护、超时等待、自动重连和应对消息发送失败等丰富的错误应对机制,稳定性很强;
(5)代码托管地址:
服务端:https://gitee.com/ping2127/python-games-ping2127/blob/master/deepseek_python_socket(服务端3.0).py
客户端:https://gitee.com/ping2127/python-games-ping2127/blob/master/deepseek_python_socket(客户端3.0).py
3. 实验过程中遇到的问题和解决过程
- 问题1:最开始链接的时候对方的客户端无法连接到服务器。
- 问题1解决方案:检查两人的端口号和IP地址是否一致,发现不一致后改正,并先启动服务器再启动客户端,后来连接成功。
- 问题2:在LLM代码运行过程中发现了第一次生成的代码出现无法做到通讯的问题。
- 问题2解决方案:找出代码中的问题所在是没有己方消息输入的设计,并让大模型重新添加输入消息的代码板块。
其他(感悟、思考等)
这次实验带给我很大的一个感悟就是它开启了我学习Python的一扇新的大门。以前我有过学Python的基础,但都只停留在解决数学问题或是设计小游戏等,并不像这一次实验内容那么实用和深入。它让我见识到Python里边儿还有像socket的库这样功能十分丰富的库,也让我理解了Python能够调用库是多么方便。同时还让我发现,我对Python的学习其实只有皮毛,编程可以带来的自由和实惠内容非常广阔,这坚定了我把Python程序设计学好学扎实的信念。
浙公网安备 33010602011771号