2024439 2025-2026-2 《Python程序设计》实验三报告
2024439 2025-2026-2 《Python程序设计》实验三报告
课程:《Python程序设计》
班级:2443
姓名: 黄至泓
学号:20244309
实验教师:王志强
实验日期:2026年4月27日
必修/选修: 公选课
1.实验内容
使用 Python 语言编写基于 Socket TCP 的服务端与客户端程序,实现局域网双向通信。消息采用凯撒密码加密传输,发送方与接收方均同时输出明文与密文。使用大模型生成带图形界面的通信程序,分析代码功能与程序优点。
2. 实验过程及结果
(一)环境与工具准备
本次实验使用 Python 语言,基于内置socket模块实现 TCP 通信,采用凯撒密码完成消息加解密,使用tkinter实现图形界面。实验在 Windows 系统下进行,服务端与客户端在局域网内完成互联,通信端口统一使用8887。
(二)服务端程序编写与运行
首先编写服务端代码,创建TCP套接字,将 IP 地址绑定为0.0.0.0以支持所有局域网设备接入,监听8887端口。程序启动后输出提示信息,等待客户端连接。当客户端接入时,服务端打印客户端地址并进入通信循环。服务端具备完整功能:接收客户端发来的密文,自动解密并同时显示密文与明文;读取控制台输入的消息,使用凯撒密码加密后发送,并在本地显示明文与密文。输入exit可正常退出聊天并关闭连接。代码如下:
import socket
def caesar_encrypt(text, offset=3):
result = ""
for char in text:
if char.isalpha():
ascii_offset = ord('a') if char.islower() else ord('A')
result += chr((ord(char) - ascii_offset + offset) % 26 + ascii_offset)
else:
result += char
return result
def caesar_decrypt(text, offset=3):
result = ""
for char in text:
if char.isalpha():
ascii_offset = ord('a') if char.islower() else ord('A')
result += chr((ord(char) - ascii_offset - offset) % 26 + ascii_offset)
else:
result += char
return result
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = "0.0.0.0"
PORT = 8886
server.bind((HOST, PORT))
server.listen(1)
print("服务端已启动,等待客户端连接...")
conn, addr = server.accept()
print(f"客户端 {addr} 已连接!输入 exit 退出")
while True:
data = conn.recv(1024).decode("utf-8")
if not data or data == "exit":
print("聊天结束")
break
decrypt_data = caesar_decrypt(data)
print(f"客户端密文:{data}")
print(f"客户端明文:{decrypt_data}\n")
send_msg = input("我:")
encrypt_msg = caesar_encrypt(send_msg)
conn.send(encrypt_msg.encode("utf-8"))
print(f"我发送的明文:{send_msg}")
print(f"我发送的密文:{encrypt_msg}\n")
if send_msg == "exit":
print("聊天结束")
break
conn.close()
server.close()
(三)客户端程序编写与运行
客户端代码通过socket连接服务端的局域网 IP 与 8886 端口,连接成功后提示已接入服务端。进入聊天循环后,客户端读取用户输入,先进行凯撒加密再发送,并在界面输出明文与密文;接收服务端消息后自动解密,同时显示收到的密文与解密后的明文。客户端同样支持exit退出,流程与服务端对称,保证收发逻辑一致、加解密结果正确。
代码如下:
import socket
def caesar_encrypt(text, offset=3):
result = ""
for char in text:
if char.isalpha():
ascii_offset = ord('a') if char.islower() else ord('A')
result += chr((ord(char) - ascii_offset + offset) % 26 + ascii_offset)
else:
result += char
return result
def caesar_decrypt(text, offset=3):
result = ""
for char in text:
if char.islower():
ascii_offset = ord('a') if char.islower() else ord('A')
result += chr((ord(char) - ascii_offset - offset) % 26 + ascii_offset)
else:
result += char
return result
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HOST = "192.168.43.21"
PORT = 8887
client.connect((HOST, PORT))
print("已连接服务端!输入 exit 退出")
while True:
send_msg = input("我:")
encrypt_msg = caesar_encrypt(send_msg)
client.send(encrypt_msg.encode("utf-8"))
print(f"我发送的明文:{send_msg}")
print(f"我发送的密文:{encrypt_msg}\n")
if send_msg = "exit":
print("聊天结束")
break
data = client.recv(1024).decode("utf-8")
if not data or data == "exit":
print("聊天结束")
break
decrypt_data = caesar_decrypt(data)
print(f"服务端密文:{data}")
print(f"服务端明文:{decrypt_data}\n")
client.close()
(四)双人联机通信测试
与队友完成联机实验:一人运行服务端,另一人运行客户端,使用各自学号与姓名标识身份。双方成功建立连接,可互相收发加密消息,程序运行稳定,无卡顿、无报错,退出流程正常,满足 “一人服务端、一人客户端” 的实验联机要求。


