20222223 实验三《Python程序设计》实验报告
20222223 2024-2025-2 《Python程序设计》实验三报告
课程:《Python程序设计》
班级: 2222
姓名: 李東霖
学号:20222223
实验教师:王志强
实验日期:2025年4月16日
必修/选修: 公选课
一、实验内容
(一)实验内容
创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。
(二)实验要求
1.创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
2.要求包含文件的基本操作,例如打开和读写操作。
3.要求发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中。
4.程序代码托管到码云。
注:在华为ECS服务器(OpenOuler系统)和物理机(Windows/Linux系统)上使用VIM、PDB、IDLE、Pycharm等工具编程实现。
二、实验过程及结果
(一)通信功能实现
1.客户端相关代码:
import socket
def show_menu():
print("\n===== 网络通信系统菜单 =====")
print("1. 基本通信功能")
print("2. 加密文件传输功能")
print("0. 退出")
return input("请选择功能 (0-2): ")
def basic_communication(client):
while True:
message = input("请输入要发送的消息: ")
if message == "exit":
client.send(message.encode())
print("通信中断")
break
client.send(message.encode())
response = client.recv(1024).decode()
print(f"服务器响应: {response}")
def main():
# 建立连接
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((HOST, PORT))
while True:
choice = show_menu()
if choice == "0":
print("退出系统")
break
client.send(choice.encode())
if choice == "1":
basic_communication(client)
elif choice == "2":
encrypted_transfer(client)
else:
print("无效选择,请重新输入")
except ConnectionRefusedError:
print("错误: 无法连接到服务器")
except Exception as e:
print(f"发生错误: {str(e)}")
finally:
client.close() # 关闭连接
HOST = "192.168.0.103"
PORT = 5555
main()
客户端通信过程的逻辑如下:
客户端启动时创建Socket并连接到服务器
客户端显示菜单选项(1.基本通信,2.加密文件传输,0.退出)
用户选择1后,客户端将选择发送给服务器,随后进入消息循环
用户输入消息,发送至服务端(输入"exit"退出)
等待并显示服务器响应
通信完成(输入exit)关闭Socket连接
程序结束
2.服务器相关代码
import socket
import threading
def handle_client(client_socket, addr):
print(f"[*] 接受来自 {addr[0]}:{addr[1]} 的连接")
try:
while True: # 添加循环保持连接
# 接收客户端选择的功能
choice = client_socket.recv(1024).decode()
if choice == "0":
print(f"[*] 客户端 {addr} 请求断开连接")
break
if choice == "1":
# 基本通信功能
while True:
message = client_socket.recv(1024).decode()
if message == "exit":
break
print(f"[{addr}] 收到消息: {message}")
reply = input("请输入回复:")
client_socket.send(reply.encode())
def start_server(host, port):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(5)
print(f"[*] 服务器监听 {host}:{port}")
try:
while True:
client_sock, addr = server.accept()
client_handler = threading.Thread(
target=handle_client,
args=(client_sock, addr)
)
client_handler.start()
except KeyboardInterrupt:
print("\n[*] 服务器关闭")
finally:
server.close()
HOST = "192.168.0.103"
PORT = 5555
start_server(HOST, PORT)
服务器通信过程的逻辑如下:
服务器启动,创建Socket (socket.AF_INET, socket.SOCK_STREAM)
绑定到指定IP和端口 (HOST = "192.168.0.103", PORT = 5555)
开始监听,设置最大挂起连接数为5
当有新客户端连接时:server.accept()接受连接,返回客户端socket和地址
为每个客户端创建新线程处理 (threading.Thread)
接收客户端选择的功能("0"退出,"1"基本通信,"2"加密传输)
选择1基本通信功时,循环接收客户端消息(收到"exit"时退出循环)
打印收到的消息
等待输入回复内容
将回复发送给客户端
3.运行结果
客户端:

服务器:

