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

20214325 2021-2022-7 《Python程序设计》实验三报告

课程:《Python程序设计》
班级: 2143
实验教师:王志强
实验日期: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

由于代码较长,将其单独放在文件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解决方案:定义函数判断字符是否为汉字解决

其他(感悟、思考等)

加密方面知识还需多加学习

程序还有很多地方都可以进一步优化升级

参考资料

posted @ 2022-05-04 22:38  Ethan-Chase  阅读(148)  评论(0编辑  收藏  举报
-->