20241113高赞凯 《Python程序设计》实验三报告
课程:《Python程序设计》
班级: 2411
姓名: 高赞凯
学号:20241114
实验教师:王志强
实验日期:2025年4月16日
必修/选修: 公选课
(一)实验内容和要求
创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。
(1)创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
(2)要求包含文件的基本操作,例如打开和读写操作。
(3)要求发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中。
(4)程序代码托管到码云。
(二)实验过程和结果
首先根据课上老师代码演示及群里代码,写一段可以完成通信功能的客户端和服务器程序:
客户端:
点击查看代码
import socket
# 创建 socket 对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
server_address = ('192.168.43.38', 8888)
client_socket.connect(server_address)
while True:
# 发送消息给服务器
message = input('请输入要发送的消息: ')
client_socket.send(message.encode('utf-8'))
# 接收服务器消息
data = client_socket.recv(1024).decode('utf-8')
if not data:
break
print('服务器说: {}'.format(data))
# if (input("继续打个Y,退出输N")=="N"):
# break
client_socket.close()
服务器:
点击查看代码
import socket
# 创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
server_address = ('192.168.43.38', 8888)
server_socket.bind(server_address)
# 监听连接
server_socket.listen(1)
print('服务器正在监听 {}:{}'.format(*server_address))
# 接受客户端连接
client_socket, client_address = server_socket.accept()
print('接受来自 {} 的连接'.format(client_address))
while True:
# 接收客户端消息
data = client_socket.recv(1024).decode('utf-8')
if not data:
break
print('客户端说: {}'.format(data))
# 发送消息给客户端
message = input('请输入要发送给客户端的消息: ')
client_socket.send(message.encode('utf-8'))
if input("是否要继续?Y/N")=="N":
break
# 关闭连接
client_socket.close()
server_socket.close()
调试结果如下(中途查询了自己笔记本的IP地址并做了更改)

