zoukankan      html  css  js  c++  java
  • python利用socketserver实现并发套接字功能

    本文实现利用python的socketserver这个强大的模块实现套接字的并发

    目录结构如下:

    测试文件请放在server_file文件夹里面

    server.py

    #!/usr/bin/env python
    # -*- coding: gbk -*-
    # @Version  : Python 3.5.2
    # @Time    : 2018/1/24 10:29
    # @Author  : Ncp
    # @File    : server.py
    # @Software: PyCharm
    
    import json
    import time
    import hashlib
    import struct
    import os
    from socketserver import *
    
    FILE_PATH = os.path.dirname(os.path.abspath(__file__))+'\server_file'
    
    class MYserver(BaseRequestHandler):   # 设置一个类,基础BaseRequestHandler这个类
        def handle(self):                 # 这个方法下添加通信功能(和上面创建类一样,这是socketserver的固定模式)
            print(self.client_address)
            '''
            :functions: 使用socketserver的并发套接字,提供客户端下载文件,并对文件进行MD5加密
            '''
            while True:
                try:
                    data = self.request.recv(1024)
                    data_recv = data.decode('gbk').split()
                    if not os.path.exists(FILE_PATH+r'\%s' %data_recv[1]):
                        self.request.send('file is not found'.encode('gbk'))
                        continue
                    else:
                        data = self.request.send('1'.encode('gbk'))  # 这里发现小问题,不回复一个信息的话,发送给客户端的包头居然成了没有封装
                        FILE_SIZE = os.path.getsize(FILE_PATH+r'\%s' %data_recv[1])
                        with open(FILE_PATH+r'\%s' %data_recv[1],'rb')as f:
                            hash_file = f.read()
                        m = hashlib.md5()
                        m.update(hash_file)
                        m_hex = m.hexdigest()
                        file_header = {'filename':data_recv[1],
                                       'filesize':FILE_SIZE,
                                       'md5':m_hex,
                                       'time':time.strftime('%Y-%m-%d-%X',time.localtime())
                                       }
                        # 包头信息序列化
                        file_header_dump = json.dumps(file_header)
                        # 编译成2进制
                        file_header_bytes = file_header_dump.encode('gbk')
                        # 封装报头
                        file_header_struct = struct.pack('i',len(file_header_bytes))
                        # 发送报头
                        self.request.send(file_header_struct)
                        # 发送报文内容
                        self.request.send(file_header_bytes)
                        # 发送文件数据
                        send_size = 0
                        with open(FILE_PATH+r'\%s' %data_recv[1] , 'rb')as f:
                            for i in f:
                                self.request.send(i)
                                send_size += len(i)   # 这里后续可以拓展一个进度或者网速显示功能
                except Exception:
                    self.request.close()
    
    
    if __name__ == '__main__':
        server = ThreadingTCPServer(('127.0.0.1',8080),MYserver)  # windows下只能开启多线程
        server.serve_forever()
    View Code

    client.py

    #!/usr/bin/env python
    # -*- coding: gbk -*-
    # @Version  : Python 3.5.2
    # @Time    : 2018/1/24 10:29
    # @Author  : Ncp
    # @File    : client.py
    # @Software: PyCharm
    
    from socket import *
    import os,sys
    import hashlib
    import struct
    import math
    import json
    
    FILE_PATH = os.path.dirname(os.path.abspath(__file__))+'\client_file'
    
    
    # 显示下载进度条功能,可以拓展为显示下载速度(提示,因为每次传输4096个字节,那么下载网速为KB/S,1KB个字节=1024B(字节),那么1s传输了多少个字节呢?)
    def progress(recvd, total):
        fraction = '{:.0%}'.format(recvd / total)
        sys.stdout.write('
    [%-30s] %s' % ('#' * int(math.floor(recvd * 30 / total)), fraction))
        sys.stdout.flush()
        if recvd == total:
            sys.stdout.write('
    ')
    
    
    # 主函数
    def run(ip,addr):
        client = socket(AF_INET,SOCK_STREAM)
        client.connect((ip,addr))
        while True:
            user_input = input('>>').strip()
            cmd = user_input.split()
            if len(cmd) != 2:
                print('input format is error please use:get xx')
                continue
            if cmd[0] == 'get':
                client.send(user_input.encode('gbk'))
                data = client.recv(1024)
                data_recv = data.decode('gbk')
                if data_recv == 'file is not found':
                    print(data_recv)
                    continue
            else:
                print('commands is not found')
                continue
            # 收包头,然后一系列处理
            header = client.recv(4)
            if not header:break
            header_json_len = struct.unpack('i', header)[0]
            header_json_bytes = client.recv(header_json_len)
            header_josn = header_json_bytes.decode('gbk')
            header_dic = json.loads(header_josn)
            # 去除包头内容进行下载
            print(header_dic)
            data_len = header_dic['filesize']
            data_file = header_dic['filename']
            data_md5 = header_dic['md5']
            recv_size = 0
            with open(FILE_PATH+r'\%s' %data_file,'wb')as fw:
                while recv_size < data_len:
                    recv_data = client.recv(4096)
                    recv_size += len(recv_data)
                    fw.write(recv_data)
                    progress(recv_size,data_len)
                print('Download completion, start validation')
            # 收到文件后,读取文件进行加密,看是否与服务端下载的文件一致!
            with open(FILE_PATH+r'\%s' %data_file,'rb')as fr:
                data_total = fr.read()
    
            m = hashlib.md5()
            m.update(data_total)
            m_hex = m.hexdigest()
    
            if m_hex == data_md5:
                print('文件验证通过')
            else:
                print('文件损坏,删除文件')
                os.remove(FILE_PATH+r'\%s' %data_file)
    
    
    if __name__ == '__main__':
        run('127.0.0.1',8080)
    View Code

    自己可以设置一个多用户登录,然后测试,用户下载同一个文件,分别存入每个用户自己的家目录下面,效果更好。

    当然现在也能测试,开启两个客户端同时下载文件。

  • 相关阅读:
    HCIA_R&S-学习_Day05(PPPoE、DHCP、ACL、NAT)
    HCIA_R&S-学习_Day04(链路状态协议OSPF & PPP)
    HCIA_R&S-学习_Day03(路由协议基础与实现)
    【详谈 Delta Lake 】系列技术专题 之 湖仓一体( Lakehouse )
    工作7年,我的10条经验总结
    Hologres揭秘:优化COPY,批量导入性能提升5倍+
    谈谈JVM内部锁升级过程
    如何帮用户管好云账本?阿里云数据库助力收钱吧 | 甲子光年
    重磅 | 数据库自治服务DAS论文入选全球顶会SIGMOD,领航“数据库自动驾驶”新时代
    同程旅行基于 RocketMQ 高可用架构实践
  • 原文地址:https://www.cnblogs.com/encp/p/8358432.html
Copyright © 2011-2022 走看看