20213306 实验三《Python程序设计》实验报告

20213306《Python程序设计》实验三报告

课程:《Python程序设计》
班级:2133
姓名:李鹏宇
学号:20213306
实验教师:王志强
实验日期:2022年4月21日
必修/选修: 公选课

1.实验内容

创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。

2.实验要求

  • 创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
  • 要求包含文件的基本操作,例如打开和读写操作。
  • 要求发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中。
  • 程序代码托管到码云。

3. 实验过程及结果

3.1 代码

客户端

import socket      
import datetime#以当前日期加密  
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
class AesCrypto():#支持中文的AES
    def __init__(self, key, IV):
        self.key = key #需为16位倍数
        self.iv = IV #必须为16位
        self.mode = AES.MODE_CBC
    def encrypt(self, text):
        cryptor = AES.new(self.key, self.mode, self.iv)
        length = 16
        count = len(text)
        if(count%length != 0):
            add = length-(count%length)
        else:
            add=0

        text = text+("\0".encode()*add)#因为中文位数原因,这里需要.encode

        self.ciphertext = cryptor.encrypt(text)
        return (self.ciphertext)
    
    def decrypt(self, text):
        cryptor = AES.new(self.key, self.mode, self.iv)
        plain_text = cryptor.decrypt((text)).decode()
        return plain_text
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print("欢迎来到客户端")
port = input("请输入连接端口号")
s.connect(('localhost',int(port))) #暂时本地传输本地
mo = input("请选择模式\n1.文字2.传输文件")
if mo == '1':
    s.sendall(mo.encode())
    str1 = input("请输入传输内容")
    k = datetime.date.today()
    key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
    mo1 = AesCrypto(key=key1, IV=key1)
    str1 = mo1.encrypt(str1.encode())
    s.sendall(str1)
    data = s.recv(1024)
    print(data.decode())
elif mo == '2':#文件传输
    s.sendall(mo.encode())
    mo2mo = input("新建文件请输入1,传输已有文件请输入2")
    addre = input("请输入文件路径")
    k = datetime.date.today()
    key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
    mo2 = AesCrypto(key=key1, IV=key1)
    addre1 = mo2.encrypt(addre.encode())
    s.sendall(addre1)
    if mo2mo == "1":
        file1 = open(addre,"w+",encoding="utf-8")#新建文件
        neirong = input("请输入内容")
        file1.write(neirong)
        file1.close()
        file1 = open(addre,"r",encoding="utf-8")
    elif mo2mo == "2":
        file1 = open(addre,"r",encoding="utf-8")#只读
    file1.seek(0)
    str1 = file1.readlines()
    file1.close()
    lenfile = len(str1)#获取文件有几行
    lenfile = str(lenfile)
    k = datetime.date.today()
    key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
    mo2 = AesCrypto(key=key1, IV=key1)
    lenfile = mo2.encrypt(lenfile.encode())#将文件行数发出去
    s.sendall(lenfile)
    for i in str1:#对于文件的每一行顺序发送
        k = datetime.date.today()
        key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
        mo2 = AesCrypto(key=key1, IV=key1)
        i = mo2.encrypt(i.encode())
        s.sendall(i)
    data = s.recv(1024)#接收“已收到”信息
    print(data.decode())
s.close

服务端

import socket      
import datetime  
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
class AesCrypto():
    def __init__(self, key, IV):
        self.key = key
        self.iv = IV
        self.mode = AES.MODE_CBC
    def encrypt(self, text):
        cryptor = AES.new(self.key, self.mode, self.iv)
        length = 16
        count = len(text)
        if(count%length != 0):
            add = length-(count%length)
        else:
            add=0

        text = text+("\0".encode()*add)

        self.ciphertext = cryptor.encrypt(text)
        return (self.ciphertext)
    
    def decrypt(self, text):
        cryptor = AES.new(self.key, self.mode, self.iv)
        plain_text = cryptor.decrypt((text)).decode('utf8','ignore')
        return plain_text#加密解密同理
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = input("欢迎使用服务端\n请输入开放连接端口号")
s.bind(("localhost", int(port)))#这里只写端口号没问题
s.listen()
con,addr= s.accept()
mo = con.recv(1024)
if mo.decode()== '1':
    print("已收到文字传输请求,对方正在输入...")
    data = con.recv(1024)
    k = datetime.date.today()
    key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
    mo1 = AesCrypto(key=key1, IV=key1)
    data = mo1.decrypt(data)
    print(data)
    right = "信息已收到"#类似状态码,就没有加密
    con.sendall(right.encode())
elif mo.decode()=='2':
    print("已收到文件传输请求,对方正在输入...")
    addre = con.recv(1024)
    k = datetime.date.today()
    key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
    mo2 = AesCrypto(key=key1, IV=key1)
    addre = mo2.decrypt(addre)
    addre = addre.encode()
    addre = addre.split(b"\x00")[0].decode("utf-8")#防‘\’导致打开文件不存在的问题
    file1 = open(addre+"1.txt","w+",encoding="utf-8")#为测试方便多加了后缀
    lenfile1 = con.recv(1024)
    k = datetime.date.today()
    key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
    mo2 = AesCrypto(key=key1, IV=key1)
    lenfile1 = mo2.decrypt(lenfile1)
    lenfile1 = lenfile1.encode()
    lenfile1 = lenfile1.split(b"\x00")[0].decode("utf-8")
    lenfile1 = int(lenfile1)#解码文件行数
    for temp in range(1,lenfile1+1):
        temp = con.recv(1024)
        k = datetime.date.today()
        key1 = k.__format__('%Y&%m&%d%j%U%w').encode()
        mo2 = AesCrypto(key=key1, IV=key1)
        temp = mo2.decrypt(temp)
        temp = temp.encode()
        temp = temp.split(b"\x00")[0].decode("utf-8")#防字符串解密问题
        print(temp)#显示一下内容
        file1.write(temp)#写入文件
    file1.close()
    right = "文件传输完成"
    con.sendall(right.encode())
    print("文件已接收")
s.close

测试截图




上传gitee截图

4. 实验过程中遇到的问题和解决过程

  • 问题1:AES加密方式无法加密中文
  • 问题1解决方案:借用了csdn上一篇文章的的方案
  • 问题2:错误“ValueError:数据必须与 ECB 模式下的块边界对齐”
  • 问题2解决方案:补齐时中文需要encode
  • 问题3:错误“UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xca in position 0: invalid continuation byte”
  • 问题3解决方案:转码错误,应严格按照utf-8方式
  • 问题4:路径传输时无法打开对应路径
  • 问题4解决方案:将接收到的多余‘/’删除

其他(感悟、思考等)

这次实验中,我在aes加解密和bytes与str类型转换上耗费了大量的时间,这次实验让我意识到了尽管python的变量开始时是自适应的,但每个函数要求的变量不是能够通过简单的强制转换就能满足的,有时即使用正确的方式也会得到错误的结果。应该善用调试,灵活的去判断传输时每个变量的具体情况。同时,对于file方法掌握仍然不熟练,尤其是常常分不清某时指针的位置,是否创建了新文件等等,在以后会更加深入的去了解。

参考资料

posted @ 2022-04-26 20:52  LPY_007  阅读(80)  评论(0编辑  收藏  举报