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

20182109 2019-2020-2 《Python程序设计》实验三报告

课程:《Python程序设计》
班级: 1821
姓名: 卢钟添
学号:20182109
实验教师:王志强
实验日期:2020年5月16日
必修/选修: 公选课

1. 实验内容

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

2. 实验过程及结果

实验三的代码由三部分实现,分别是客户端与服务器端之间建立连接以及客户端对明文的加密,对密文的传输以及服务器端对密文的接收和解密。

注:本实验默认双方在通信前均已知密钥

1. 客户端与服务器端之间建立连接

本实验通过Socket套接字来进行通信,因此在客户端和服务器端均应按如下语句设置Socket套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

1. 服务器端的设置

在服务器端是要将local host即本地服务器与端口号进行绑定。
端口号的范围是从1至65535,但在使用端口号时需要注意,有一部分端口号与服务绑定在一起,我们最好不要使用。
例如:HTTP常用80号端口,FTP常用21号端口,SMTP也就是我们使用的电子邮件常用25号端口。
而本地服务器可设置为127.0.0.1,综上,可写出如下语句
s.bind(('127.0.0.1', 8001))

2. 客户端的设置

要保证客户端能与服务器端通信,因此在客户端设置的local host和端口号与服务器端应保持一致。不同的是在客户端要使用connect这一方法名
s.connect(('127.0.0.1', 8001))

2. 客户端对明文的加密和对密文的传输

1. 从本地打开明文

我将明文保存在D盘根目录的某一txt文件下,利用文件的读操作,从中读取出明文。

f = open(r"D:\test3_C.txt")
str1 = f.read()

2. 对明文的加密

在本实验中我调用了pyDes库中的相应算法,如果没安装的话,可在命令行中输入pip install pyDes来安装该库。
调用库中的加密函数时要保证明文的长度能被8整除,对于不满足该条件的明文可用空字符,即空格来补全。

while len(str1) % 8 != 0:  # 使明文长度能被8整除
    str1 += ' '

具体加密函数如下

def des_encrypt(s):
    """
    DES 加密
    :param s: 原始字符串
    :return: 加密后字符串,16进制
    """
    secret_key = KEY
    iv = secret_key
    k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
    en = k.encrypt(s, padmode=PAD_PKCS5)
    return binascii.b2a_hex(en)

需要注意的是,该加密函数返回的是一串16进制字符串,如果明文中存有中文,那么须在传输前对这一字符串用UTF-8编码重新编辑,得到密文。

3. 对密文的传输

在套接字连接的通信中,传输数据应使用sendall方法,且传输的是经过.encode()方法处理后的数据。
s.sendall(cipher.encode())

3. 服务器端对密文的接收和解密

1. 监听

如果服务器端要接收数据,那么它便要通过s.listen()保持一个监听状态。

2. 接收密文

通过s.accept()方法得到客户端与服务器端之间的连接后,便可接收数据。在接收数据后需要对数据.decode()来进行解码。

3. 解密

同加密函数一样,解密也要借用pyDes库中的方法,具体函数如下,

def des_descrypt(s):
    """
    DES 解密
    :param s: 加密后的字符串,16进制
    :return:  解密后的字符串
    """
    secret_key = KEY
    iv = secret_key
    k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
    de = k.decrypt(binascii.a2b_hex(s), padmode=PAD_PKCS5)
    return de

同理,如果存在中文,应使用UTF-8重新编码后保存在字符串中。

4. 对明文的保存

在服务器端用写方式打开一份txt文件,将解密后得到的文件写入。
考虑到会有多份解密后的文件,且可能会有被去除写权限的文件,我还添加了对异常的处理。具体代码如下

try:
    f.write(message)
except IOError:
    sendee = "服务器已经收到了你发送的数据内容,但无法写入文件"
else:
    sendee = "服务器已经收到了你发送的数据内容,且已解密"

5. 回复客户端

在服务器端完成对密文的接收和密文的解密后还应回复客户端,以确认。具体发送的信息即为在上一步中定义的sendee字符串。
在客户端需要用.recv()方法来接收服务器端发送的数据,也可以在接收完后用print方法显示在屏幕上。

4.程序运行结果说明

下图是在D盘根目录下保存的明文。

如果要完成服务器端和客户端的连接,那么必须要先运行服务器端的程序,否则会在客户端内出现如下错误。

正确运行之后,客户端会显示提示信息,

且在服务器端打开的txt文件中也被正确写入了解密后的数据。

5.码云链接

服务器端:https://gitee.com/python_programming/Python_2020_lzt/blob/master/test3_Server.py
客户端:https://gitee.com/python_programming/Python_2020_lzt/blob/master/test3_Client.py
明文(保存在D盘根目录下):https://gitee.com/python_programming/Python_2020_lzt/blob/master/test3_C.txt

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

  • 问题1:不能正确调用pyDes库中的方法来完成加解密函数
  • 问题1解决方案:询问老师后,我得知利用该库中的方法会得到一串2进制代码,还需利用binascii.b2a_hex()方法将其转换成16进制,以便之后的操作
  • 问题2:在使用sendall()方法时出错
  • 问题2解决方案:通过阅读编译器提示的错误信息,得知先将要传输的数据用.encode()方法进行编码,才能在信道之间传输
  • 问题3:在程序结束后,不能打开解密后的文件
  • 问题3解决方案:通过阅读编译器提示的Warning信息,发现要在程序的最后加上对文件的关闭,即f.close()
  • 问题4:在服务器端中对文件的写出现IOError
  • 问题4解决方案:利用try-except-else方法来完成对异常的处理

其他(感悟、思考等)

第三次的实验难度果然加大了,对我们知识点整合的能力考察的更为具体。我们不仅需掌握套接字的建立,还要掌握对文件的读写操作以及Debug的调试等。
当然在这次实验中我依然发现了自己的诸多问题,例如没能静下心来阅读编译器提示的错误信息从而来找出自己代码中的错误,而在实际中,编译器给出的错误信息是十分重要的,它让我们在非Debug下就能找出代码的错误位置,从而找出具体错误。
同时,我对文件操作也还不够熟悉,什么可以写入到文件中,什么要通过编码或是解码才能写入到文件中。
总的来说,这倒数第二次实验,也是能够体现个人能力的综合实验,我完成的还不够熟练,仍需要在日后的学习中继续加深对Python的认识,加强逻辑思维能力的培养。

参考资料

  • 《python编程 从入门到实践》
posted @ 2020-05-16 12:16  Rua_ow  阅读(150)  评论(0编辑  收藏