python day 14: 作业:开发一个能够多用户上传文件的FTP脚本
python day 14
2019/10/19
看了老师的FTP脚本之后,我下面的代码就是a piece of shit。不忍目睹。
1. 要求

FTP:
1,单独功能实现(进度条,断点续传)
2,整合
3,bin,config,db,lib程序目录
2. 自己写的程序目录

3. models模块
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import socketserver
import socket
import hashlib
import pickle
from config import settings
import subprocess
import chardet
def down_file(conn):
    conn.sendall('请输入文件路径'.encode('utf-8'))
    filename = conn.recv(1024).decode('utf-8')
    print(filename)
    path = os.path.join(settings.FILE_DB_DIR, filename)
    if not os.path.exists(path):
        conn.sendall(b'1000')
        filesize = int(conn.recv(1024).decode('utf-8'))
        print(filesize)
        conn.sendall(b'ack')
        has_data = 0
        content = bytes('',encoding='ISO-8859-1')
        while has_data<filesize:
            ret = conn.recv(1024)
            # print(chardet.detect(ret))
            content += ret
            has_data += len(ret)
        f = open(path,'wb')
        f.write(content)
        f.close()
    else:
        conn.sendall(b'1001')
        exist_file_size=os.stat(path).st_size
        conn.sendall(str(exist_file_size).encode('utf-8'))
def do_command(conn):
    conn.sendall('请输入命令'.encode('utf-8'))
    com1 = conn.recv(1024).decode('utf-8')  # ipconfig
    print(com1)
    result = subprocess.check_output(com1)
    # linux系统是以utf-8默认编码,windows是以gbk默认编码,所以此处result是以gbk编码的bytes,折腾了两个小时
    # print(result.decode('gbk'))
    conn.sendall(str(len(result)).encode('utf-8'))  # 1638
    print(conn.recv(1024))  # b'lan'
    conn.sendall('ack'.encode('utf-8'))
    print(conn.recv(1024))  # b'ack'
    result = result.decode('gb2312').encode('utf-8')
    # print(chardet.detect(result))
    conn.sendall(result)
def login(conn, name, pwd):
    m = hashlib.md5(bytes('lan', encoding='utf-8'))
    m.update(bytes(pwd, encoding='utf-8'))
    hex1 = m.hexdigest()
    path = os.path.join(settings.CLIENT_DB_DIR, name)
    result = pickle.load(open(path, 'rb'))
    username, password = result.split('$')
    if username == name and password == hex1:
        conn.sendall('登录成功'.encode('utf-8'))
        return 1
    else:
        conn.sendall('密码错误'.encode('utf-8'))
        return 0
def register(conn, name, pwd):
    m = hashlib.md5(bytes('lan', encoding='utf-8'))
    m.update(bytes(pwd, encoding='utf-8'))
    hex1 = m.hexdigest()
    s1 = '$'.join([name, hex1])
    print(s1)
    path = os.path.join(settings.CLIENT_DB_DIR, name)
    pickle.dump(s1, open(path, 'wb'))
    conn.sendall('用户{0}注册成功'.format(name).encode('utf-8'))
def connect_user(conn, addr1):
    inp = '请输入用户名与密码'.encode('utf-8')
    conn.sendall(inp)
    name = conn.recv(1024).decode('utf-8')
    pwd = conn.recv(1024).decode('utf-8')
    inp2 = '1是登录;2是注册,请输入数字进行选择'.encode('utf-8')
    conn.sendall(inp2)
    ret = conn.recv(1024).decode('utf-8')
    print('来自%s的消息:\n>>>%s' % (addr1[0], ret))
    if ret == '2':
        register(conn, name, pwd)
    if ret == '1':
        result = login(conn, name, pwd)
        if result:
            while True:
                inp3 = '3是执行命令;4是上传文件,请输入数字进行选择'.encode('utf-8')
                conn.sendall(inp3)
                ret2 = conn.recv(1024).decode('utf-8')
                print('来自%s的消息:\n>>>%s' % (addr1[0], ret2))
                if ret2 == '3':
                    do_command(conn)
                elif ret2 == '4':
                    down_file(conn)
                elif ret == 'q':
                    break
class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        conn, addr2 = self.request, self.client_address
        connect_user(conn, addr2)
        # size_str = conn.recv(1024).decode('utf-8')
        # total_size_int = int(size_str)
        # print('来自%s的消息:\n>>>文件大小是%s' % (addr[0], total_size_int))
        # has_data = 0
        # file_name = conn.recv(1024).decode('utf-8')
        # print('来自%s的消息:\n>>>文件名字是%s' % (addr[0], file_name))
        # conn.sendall('ack'.encode('utf-8'))
        # f = open(file_name, 'wb')
        # while True:
        #     if has_data == total_size_int:
        #         break
        #     ret = conn.recv(1024)
        #     f.write(ret)
        #     has_data += len(ret)
        # f.close()