(二)文件操作及加密传输
1.客户端代码
import socket
# 异或加密/解密函数
def xor_crypt(data, key):
return bytes([b ^ key for b in data])
def show_menu():
print("\n===== 网络通信系统菜单 =====")
print("1. 基本通信功能")
print("2. 加密文件传输功能")
print("0. 退出")
return input("请选择功能 (0-2): ")
def encrypted_transfer(client):
try:
# 获取异或加密密钥
key = int(input("请输入异或加密密钥(0-255): "))
if not 0 <= key <= 255:
raise ValueError
#传输密钥和文件名
client.send(str(key).encode())
filename = input("请输入要加密传输的文件: ")
client.send(filename.encode())
# 读取并加密文件
with open(filename, "rb") as file:
file_data = file.read()
encrypted_data = xor_crypt(file_data, key)
# 分块发送加密数据
chunk_size = 4096
for i in range(0, len(encrypted_data), chunk_size):
client.send(encrypted_data[i:i + chunk_size])
# 发送结束标记
client.shutdown(socket.SHUT_WR)
# 接收服务器响应
response = client.recv(1024).decode()
print(f"服务器响应: {response}")
except ValueError:
print("错误: 密钥必须是0-255之间的整数")
except Exception as e:
print(f"文件传输失败: {str(e)}")
def main():
# 建立连接
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((HOST, PORT))
while True:
choice = show_menu()
if choice == "0":
print("退出系统")
break
client.send(choice.encode())
if choice == "1":
basic_communication(client)
elif choice == "2":
encrypted_transfer(client)
else:
print("无效选择,请重新输入")
except ConnectionRefusedError:
print("错误: 无法连接到服务器")
except Exception as e:
print(f"发生错误: {str(e)}")
finally:
client.close() # 关闭连接
HOST = "120.46.29.197"#云服务器的公网IP
PORT = 8080
main()
客户端逻辑:
客户端启动时创建Socket并连接到服务器
客户端显示菜单选项(1.基本通信,2.加密文件传输,0.退出)
选择2进入文件传输
用户输入加密密钥(0-255的整数,加密方式为异或)
客户端发送密钥给服务器
用户输入要传输的文件名
客户端发送文件名给服务器
客户端执行文件传输:
读取文件内容
使用异或加密算法加密文件数据
分块(4096字节/块)发送加密数据
发送完成后关闭写入端(SHUT_WR)
接收并显示服务器响应
2.服务器代码:
import socket
import threading
# 异或加密/解密函数
def xor_crypt(data, key):
return bytes([b ^ key for b in data])
def handle_client(client_socket, addr):
print(f"[*] 接受来自 {addr[0]}:{addr[1]} 的连接")
try:
while True: # 添加循环保持连接
# 接收客户端选择的功能
choice = client_socket.recv(1024).decode()
if choice == "0":
print(f"[*] 客户端 {addr} 请求断开连接")
break
if choice == "1":
# 基本通信功能
while True:
message = client_socket.recv(1024).decode()
if message == "exit":
break
print(f"[{addr}] 收到消息: {message}")
reply = input("请输入回复:")
client_socket.send(reply.encode())
elif choice == "2":
# 加密传输功能
try:
# 接收密钥
key = int(client_socket.recv(1024).decode())
print(f"[*] 使用异或密钥: {key}")
# 接收文件名
filename = client_socket.recv(1024).decode()
print(f"[*] 接收文件: {filename}")
# 接收加密数据
encrypted_data = b""
while True:
chunk = client_socket.recv(4096)
if not chunk:
break
encrypted_data += chunk
print(f"收到密文:\n{encrypted_data}")
# 解密数据
decrypted_data = xor_crypt(encrypted_data, key)
print(f"解密结果为:\n{decrypted_data}")
# 保存解密后的文件
save_path = f"decrypted_{filename}"
with open(save_path, "wb") as file:
file.write(decrypted_data)
print(f"[+] 文件已解密保存到: {save_path}")
# 发送确认信息给客户端
client_socket.send(f"文件接收解密成功,保存为: {save_path}".encode())
except Exception as e:
print(f"[!] 解密失败: {str(e)}")
client_socket.send(f"解密失败: {str(e)}".encode())
except Exception as e:
print(f"[!] 处理 {addr} 时出错: {str(e)}")
finally:
client_socket.close()
def start_server(host, port):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(5)
print(f"[*] 服务器监听 {host}:{port}")
try:
while True:
client_sock, addr = server.accept()
client_handler = threading.Thread(
target=handle_client,
args=(client_sock, addr)
)
client_handler.start()
except KeyboardInterrupt:
print("\n[*] 服务器关闭")
finally:
server.close()
HOST = "192.168.10.184"#云服务器的映射IP
PORT = 8080
start_server(HOST, PORT)
服务器逻辑:
服务器启动,创建Socket (socket.AF_INET, socket.SOCK_STREAM)
绑定到指定IP和端口 (HOST = "192.168.10.184", PORT = 5555)
开始监听,设置最大挂起连接数为5
当有新客户端连接时:server.accept()接受连接,返回客户端socket和地址
为每个客户端创建新线程处理 (threading.Thread)
接收客户端选择的功能("0"退出,"1"基本通信,"2"加密传输)
选择2进入加密传输
接收加密密钥(0-255的整数,用于异或)
接收文件名
分块接收加密文件数据(4096字节/块)
使用异或算法解密数据
将解密数据保存为"decrypted_原文件名"
发送操作结果给客户端
3.运行结果
客户端:

服务器:


文件内容:
客户端发送:

服务器接收:

(三)上传代码至码云
https://gitee.com/doronlee/python/tree/master/实验三

三、实验过程中遇到的问题和解决过程
-
问题1:无法安装cryptography库,不能使用库内的加密函数
-
问题1解决方案:没能解决安装库的问题,使用简单的异或加密代替
-
问题2:文件传输出现乱码
-
问题2解决方案:传输过程中明确编码方式可以避免乱码问题
# 发送方
with open('file.txt', 'r', encoding='utf-8') as f:
content = f.read()
socket.send(content.encode('utf-8'))
# 接收方
data = socket.recv(1024)
content = data.decode('utf-8')
其他(感悟、思考等)
我了解过在linux中使用C语言进行socket编程,学会python后发现有许多的相似之处,都有相同的流程:创建Socket → 绑定地址 → 监听(服务端)/连接(客户端) → 接受连接(服务端) → 发送/接收数据 → 关闭连接。但是使用python更方便,不需要手动管理内存。
浙公网安备 33010602011771号