课程:《Python程序设计》
班级: 1924
姓名: 陈瀚文
学号: 20192426
实验教师:王志强
实验日期:2020年5月16日
必修/选修: 公选课
1.实验内容
创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。
2. 实验过程及结果
实验过程:
-
首先,我构思了整体代码的布局:先由客户端使用base64加密密钥并传输给服务端,服务端接收密钥后解密得到密钥,之后客户端读取文件并将文件内容使用密钥进行DES加密后发送给服务端,服务端接收文件后使用密钥解密并保存到文件中。
-
接着,我根据所需要实现的功能导入了以下模块:
import socket import os from Cryptodome.Cipher import DES import base64
-
之后是代码部分,服务端的代码如下(码云直达):
# -*- encoding: utf-8 -*- ''' 文件: Experiment3S.py 时间: 2020/05/16 13:37:02 作者: 20192426 陈瀚文 ''' import socket import os from Cryptodome.Cipher import DES import base64 os.chdir("D:\网空专业\大一下\Python程序设计\Learnpython\Experiment") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 8080)) # 绑定地址到套接字 s.listen() # 开启TCP监听 conn, address = s.accept() # 等待连接到来 print("来自", address, "的信息:", conn.recv(1024).decode()) # 接收客户端的信息 conn.sendall("请发送密钥!".encode()) # 向客户端请求密钥 key = base64.b64decode(conn.recv(1024)) # 接收密钥并解密 conn.sendall("已收到密钥!".encode()) # 反馈信息 print("密钥为:", key) # 输出密钥 des = DES.new(key, DES.MODE_ECB) # 创建一个DES实例 name = conn.recv(1024) # 接收文件名 print("来自", address, "的文件:", name.decode()) # 打印接收到的文件名 data = conn.recv(1024) # 接收文件内容 # 将接收到的内容保存到文件Ex3receive.txt中 f = open("Ex3receive.txt", "w", encoding="utf8") f.write(des.decrypt(data).decode().rstrip( ' ')) f.close() print("来自", address, "的信息:", des.decrypt(data).decode().rstrip( ' '), "已保存为receive.txt") # 打印接收到的信息 conn.sendall("服务器已经收到了数据内容!".encode()) # 与客户端进行交互 data = conn.recv(1024) # 接收反馈 s.close() # 关闭套接字
-
根据已有的服务端的代码,我完成了客户端代码的编写,首先,导入和服务端相同的模块。
import socket import os from Cryptodome.Cipher import DES import base64
-
接着,通过参考资料我定义了一个函数pad(),用于将加密文本的大小补足为8的倍数。
def pad(text): """ 参考:https://blog.csdn.net/yangxiaodong88/article/details/80801278 ### 加密函数,如果text不是8的倍数【加密文本text必须为8的倍数!】,那就补足为8的倍数 :param text: :return: """ while len(text) % 8 != 0: text += ' ' return text
-
最后完成了客户端函数的主体部分:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 8080)) # 初始化TCP服务器连接 key = "qwerasdf".encode() # 将密钥编码为二进制格式 des = DES.new(key, DES.MODE_ECB) # 创建DES实例 str1 = input("请输入要传输的文件名:") # 输入文件名 s.sendall("请接收密钥!".encode()) # 提示服务端接收密钥 print("来自 ('127.0.0.1', 8080) 的信息:", s.recv(1024).decode()) # 接收服务端反馈 s.sendall(base64.b64encode(key)) # 发送加密的密钥 print("来自 ('127.0.0.1', 8080) 的信息:", s.recv(1024).decode()) # 接收服务端反馈 s.sendall(str1.encode()) # 发送文件名 os.chdir("D:\网空专业\大一下\Python程序设计\Learnpython\Experiment") file = open('{}'.format(str1), 'r', encoding="utf8") # 打开目标文件 text = file.read() # 读取文件信息 # 参考了https://blog.csdn.net/yangxiaodong88/article/details/80801278 padded_text = pad(text) encrypted_text = des.encrypt(padded_text.encode('utf-8')) # 加密 s.sendall(encrypted_text) # 发送文件信息 file.close() data = s.recv(1024) # 接收反馈信息 print("来自 ('127.0.0.1', 8080) 的信息:", data.decode()) # 打印接收到的信息 s.sendall("收到".encode()) # 回复服务器 s.close() # 关闭套接字
-
客户端的代码如下(码云直达):
# -*- encoding: utf-8 -*- ''' 文件: Experiment3C.py 时间: 2020/05/16 13:46:56 作者: 20192426 陈瀚文 ''' import socket import os from Cryptodome.Cipher import DES import base64 def pad(text): """ 参考:https://blog.csdn.net/yangxiaodong88/article/details/80801278 ### 加密函数,如果text不是8的倍数【加密文本text必须为8的倍数!】,那就补足为8的倍数 :param text: :return: """ while len(text) % 8 != 0: text += ' ' return text s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 8080)) # 初始化TCP服务器连接 key = "qwerasdf".encode() # 将密钥编码为二进制格式 des = DES.new(key, DES.MODE_ECB) # 创建DES实例 str1 = input("请输入要传输的文件名:") # 输入文件名 s.sendall("请接收密钥!".encode()) # 提示服务端接收密钥 print("来自 ('127.0.0.1', 8080) 的信息:", s.recv(1024).decode()) # 接收服务端反馈 s.sendall(base64.b64encode(key)) # 发送加密的密钥 print("来自 ('127.0.0.1', 8080) 的信息:", s.recv(1024).decode()) # 接收服务端反馈 s.sendall(str1.encode()) # 发送文件名 os.chdir("D:\网空专业\大一下\Python程序设计\Learnpython\Experiment") file = open('{}'.format(str1), 'r', encoding="utf8") # 打开目标文件 text = file.read() # 读取文件信息 # 参考了https://blog.csdn.net/yangxiaodong88/article/details/80801278 padded_text = pad(text) encrypted_text = des.encrypt(padded_text.encode('utf-8')) # 加密 s.sendall(encrypted_text) # 发送文件信息 file.close() data = s.recv(1024) # 接收反馈信息 print("来自 ('127.0.0.1', 8080) 的信息:", data.decode()) # 打印接收到的信息 s.sendall("收到".encode()) # 回复服务器 s.close() # 关闭套接字
实验结果:
服务端:
客户端:
后续:
在这之后,我使用了我的阿里云服务器进行了测试,以该服务器作为服务端,修改了部分代码,其中,将服务端的绑定地址修改为了172.17.232.247(服务器内网IP),将客户端连接地址修改为了39.96.51.81(服务器公网IP),完成了远程连接,结果如下:
服务端(码云直达):
客户端(码云直达):
3. 实验过程中遇到的问题和解决过程
- 问题1:在进行加密解密的时候,出现了'***' has type str, but expected one of: bytes
- 问题1解决方案:通过encode函数将对象转换成二进制类型,报错消失。
- 问题2:在远程服务器上运行代码时,错将socket绑定至公网IP,导致无法连接端口
- 问题2解决方案:查询到了服务器的内网IP,将服务端的socket绑定至内网IP上,正确运行。
其他(感悟、思考等)
- 在传输使用对称加密算法加密的文件时密钥的传输也应当注意安全,可以利用base64等算法加密密钥再将密钥传输给服务端。
- 通过上课以及本次实验,我对socket网络编程有了进一步地认识,同时对于网络传输的大概过程也有了一定的了解。
- python的种类繁多的第三方库使得python这种语言使用起来非常舒服,使得一些较为复杂的过程可以轻松实现