(五)图形界面(GUI)程序实现
使用豆包大模型生成带图形界面的 Socket 通信程序,界面包含 IP 输入框、端口输入、连接按钮、消息发送框、消息显示区等组件。GUI 版自动完成加密、解密、收发、显示,操作更直观。关键功能正常:连接服务端、发送消息、接收消息、明文密文同步展示。
(1)本程序利用 Python 内置 socket 库搭建 TCP 套接字通信,服务端通过创建流式 Socket、绑定 IP 端口、开启端口监听,配合多线程技术循环接收并响应多个客户端连接请求,通过 recv () 接收数据、send () 发送数据,实现多用户并发通信;客户端通过 Socket 主动连接服务端指定地址与端口,建立可靠 TCP 连接,独立线程实时接收服务端推送消息,输入内容编码后发送至服务端,程序结合 tkinter 实现图形化界面,统一完成消息展示、连接控制与交互操作,整体依靠套接字收发函数完成网络数据传输,多线程解决单线程阻塞问题,GUI 控件简化操作流程,完整实现服务端监听、多客户端接入与双向消息收发的 Socket 通信功能。
(2)该 Socket 通信程序采用 TCP 协议进行数据传输,传输稳定可靠、不易丢失数据,运用多线程技术使服务端能够同时监听并处理多个客户端请求,实现多用户并发连接,程序搭载 tkinter 图形化操作界面,操作简单直观、无需命令行操作,代码结构规范清晰,便于理解与修改拓展,依托 Python 内置库开发,无需安装额外依赖,跨平台兼容性强,同时具备消息收发、日志显示、连接状态管理与消息广播等完整功能,运行稳定且容错性良好,有效提升了网络通信的实用性与便捷性。
(3)服务端代码:
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, Entry, Button
class TCPServerGUI:
def init(self, root):
self.root = root
self.root.title("TCP多客户端服务端")
self.root.geometry("600x500")
tk.Label(root, text="监听端口:").pack()
self.port_entry = Entry(root)
self.port_entry.insert(0, "8888")
self.port_entry.pack()
self.start_btn = Button(root, text="启动服务", command=self.start_server)
self.start_btn.pack(pady=3)
self.stop_btn = Button(root, text="关闭服务", command=self.stop_server, state=tk.DISABLED)
self.stop_btn.pack(pady=3)
self.log_area = scrolledtext.ScrolledText(root, width=70, height=22)
self.log_area.pack(pady=5)
self.server_socket = None
self.is_running = False
self.client_list = []
def log(self, txt):
self.log_area.insert(tk.END, txt + "\n")
self.log_area.see(tk.END)
def handle_client(self, cli_sock, addr):
self.log(f"客户端 {addr} 已连接")
self.client_list.append(cli_sock)
while self.is_running:
try:
data = cli_sock.recv(1024)
if not data:
break
text = data.decode("utf-8")
self.log(f"收到{addr}:{text}")
for c in self.client_list:
if c != cli_sock:
c.send(f"{addr} 说:{text}".encode("utf-8"))
except:
break
cli_sock.close()
self.client_list.remove(cli_sock)
self.log(f"客户端 {addr} 已断开")
def accept_loop(self):
while self.is_running:
try:
cli, addr = self.server_socket.accept()
threading.Thread(target=self.handle_client, args=(cli, addr), daemon=True).start()
except:
break
def start_server(self):
port = int(self.port_entry.get())
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_socket.bind(("0.0.0.0", port))
self.server_socket.listen(10)
self.is_running = True
self.start_btn.config(state=tk.DISABLED)
self.stop_btn.config(state=tk.NORMAL)
self.log(f"服务端已启动,端口:{port}")
threading.Thread(target=self.accept_loop, daemon=True).start()
def stop_server(self):
self.is_running = False
for c in self.client_list:
c.close()
if self.server_socket:
self.server_socket.close()
self.client_list.clear()
self.start_btn.config(state=tk.NORMAL)
self.stop_btn.config(state=tk.DISABLED)
self.log("服务端已关闭")
if name == "main":
root = tk.Tk()
app = TCPServerGUI(root)
root.mainloop()
客户端代码:
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, Entry, Button
class TCPClientGUI:
def init(self,root):
self.root = root
self.root.title("TCP客户端")
self.root.geometry("600x500")
tk.Label(root,text="服务端IP:").pack()
self.ip_entry = Entry(root)
self.ip_entry.insert(0,"192.168.43.21")
self.ip_entry.pack()
tk.Label(root,text="端口:").pack()
self.port_entry = Entry(root)
self.port_entry.insert(0,"8888")
self.port_entry.pack()
self.conn_btn = Button(root,text="连接服务端",command=self.connect)
self.conn_btn.pack(pady=3)
self.dis_btn = Button(root,text="断开连接",command=self.disconnect,state=tk.DISABLED)
self.dis_btn.pack(pady=3)
self.chat_text = scrolledtext.ScrolledText(root,width=70,height=20)
self.chat_text.pack(pady=5)
tk.Label(root,text="输入消息:").pack()
self.msg_entry = Entry(root,width=50)
self.msg_entry.pack()
self.send_btn = Button(root,text="发送消息",command=self.send_msg,state=tk.DISABLED)
self.send_btn.pack(pady=3)
self.sock = None
self.connected = False
def log(self,txt):
self.chat_text.insert(tk.END,txt+"\n")
self.chat_text.see(tk.END)
def recv_loop(self):
while self.connected:
try:
data = self.sock.recv(1024)
if data:
self.log(data.decode("utf-8"))
except:
self.log("连接断开")
self.connected = False
self.reset_btn()
break
def connect(self):
ip = self.ip_entry.get()
port = int(self.port_entry.get())
self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
self.sock.connect((ip,port))
self.connected = True
self.log("✅ 成功连接服务端")
self.reset_btn()
threading.Thread(target=self.recv_loop,daemon=True).start()
except:
self.log("❌ 连接失败,请先开启服务端")
def send_msg(self):
msg = self.msg_entry.get().strip()
if not msg or not self.connected:
return
self.sock.send(msg.encode("utf-8"))
self.log(f"我:{msg}")
self.msg_entry.delete(0,tk.END)
def disconnect(self):
self.connected = False
if self.sock:
self.sock.close()
self.reset_btn()
self.log("已手动断开连接")
def reset_btn(self):
if self.connected:
self.conn_btn.config(state=tk.DISABLED)
self.dis_btn.config(state=tk.NORMAL)
self.send_btn.config(state=tk.NORMAL)
else:
self.conn_btn.config(state=tk.NORMAL)
self.dis_btn.config(state=tk.DISABLED)
self.send_btn.config(state=tk.DISABLED)
if name == "main":
win = tk.Tk()
c = TCPClientGUI(win)
win.mainloop()
运行截图如下:


