20214325 实验三《Python程序设计》实验报告
20214325 2021-2022-7 《Python程序设计》实验三报告
课程:《Python程序设计》
班级: 2143
姓名: 冀彦丞
学号: 20214325
实验教师:王志强
实验日期:2022年5月4日
必修/选修: 公选课
1.实验内容
创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。
(1)创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
(2)要求包含文件的基本操作,例如打开和读写操作。
(3)要求发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中。
(4)程序代码托管到码云。
注:在华为ECS服务器(OpenOuler系统)和物理机(Windows/Linux系统)上使用VIM、PDB、IDLE、Pycharm等工具编程实现。
2. 实验过程及结果
(1)进行基本的socket初始化
过于简单,此处略过
(2)编写加密模块
此处采用了Cryptodome库中提供的AES加密,由于key,iv和加密文字有严格的位数要求,通过判断位数在后方补空格满足格式

1 from Crypto.Cipher import AES 2 def encode(message:str,key:str,iv:str): 3 key = key_transfer(key) 4 iv = transfer(iv) 5 jiami = AES.new(key.encode('utf-8'),AES.MODE_CBC,iv.encode('utf-8')) #key必须为15字节 iv必须为16字节 6 string = transfer(message) #被加密的字符串 字节数 必须为16的倍数 utf-8中一个汉字为 3 字节 7 ciphertext = jiami.encrypt(string.encode('utf-8')) #encrypt()对字符串进行加密 8 return ciphertext 9 10 def decode(code:str,key:str,iv:str): 11 key = key_transfer(key) 12 iv = transfer(iv) 13 jiemi = AES.new(key.encode('utf-8'),AES.MODE_CBC,iv.encode('utf-8')) #解密使用的key和IV必须是加密时使用的 14 raw = jiemi.decrypt(code).decode('utf-8') 15 return str(raw) 16 17 def key_transfer(str): 18 a = 0 19 for i in range(len(str)): 20 if is_chinese(str[i]): 21 a += 3 22 else: 23 a +=1 24 a = a%15 25 if a>0: 26 for i in range(16-a): 27 str = str +" " 28 return str 29 30 def transfer(str): 31 a = 0 32 for i in range(len(str)): 33 if is_chinese(str[i]): 34 a += 3 35 else: 36 a +=1 37 a = a%16 38 if a>0: 39 for i in range(16-a): 40 str = str +" " 41 return str 42 43 def is_chinese(ch): 44 if ch < '一' or ch > '龥': 45 return False 46 return True 47 48 # 测试代码 49 # message = input("\n") 50 # code = encode(message,'1','1') 51 52 # print("\n\n") 53 # s = decode(code, '1','1') 54 # print(s)
由于代码较长,将其单独放在文件info_encode.py中,通过import调用至服务器和客户端代码
(3)文件操作
加密传输后将信息与客户端ip,当前时间写入data.txt文件中作为缓存
(4)优化程序结构
使连接可以在主动退出前一直保持,为客户端增加了远程关闭服务器的指令,通过try-except使服务器不会因为客户端断开连接而报错关闭
(5)程序运行展示
如图,当客户端输入key与iv与服务器不同时,服务器不会响应(实质为解码过程中会报错运行except pass跳过) 当key与iv与服务器差距较小时会解码成乱码,不过在密码与iv复杂的情况下概率极低。
当密码与iv正确时即可进行正常通信
缓存记录正常:
(5)将代码托管至git
(6)源码展示:
1.服务器
1 import socket 2 from info_encode import * 3 import time 4 5 ##初始化服务器 6 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 7 s.bind(("192.168.31.254",8002)) #ip 和 端口 8 9 key = input("input key") 10 iv = input("input iv") 11 def listen(): 12 global key,iv 13 s.listen() 14 conn,adress = s.accept() 15 data = conn.recv(1024) 16 data = decode(data,key,iv).rstrip() 17 print(str(adress[0]) + ' : ' + str(data) + "\n") 18 if data == 'close the program': 19 conn.sendall(("\n服务器已关闭\n").encode()) 20 return 0 21 with open(r'./data','a',encoding="utf_8") as txt: 22 txt.write(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))) 23 txt.write("\n" + str(adress[0]) + ' : ' + str(data) + "\n\n") 24 conn.sendall(("##服务器已收到:" +str(adress[0]) + ' : ' + str(data) + "\n").encode()) 25 return 1 26 27 flag = 1 28 while True: 29 if flag==0: 30 s.close() 31 break 32 try: 33 if listen() == 0: 34 flag = 0 35 except: 36 pass
2.客户端
1 import socket 2 from info_encode import * 3 4 key = input("input key") 5 iv = input("input iv") 6 7 while True: 8 try: 9 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 10 s.connect(("192.168.31.254",8002)) #ip 和 端口 11 word = input("请输入(输入q断开链接,close断开连接并关闭服务器)") 12 if word == "q": 13 break 14 if word == "close": 15 s.sendall((encode('close the program',key,iv))) 16 print("服务器已关闭") 17 break 18 s.sendall((encode(word,key,iv))) 19 data = s.recv(1024) 20 print(data.decode()) 21 except: 22 pass 23 24 print("已断开连接") 25 s.close()
3.加密模块
from Crypto.Cipher import AES def encode(message:str,key:str,iv:str): key = key_transfer(key) iv = transfer(iv) jiami = AES.new(key.encode('utf-8'),AES.MODE_CBC,iv.encode('utf-8')) #key必须为15字节 iv必须为16字节 string = transfer(message) #被加密的字符串 字节数 必须为16的倍数 utf-8中一个汉字为 3 字节 ciphertext = jiami.encrypt(string.encode('utf-8')) #encrypt()对字符串进行加密 return ciphertext def decode(code:str,key:str,iv:str): key = key_transfer(key) iv = transfer(iv) jiemi = AES.new(key.encode('utf-8'),AES.MODE_CBC,iv.encode('utf-8')) #解密使用的key和IV必须是加密时使用的 raw = jiemi.decrypt(code).decode('utf-8') return str(raw) def key_transfer(str): a = 0 for i in range(len(str)): if is_chinese(str[i]): a += 3 else: a +=1 a = a%15 if a>0: for i in range(16-a): str = str +" " return str def transfer(str): a = 0 for i in range(len(str)): if is_chinese(str[i]): a += 3 else: a +=1 a = a%16 if a>0: for i in range(16-a): str = str +" " return str def is_chinese(ch): if ch < '一' or ch > '龥': return False return True # 测试代码 # message = input("\n") # code = encode(message,'1','1') # print("\n\n") # s = decode(code, '1','1') # print(s)
3. 实验过程中遇到的问题和解决过程
- 问题1:不知道加密的方法
- 问题1解决方案:上CSDN后查到有关加密的库
- 问题2:pycrypto无法安装
- 问题2解决方案:安装pycryptodome替代
- 问题3:AES_CBC加密模式只能接受16字节的输入,中文信息处理困难
- 问题3解决方案:定义函数判断字符是否为汉字解决
其他(感悟、思考等)
加密方面知识还需多加学习
程序还有很多地方都可以进一步优化升级