# class MySocket(socket.socket):
#     def __init__(self, family=-1, type=-1, proto=-1, fileno=None):
#         self.name = None
#         self.pwd = None
#         super().__init__(family, type, proto, fileno)
#
#     def login(self, user, pwd):
#         if self.name == user and self.pwd == pwd:
#             return True
#         else:
#             return False
#
#     def register(self, user, pwd):
#         self.name = user
#         m = hashlib.md5()
#         m.update(bytes(pwd, encoding='utf-8'))
#         password = m.hexdigest()
#         self.pwd = password
if __name__ == '__main__':
    addr = ('192.168.131.1', 9999,)
    tcp_server = socketserver.ThreadingTCPServer(addr, MyServer)
    tcp_server.serve_forever()
4. settings模块
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
CLIENT_DB_DIR = os.path.join(BASE_DIR, 'db', 'client')
FILE_DB_DIR= os.path.join(BASE_DIR, 'db', 'file')
5. tcp_server模块
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import pickle
from lib.models import *
def main():
    addr = ('192.168.131.1', 9999,)
    tcp_server = socketserver.ThreadingTCPServer(addr, MyServer)
    tcp_server.serve_forever()
if __name__ == '__main__':
    main()
6. client模块
import os, sys
import socket
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from lib.models import *
import hashlib
import getpass
import chardet
import pickle
def recv_com(obj):
    file_size = int(obj.recv(1024).decode('utf-8'))
    print(file_size)  # 1857
    has_data = 0
    obj.sendall('lan'.encode('utf-8'))
    print(obj.recv(1024))  # b'ack
    obj.sendall(b'ack')
    ret3 = ''
    while has_data < file_size:
        data = obj.recv(1024)
        # print(chardet.detect(data))
        ret3 += data.decode('utf-8')
        has_data += len(data)
        # has_data = len(obj.recv(1024)) 这里还会再执行一次接收数据动作,所以就是这里卡住了。
    print(ret3)
def load_file(obj):
    command1 = obj.recv(1024).decode('utf-8')  # 文件路径
    print(command1)
    file_path = input('文件路径是:\n>>>').strip()
    file_name = os.path.split(file_path)[1]
    obj.sendall(file_name.encode('utf-8'))
    ret_code = obj.recv(1024)
    if ret_code ==b'1000':
        file_size = os.stat(file_path).st_size  # int类型
        obj.sendall(str(file_size).encode('utf-8'))
        obj.recv(1024)
        with open(file_path, 'rb') as f:
            for i in range(1,file_size+1):
                file_content = f.read(1)
                obj.sendall(file_content)
                sys.stdout.write('\r')
                sys.stdout.write('%.2f%% |%s' % (i / file_size * 100, int(i / file_size * 100) * '#'))
                sys.stdout.flush()
    elif ret_code==b'1001':
        pass
def connect_server():
    obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    addr = ('192.168.131.1', 9999,)
    obj.connect(addr)
    ret_str = obj.recv(1024).decode('utf-8')
    print('来自%s的消息:\r\n>>>%s' % (addr[0], ret_str))
    user = input('请输入用户名:>>>').strip()
    obj.sendall(user.encode('utf-8'))
    pwd = getpass.win_getpass('password:')
    obj.sendall(pwd.encode('utf-8'))
    result2 = str(obj.recv(1024), encoding='utf-8')  # 1是登录;2是注册,请输入数字进行选择
    print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,))
    inp = input('请输入发送给%s的消息:\n>>>' % addr[0]).strip()  # 1
    obj.sendall(inp.encode('utf-8'))
    result2 = str(obj.recv(1024), encoding='utf-8')
    print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,))  # 登录成功
    while True:
        result2 = str(obj.recv(1024), encoding='utf-8')
        print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,))
        # 3是执行命令;4是上传文件,请输入数字进行选择
        inp = input('请输入发送给%s的消息:\n>>>' % addr[0]).strip()
        obj.sendall(inp.encode('utf-8'))  # 3
        if inp == '3':
            result2 = str(obj.recv(1024), encoding='utf-8')
            print('来自%s的消息:\r\n>>>%s' % (addr[0], result2,))  # 请输入命令
            inp = input('请输入发送给%s的消息:\n>>>' % addr[0]).strip()
            obj.sendall(inp.encode('utf-8'))  # ipconfig
            recv_com(obj)
        elif inp == '4':
            load_file(obj)
        elif inp == 'q':
            obj.close()
            break
def main():
    '''
    客户端主程序
    :return:
    '''
    connect_server()
    # ret = obj.recv(1024).decode('utf-8')
    # print('来自%s的消息:\n>>>%s' % (addr[0], ret))
    # inp = input('请输入要传送的文件路径:\n>>>').strip()
    # size = str(os.stat(inp).st_size, encoding='utf-8')
    # file_name = os.path.split(inp)[1]
    # obj.sendall(size.encode('utf-8'))
    # obj.sendall(file_name.encode('utf-8'))
    # obj.recv(1024)
    # with open(inp, 'rb') as f:
    #     for line in f:
    #         if line:
    #             obj.sendall(line)
    #         else:
    #             print('传送完毕')
    #             break
    # obj.close()
