day29 python socket实现文件上传下载功能 socketserver模块

day29 python socket实现文件上传下载功能 socketserver模块
 
一.写个文件上传的功能(类似于ftp文件上传的功能)
    1.上传文件需要考虑先传: 文件信息(包括文件名, 大小, md5, 和上传的动作)
    2.上传数据结构的组织: 防止出现黏包的现象(通过构造数据头部信息实现)
        上传的数据格式为: json_header+json+data
            json_header: 此字段固定长度为4字节(由struct模块实现), 用于取到完整的json
            json:此为记录文件信息,记录文件的各种信息
            data:通过json中文件长度,取文件的全部数据
#ftp_server
 
import socket
import json
import struct
import hashlib
ip_port = ('127.0.0.1', 65533)
server = socket.socket()
server.bind(ip_port)
server.listen(5)
print('ftp_server is running... ...')
while 1:
    conn, addr = server.accept()
    while 1:
        json_header = conn.recv(4)
        json_header = struct.unpack('i', json_header)[0]
        file_info_json = conn.recv(json_header)
        file_info_dict = json.loads(file_info_json)
        file_name = file_info_dict.get('file_name')
        file_size = file_info_dict.get('file_size')
        file_md5 = file_info_dict.get('file_md5')
        file_operation = file_info_dict.get('file_operation')
        if file_operation == 'put':
            recv_size = 0
            md5 = hashlib.md5(b'bajieaishuishui')
            with open('abc'+file_name, mode='wb') as f:      #出现过的问题: 文件19k, 但是接收的文件只有1k,(md5对的: 说明接收到的数据是完整的, 只是写文件的过程中有问题)
                while recv_size < file_size:                 #原因: 是把条件判断写在了文件打开的外面, 导致每次条件判断都先清空文件.最后只留下最后一次接收
                    free_size = file_size - recv_size        #解决方法: 条件判断和打开文件动作互换, 得以解决
                    if free_size < 1024:
                        recv_data = conn.recv(free_size)
                    else:
                        recv_data = conn.recv(1024)
                    recv_size += len(recv_data)
                    free_size = file_size - recv_size
                    f.write(recv_data)
                    md5.update(recv_data)
            recv_md5 = md5.hexdigest()
            if file_md5 == recv_md5:
                conn.send(b'203')
            else:
                conn.send(b'204')
                #上传
        elif file_operation == 'get':
            #下载
            pass
 
 
#ftp_client
 
import socket
import json
import struct
import os
import hashlib
ip_port = ('127.0.0.1', 65533)
def mymd5(filename):
    md5 = hashlib.md5(b'bajieaishuishui')
    with open(filename, mode='rb') as f:
        for line in f:
            md5.update(line)
        else:
            return md5.hexdigest()
 
client = socket.socket()
client.connect(ip_port)
while 1:
    cmds = input('>>> ')                                        #命令: put digit.py
    file_name = cmds.strip().split(' ')[1]
    file_operation = cmds.strip().split(' ')[0]
    file_size = os.path.getsize(file_name)
    file_md5 = mymd5(file_name)
    file_info_dict = {'file_name':file_name,
                      'file_operation':file_operation,
                      'file_size':file_size,
                      'file_md5':file_md5,
                      }
    file_info_json = json.dumps(file_info_dict)
    json_size = len(file_info_json)
    json_header = struct.pack('i',json_size)
    client.send(json_header)
    client.send(file_info_json.encode('utf-8'))
    with open(file_name, mode='rb') as f:
        for line in f:
            client.send(line)
    code = client.recv(1024).decode('utf-8')
    if code == '203':
        print('full send')
    elif code == '204':
        print('send error')
 
二.socketserver模块
    1.socketserver的使用
        多继承: 灵活
import socketserver
ip_port = ('127.0.0.1',65533)
class Myserver(socketserver.BaseRequestHandler):                    #自定义一个类
    def handle(self):                                               #方法名必须是这个名字
        print('socketserver is runing... ...')                      #这里是业务逻辑: 而且 conn 会封给 self.request
        while 1:
            try:
                data = self.request.recv(1024)
                self.request.send(data+b'bajieaishuishui')
            except:
                self.request.close()
server = socketserver.ThreadingTCPServer(ip_port, Myserver)          #socket.socket, bind, listen
server.serve_forever()                                               #accept
    2.解析socketserver的源码
 
 
三.ftp练习
    1.多用户同时登陆                                    (并发, 用socketserver模块实现)
    2.用户登录,加密认证                                 (使用hashlib MD5加密)
    3.上传/下载文件, 保证文件的一致性                   (对文件hashlib md5加密)
    4.传输过程中实现进度条
    5.不同用户家目录不同, 且只能访问自己的家目录        (os.path.join('',username, 'a.txt')
    6.对用户进行磁盘配额, 不同用户配额可不同            (上传,下载之前做文件夹大小的判断)
    7.用户登录server后, 可在家目录权限下切换子目录      (客户端向服务端发送命令, 服务端执行命令 subprocess.popen)
    8.查看当前目录下文件, 新建文件夹                    (dir )
    9.删除文件和空文件夹                                (也是执行命令)
    10.充分使用面向对象知识                             (类,反射)
    11.支持断点续传                                     ()
 
 
 
 

猜你喜欢

转载自www.cnblogs.com/aiaii/p/12217641.html