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)
(以上三个代码都是在csdn上找到的) 结合浅浅了解到的aes,配合大模型,得到了这样的代码 aes加密:
点击查看代码
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

posted on 2025-04-23 22:16  gzk6962  阅读(16)  评论(0)    收藏  举报