• 20201324 2020-2021-2 《Python程序设计》实验三报告


    20201324 2020-2021-2 《Python程序设计》实验三报告

    课程:《Python程序设计》
    班级: 2013
    姓名: 徐源
    学号:20201324
    实验教师:王志强
    实验日期:2020年5月27日
    必修/选修: 公选课

    一、实验内容

    1. 创建:创建服务端和客户端,服务端在特定端口监听多个客户请求,选择一个通信端口,用Python语言编程实现通信演示程序;

    2. 通信:客户端和服务端通过Socket套接字(TCP/UDP)进行通信,要求包含文件的基本操作,例如打开和读写操作;

    3. 加密:要求发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中;

    4. 托管:程序代码托管到码云。

    二、实验过程及结果

    实验思路

    1. 先创建服务端和客户端,实现一个服务端对应一个客户端的功能,再尝试一个服务端响应多个客户端;
    2. 构建循环,使通信可以进行多次;
    3. 分别针对服务端和客户端,编写代码,实现文件传输与接受;
    4. 运用AES,实现对文件的加密和解密;
    5. 整合上述功能,形成完整程序。

    监听多个客户端

    创建服务端

    服务端

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 参数1:服务器之间网络通信;参数2:流式socket , for TCP
    # s = socket.socket()#服务器端的socket初始化
    s.bind(('127.0.0.1', 8001))#绑定. localhost = 127.0.0.1,port=0-65535
    s.listen(5)#监听
    socks = []  # 放每个客户端的socket
    

    将监听和处理放到不同的线程进行处理;
    将监听放入主线程,将处理放进子线程。

    客户端

    import socket
    #客户端的Socket初始化
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #参数1:服务器之间网络通信;参数2:流式socket , for TCP
    s.connect(('127.0.0.1', 8001))#连接,元组的形式,(IP地址,端口)
    
    str = input("请输入要传输的内容:")
    #s.sendall(str.encode())
    data = s.recv(1024)
    #print(data.decode())
    
    # print(data)
    
    s.close()
    

    构建循环通信

    必须放进一个while循环(如果不放进循环,监听一次就没了)

    代码来源

    def handle():
        while True:
            for k in socks:
                try:
                    data = k.recv(1024)  #到这里程序继续向下执行
                except Exception as e:
                    continue
                if not data:
                    socks.remove(k)
                    continue
    
    
    t = threading.Thread(target=handle)  # 子线程
    if __name__ == '__main__':
        t.start()
        print(r'我在%s线程中' % threading.current_thread().name)
        print('waiting for connecting ...')
        while True:
            clientSock, addr = s.accept()
            print('connected from:', addr)
            socks.append(clientSock)
    

    运行结果

    image

    通过TCP进行通信

    服务端

    接收文件

    def take_in(filename,s):
        while True:
            with open(filename, 'ab') as file:
                data = s.recv(1024)
                if data == b'quit':
                    break
                file.write(data)
            s.sendall('done'.encode())
        print("File reception has been completed!")
    

    发送文件

    def send_out(filename,s):
        with open(filename, 'rb') as file:
            i = file.read()
            s.send(i)
        s.send('quit'.encode())
        print("File has been sent out successfully!")
    

    客户端

    发送文件

    def send_out(filename):
        with open(filename, 'rb') as file:
            for i in file:
                CliSock.send(i)
                data = CliSock.recv(1024)
                if data != b'done':
                    break
        time.sleep(1)
        CliSock.send('quit'.encode())
        print("File has been sent out successfully")
    

    接收文件

    def take_in(af_filename):
        while True:
            with open(af_filename, 'ab') as file:
                data = CliSock.recv(1024)
                if data == b'quit':
                    break
                file.write(data)
            time.sleep(1)
            CliSock.sendall('done'.encode())
        print("File reception has been completed!")
    

    对文件的加密和解密

    image
    我选择使用AES加密和解密,前期需先下载Crypto模块;

    我下载时遇到了比较多的问题,后文详细描述,最后是通过在cmd和pycharm终端分别输入pip install pycrypto安装成功的

    将str补足为16的倍数

    代码来源

    注意!!密钥长度必须为16、24或32位,分别对应AES-128、AES-192和AES-256

    加密过程就是用pyCryptodome模块带的aes先将秘钥,以及要加密的文本填充为16位,随后对aes产生的字节码进行base64位编码,转为字符串的形式即可,解密思想逆过来即可。先逆向解密base64成bytes,执行解密密并转码返回str,将多余位数的’’替换为空

    def add_to_16(value):# str不是16的倍数那就补足为16的倍数
        while len(value) % 16 != 0:
            value += ''
        return str.encode(value)  # 返回bytes
    

    服务端加密

    def encrypt(filename,af_filename):#加密方法
        key = input("Please set a key:")
        text = open(filename,'rb').read()
        open(filename,'rb').close()
        text = str(text)
        aes = AES.new(add_to_16(key), AES.MODE_ECB)
        encrypt_aes = aes.encrypt(add_to_16(text))
        encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8') # 执行加密并转码返回bytes
        print('The encrypted contents are:',encrypted_text)
        logbat = open(af_filename, 'w')
        logbat.write(encrypted_text)
        logbat.close()
        print('File has been encrypted successfully!')
    

    客户端解密

    def decrypt(af_filename):
        key = input('
    Please enter the corresponding key:')
        text = str(open(af_filename, 'r').read())  # 密文文件
        open(af_filename, 'r').close()
        aes = AES.new(add_to_16(key), AES.MODE_ECB)  # 初始化加密器
        base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8'))  # 优先逆向解密base64成bytes
        decrypted_text = str(aes.decrypt(base64_decrypted), encoding='utf-8').replace('', '')  # 执行解密
        decrypted_text1 =decrypted_text.decode('utf-8')
        print("
    File has been decrypted successfully! the contents of the file are:")
        print(decrypted_text1)
    

    运行结果

    服务端

    image

    客户端

    image

    三、实验过程中遇到的问题和解决过程

    • 问题1:下载Crypto模块时,我在cmd输入pip install pycrypto,显示下载成功,但pycharm报错:ModuleNotFoundError: No module named 'Crypto'

    • 问题1 分析:早先在c盘和d盘都下过python,可能下载了Crypto的python与pycharm所连接的并不是同一个。

    • 问题1解决方法:在pycharm终端也输入一次pip install pycrypto,并查看python39文件,确定里面有Crypto文件。但又报错:“ModuleNotFoundError:No module named ‘Crypto.Cipher’”,这时应先卸载pycrypto,再pip install pycryptodome,即可image

    • 问题2:解密时报错
      image
      这段代码在运行时会报错:UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xa1 in position 0: invalid start byte

    • 问题2 分析:最初怀疑是用于加密的txt并不是用‘utf-8’保存的,或含有非法字符,但经检验可以排查这种假设
      image

      后经查找资料,认为可能是解码对参数的控制过于严格,我们不能改变errors参数的默认值,但可以覆盖默认错误=“strict”的处理程序
      image

      但这样修改后,程序运行后会出现无法识别的字符

    • 问题1解决方法:加一个eval()就可以了
      image

    四、其他(感悟、思考等)

       算是做的最艰难的一个实验了,因为之前下载过很多个python的锅,实验开始没多久,pycharm就崩了,pycharm小白查方法查了很久才修好。虽然实验思路出来得很快,但面对网络上各种各样的代码,整合的过程对我来说难度很大。尤其是接连报错的时候,是换一份代码来copy还是给现有的代码缝缝补补是个很值得考虑的问题。爆肝几个晚上搞好,最后往码云push的时候,电脑十分适时地坏了,本地D盘中一切与"python"有关的东西统统丢掉了。。本实验被迫重做,写了四分之三的实验报告被迫重写,找好的资料被迫重找。。
       感觉做大的项目,自信心和意志力甚至是比敲代码能力更重要的东西。在艰难的时候不放弃自己,遇到无法挽回的局面时有随时重新来过的勇气,这样才能走的更远吧。
    

    五、参考资料

  • 相关阅读:
    YYC松鼠视频pro版安装实操001
    YYC松鼠视频短信对接教程
    此处指讲解自定义的一些目录结构及组件-yyc松鼠短视频系统
    APP启动无视频数据-YYC松鼠短视频系统
    后台提示登录失败----YYC松鼠短视频开源
    C++静态成员变量和静态成员函数
    内联函数和宏定义的区别
    C++中的接口继承和实现继承
    拷贝构造函数(define)
    类的封装
  • 原文地址:https://www.cnblogs.com/cqszxy2020/p/14826279.html
Copyright © 2020-2023  润新知