if __name__ == '__main__':
    main()
7. 后记
只实现了多用户md5登录,命令执行,文件传递,进度条显示,并没有实现文件续传功能。
还需要修改。不过也折腾了近5个小时,在编码的转换问题上折腾了好久。
下次一定要记住使用chardet模块的detect方法先检测下编码,然后按照对应的编码方式进行编码与解码。
python day 14: 作业:开发一个能够多用户上传文件的FTP脚本的更多相关文章
- java 26 - 9 网络编程之 TCP协议多用户上传文件
		TCP实现多用户上传文件: 需要同时给多用户上传文件,这样就得用多线程来实现. 实际上,这样的话,上传的先后顺序和速度就跟客户端的带宽有关:带宽够,就容易抢占到线程的执行权: 首先,创建个线程类:(这 ... 
- 【HTTP】boundary 中一个 = 导致HTTP上传文件失败
		(1)#define ABOUNDARY "----=_Resume_002_0CE7_01D1C649.298A8070" (2)#define ABOUNDARY " ... 
- 朋友封装的一个ASP.NET上传文件的方法
		朋友做了asp.net开发多年,做了这个,自我感觉封装得还不错!!! 代码如下: #region 上传文件的方法 /// <summary> /// 上传文件方法 /// </sum ... 
- 一个Jmeter模拟上传文件接口的实例
		资料参考:https://blog.csdn.net/u010390063/article/details/78329373 项目中,避免不了要用到很多上传文件.图片的接口,那么碰到这类接口该如何进行 ... 
- IOS开发教程之put上传文件的服务器的配置及实例分享-备用
		感谢大神分享 1,HTTP常见的方法 GET 获取指定资源 POST 2M 向指定资源提交数据进行处理请求,在RESTful风格中用于新增资源 HEAD 获取指定资源头部信息PUT 替换指定资源(不支 ... 
- python 从windows上传文件到linux脚本
		import paramiko import datetime import os hostname = '192.168.112.132' username = 'root' password = ... 
- git从无到有建立一个仓库并上传文件
		第一步,创建仓库 登录自己的码云 第二步,本地操作 1.到你所要上传的文件夹中右键 选择git bash here 2.初始化项目 git init 3.连接远程仓库 刚才我们建立的时候的远程地址就 ... 
- python 开发一个支持多用户在线的FTP
		### 作者介绍:* author:lzl### 博客地址:* http://www.cnblogs.com/lianzhilei/p/5813986.html### 功能实现 作业:开发一个支持多用 ... 
- Python3学习之路~8.6 开发一个支持多用户在线的FTP程序-代码实现
		作业: 开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ... 
随机推荐
- SpringBoot——配置文件占位符
			在配置文件中采用: ${random.int} 获取一个随机值. 
- Go1.13 标准库的 http 包爆出重大 bug,你的项目中招了吗? 原创: 王亚楼  Go语言中文网  今天
			Go1.13 标准库的 http 包爆出重大 bug,你的项目中招了吗? 原创: 王亚楼 Go语言中文网 今天 
- 将innodb置为只读模式
			1.关闭change bufferset global.innodb_change_buffering=0; 2.将mysql执行slow shutdown(即干净关闭)set global.inno ... 
- tomcat高并发优化的参数优化并查看tomcat线程数
			在Tomcat配置文件conf下面 server.xml 中的配置中和连接数相关的参数有: minProcessors:最小空闲连接线程数,用于提高系统处理性能,默认值为10 maxProcessor ... 
- (转)LoadRunner之录制你的第一个脚本
			LoadRunner安装完成之后,肯定就迫不及待的想要上手试用了.下面就是讲一下LR脚本录制的流程和基本的设置. 1.先放一张脚本录制以及运行的流程图 2.脚本录制步骤 1)以管理员身份打开LR软件, ... 
- ubuntu 本地生成被浏览器信任的证书
			vhosts添加https证书两步: 1:生成证书: sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl ... 
- jstl标签库使用报错index_jsp.java找不到问题
			初学jstl的时候记得只需要讲jstl和standard的jar放在lib下面,然后jsp中使用对应导入语法就可以使用标签库了. 但那时候用的是myeclipes,myeclipes的导包的过程记得是 ... 
- PAT-2019年冬季考试-甲级 7-3 Summit (25分) (邻接矩阵存储,直接暴力)
			7-3 Summit (25分) A summit (峰会) is a meeting of heads of state or government. Arranging the rest ar ... 
- 【Docker学习之三】Docker查找拉取镜像、启动容器、容器使用
			环境 docker-ce-19.03.1-3.el7.x86_64 CentOS 7 一.查找.拉取镜像.启动容器1.查找镜像-docker search默认查找Docker Hub上的镜像,举例:D ... 
- cocoapods安装 Unable to download data from http://ruby.taobao.org/  &  don't have write permissions for the /Library/Ruby/Gems/2.0.0 directory.
			安装cocoapods,记录两个问题! 1.镜像已经替换成了 http://ruby.taobao.org/, 还是不能不能安装cocoapods, 报错:Unable to download dat ... 