3. 实验过程中遇到的问题和解决过程
- 问题1:服务端绑定指定 IP 时报错 WinError 10049 地址无效
- 问题1解决方案: 服务端不能绑定其他设备 IP,改为绑定 0.0.0.0 即可正常监听。
- 问题2:消息传输时未加密,不符合实验要求
- 问题2解决方案: 添加凯撒加密、解密函数,发送前加密,接收后解密。
-问题3:不会将IP设置为学号 - 问题3解决方案:询问同学设置方法
其他(感悟、思考等)
通过本次 Python Socket 通信实验,我不仅完成了客户端与服务端的编程、消息加密传输和图形界面实现,还在实践中加深了对网络通信原理、数据安全基础以及程序开发流程的理解。在一步步调试、修改、联调的过程中,我真正体会到从理论代码到实际运行的完整链路,收获非常充实。
首先,我对TCP 网络通信有了更直观、更深刻的认识。以前只在课堂上了解客户端和服务端的概念,而这次亲手编写 bind、listen、accept、connect、send、recv 等函数,让我真正理解了 TCP 的连接建立、数据传输和断开流程。服务端负责监听与等待,客户端主动发起连接,双方通过套接字交换数据,这种分工明确的结构让我对网络程序的运行逻辑更加清晰。
在调试程序的过程中,我遇到了地址无效、端口冲突、变量未定义、循环卡死等多种错误。每一次排查与修正,都让我更加熟悉 Python 语法和 Socket 的使用规范,也提升了逻辑分析与问题定位能力。我学会了先看报错信息、再定位代码行、逐步验证功能的调试方法,这种排错思路对今后的编程学习非常有帮助。
借助大模型生成图形界面 GUI 程序,让我感受到现代工具对编程效率的巨大提升。模型能够快速理解需求,自动生成界面布局、事件处理、多线程、加密逻辑等完整代码,不仅减少了重复编写的工作量,还让我看到了更规范、更优雅的代码结构。图形界面让原本枯燥的命令行聊天变得直观易用,也让我认识到良好的交互体验对程序的重要性。
最后,与队友联机通信的环节让我体会到团队协作与网络互联的真实意义。从配置 IP、端口,到互相连接、收发消息,再到一起测试退出逻辑,整个过程让我感受到网络程序的实际应用价值。这次实验不仅巩固了 Python 编程能力,更让我对网络开发、信息安全和软件工程有了更全面的认识,为后续更复杂的项目打下了扎实基础。
参考资料
- 《Java程序设计与数据结构教程(第二版)》
- 《Java程序设计与数据结构教程(第二版)》学习指导
浙公网安备 33010602011771号