接着完成“发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中”这一要求
在从csdn以及知乎上的学习中了解到了aes
就是这个
又了解到了一些aes算法实现
这是aes加密函数预览
点击查看代码
def aes(plaintext: bytes, key: bytes) -> bytes:
"""
AES-128/192/256 加密实现(ECB模式)
参数:
plaintext: 明文字节串(长度必须是16的倍数)
key: 密钥字节串(长度必须是16、24或32字节)
返回:
密文字节串
"""
plen = len(plaintext)
keylen = len(key)
# 验证输入长度
if plen == 0 or plen % 16 != 0:
raise ValueError("明文字符长度必须为16的倍数!")
if keylen not in [16, 24, 32]:
raise ValueError(f"密钥长度错误!必须为16/24/32字节,当前为{keylen}")
# 扩展密钥
expanded_key = extend_key(key)
block_size = 16
rounds = 10 if keylen == 16 else 12 if keylen == 24 else 14
# 分块加密
ciphertext = bytearray()
for i in range(0, plen, block_size):
block = plaintext[i:i+block_size]
# 转换为状态矩阵 (4x4字节)
state = [[block[r + c*4] for c in range(4)] for r in range(4)]
# 初始轮密钥加
add_round_key(state, expanded_key, 0)
# 前n-1轮
for rnd in range(1, rounds):
sub_bytes(state)
shift_rows(state)
mix_columns(state)
add_round_key(state, expanded_key, rnd)
# 最后一轮(无列混合)
sub_bytes(state)
shift_rows(state)
add_round_key(state, expanded_key, rounds)
# 转换回字节并添加到密文
ciphertext.extend([state[r][c] for c in range(4) for r in range(4)])
return bytes(ciphertext)
# 辅助函数实现
def extend_key(key: bytes) -> list:
"""密钥扩展函数"""
# 实现依赖 AES 密钥长度和轮数
pass
def sub_bytes(state: list) -> None:
"""字节替换(SubBytes)"""
# 使用 AES S-Box 替换每个字节
s_box = [
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
# ... 完整S-Box省略 ...
]
for r in range(4):
for c in range(4):
state[r][c] = s_box[state[r][c]]
def shift_rows(state: list) -> None:
"""行移位(ShiftRows)"""
state[0][1], state[1][1], state[2][1], state[3][1] = state[1][1], state[2][1], state[3][1], state[0][1]
state[0][2], state[1][2], state[2][2], state[3][2] = state[2][2], state[3][2], state[0][2], state[1][2]
state[0][3], state[1][3], state[2][3], state[3][3] = state[3][3], state[0][3], state[1][3], state[2][3]
def mix_columns(state: list) -> None:
"""列混合(MixColumns)"""
# 有限域GF(2^8)上的矩阵乘法
pass
def add_round_key(state: list, expanded_key: list, round_num: int) -> None:
"""轮密钥加(AddRoundKey)"""
round_key = expanded_key[round_num*16:(round_num+1)*16]
for c in range(4):
for r in range(4):
state[r][c] ^= round_key[c*4 + r]
点击查看代码
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import os
def aes_encrypt(plaintext, key, mode=AES.MODE_CBC, iv=None):
key_len = len(key)
if key_len not in [16, 24, 32]:
raise ValueError("密钥长度必须为16/24/32字节")
if mode in [AES.MODE_CBC, AES.MODE_CFB, AES.MODE_OFB]:
iv = iv if iv else os.urandom(AES.block_size)
if len(iv) != AES.block_size:
raise ValueError(f"IV长度必须为{AES.block_size}字节")
elif mode == AES.MODE_ECB:
iv = b''
cipher = AES.new(key, mode, iv=iv)
plaintext_bytes = plaintext.encode('utf-8')
padded_bytes = pad(plaintext_bytes, AES.block_size)
ciphertext = cipher.encrypt(padded_bytes)
return iv + ciphertext if mode != AES.MODE_ECB else ciphertext
def aes_decrypt(ciphertext, key, mode=AES.MODE_CBC):
key_len = len(key)
if key_len not in [16, 24, 32]:
raise ValueError("密钥长度必须为16/24/32字节")
if mode == AES.MODE_ECB:
iv = b''
ciphertext_ = ciphertext
else:
iv = ciphertext[:AES.block_size]
ciphertext_ = ciphertext[AES.block_size:]
cipher = AES.new(key, mode, iv=iv)
decrypted_padded = cipher.decrypt(ciphertext_)
decrypted_bytes = unpad(decrypted_padded, AES.block_size)
return decrypted_bytes.decode('utf-8')
message = "Hello, AES!"
key = os.urandom(16)
encrypted_data = aes_encrypt(message, key)
decrypted_data = aes_decrypt(encrypted_data, key)
点击查看代码
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import os
def aes_encrypt(plaintext, key, mode=AES.MODE_CBC, iv=None):
key_len = len(key)
if key_len not in [16, 24, 32]:
raise ValueError("密钥长度必须为16/24/32字节")
if mode in [AES.MODE_CBC, AES.MODE_CFB, AES.MODE_OFB]:
iv = iv if iv else os.urandom(AES.block_size)
if len(iv) != AES.block_size:
raise ValueError(f"IV长度必须为{AES.block_size}字节")
elif mode == AES.MODE_ECB:
iv = b''
cipher = AES.new(key, mode, iv=iv)
plaintext_bytes = plaintext.encode('utf-8')
padded_bytes = pad(plaintext_bytes, AES.block_size)
ciphertext = cipher.encrypt(padded_bytes)
return iv + ciphertext if mode != AES.MODE_ECB else ciphertext
def aes_decrypt(ciphertext, key, mode=AES.MODE_CBC):
key_len = len(key)
if key_len not in [16, 24, 32]:
raise ValueError("密钥长度必须为16/24/32字节")
if mode == AES.MODE_ECB:
iv = b''
ciphertext_ = ciphertext
else:
iv = ciphertext[:AES.block_size]
ciphertext_ = ciphertext[AES.block_size:]
cipher = AES.new(key, mode, iv=iv)
decrypted_padded = cipher.decrypt(ciphertext_)
decrypted_bytes = unpad(decrypted_padded, AES.block_size)
return decrypted_bytes.decode('utf-8')
message = "Hello, AES!"
key = os.urandom(16)
encrypted_data = aes_encrypt(message, key)
decrypted_data = aes_decrypt(encrypted_data, key)
点击查看代码
import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
# 加密密钥,必须是16、24或32字节
key = os.urandom(16)
# 初始化向量,必须是16字节
iv = os.urandom(16)
def encrypt_message(message):
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(pad(message.encode('utf-8'), AES.block_size))
return iv + encrypted
def decrypt_message(encrypted_message):
iv = encrypted_message[:AES.block_size]
encrypted = encrypted_message[AES.block_size:]
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(encrypted), AES.block_size)
return decrypted.decode('utf-8')
client端:
点击查看代码
import socket
from AesModule import encrypt_message
# 创建socket对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
server_address = ('localhost', 8888)
client_socket.connect(server_address)
try:
# 从文件读取内容
with open('send_file.txt', 'r', encoding='utf-8') as file:
message = file.read()
# 加密数据
encrypted_message = encrypt_message(message)
# 发送加密数据
client_socket.sendall(encrypted_message)
print('数据已加密并发送')
except FileNotFoundError:
print("文件 send_file.txt 未找到,请确保文件存在。")
finally:
# 关闭连接
client_socket.close()
点击查看代码
import socket
from AesModule import decrypt_message
# 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
server_address = ('localhost', 8888)
server_socket.bind(server_address)
# 监听连接
server_socket.listen(1)
print(f'服务器正在监听 {server_address[0]}:{server_address[1]}')
while True:
# 接受客户端连接
client_socket, client_address = server_socket.accept()
print(f'接受来自 {client_address} 的连接')
try:
# 接收客户端发送的加密数据
encrypted_data = client_socket.recv(4096)
if not encrypted_data:
break
# 解密数据
decrypted_data = decrypt_message(encrypted_data)
# 将解密后的数据保存到文件
with open('received_file.txt', 'w', encoding='utf-8') as file:
file.write(decrypted_data)
print('数据已解密并保存到 received_file.txt')
except Exception as e:
print(f"发生错误: {e}")
finally:
# 关闭客户端连接
client_socket.close()
# 关闭服务器连接
server_socket.close()
结果如下

实验过程中遇到的问题和解决过程
问题一:在进行不同计算机之间的通信时,显示“目标计算机积极防御”。
问题一解决方案:询问同学,防火墙允许应用访问即可。
问题二:开始时连接出现问题
问题二解决方案:查资料后学会了运用命令符来获取自己的ip地址,把老师给的代码里的地址换成自己的ip地址就连接成功了
问题三:加密时出现问题,没懂老师发的那个加密文件怎么用。
问题三解决方案:在CSDN中找到AES相关的博客,学习使用AES加密。
其他(感悟、思考等)
做这个实验已经开始懵了,有种深深的无力感,真的没有学明白,继续努力吧
参考资料
https://blog.csdn.net/qq_28205153/article/details/55798628
浙公网安备 33010602011771号