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方法掌握仍然不熟练,尤其是常常分不清某时指针的位置,是否创建了新文件等等,在以后会更加深入的去了解。