声明:

  该项目参考学习地址:

    http://www.cnblogs.com/lianzhilei/p/5869205.html , 感谢博主分享,如有侵权,立即删除。

作业:开发一个支持多用户在线的FTP程序

要求:

  1. 用户加密认证
  2. 允许同时多用户登录
  3. 每个用户有自己的家目录 ,且只能访问自己的家目录
  4. 对用户进行磁盘配额,每个用户的可用空间不同
  5. 允许用户在ftp server上随意切换目录
  6. 允许用户查看当前目录下文件
  7. 允许上传和下载文件,保证文件一致性
  8. 文件传输过程中显示进度条
  9. 附加功能:支持文件的断点续传

程序:

1、README

  1. # 作者介绍:
  2. author: hkey
  3.  
  4. # 博客地址:
  5.  
  6. # 功能实现:
  7.  
  8. 作业:开发一个支持多用户在线的FTP程序
  9.  
  10. 要求:
  11.  
  12. 用户加密认证
  13. 允许同时多用户登录
  14. 每个用户有自己的家目录 ,且只能访问自己的家目录
  15. 对用户进行磁盘配额,每个用户的可用空间不同
  16. 允许用户在ftp server上随意切换目录
  17. 允许用户查看当前目录下文件
  18. 允许上传和下载文件,保证文件一致性
  19. 文件传输过程中显示进度条
  20. 附加功能:支持文件的断点续传
  21.  
  22. # 目录结构:
  23.  
  24. FTP/
  25. ├── ftp_client/ # ftp客户端程序
  26.    ├── ftp_client.py # 客户端主程序
  27.    ├── __init__.py
  28. └── ftp_server/ # ftp服务端程序
  29. ├── conf/ # 配置文件目录
  30.    ├── __init__.py
  31.    └── settings.py
  32. ├── database/ # 用户数据库
  33.    ├── hkey.db
  34.    └── xiaofei.db
  35. ├── ftp_server.py
  36. ├── home/ # 用户家目录
  37.    ├── hkey/
  38.    └── xiaofei/
  39. ├── __init__.py
  40. ├── log/
  41. └── modules/ # 程序核心功能目录
  42. ├── auth_user.py
  43. ├── __init__.py
  44. └── socket_server.py
  45.  
  46. # 功能实现:
  47.  
  48. 1. 初始化配置在conf下的settings.py 文件里声明,第一次运行创建用户家目录(home/)和数据文件(database/)
  49. 2. 每个用户的磁盘配额为10M, conf/settings.py 中声明, 可以修改
  50. 3. 本程序适用于windows,命令:cd / mkdir / pwd / dir / put / get
  51. 4. 实现了get下载续传的功能:
  52. 服务器存在文件, 客户端不存在,直接下载;
  53. 服务器存在文件, 客户端也存在文件,比较大小, 一致则不传,不一致则追加续传;
  54.  
  55. # 状态码:
  56. 400 用户认证失败
  57. 401 命令不正确
  58. 402 文件不存在
  59. 403 创建文件已经存在
  60. 404 磁盘空间不够
  61. 405 不续传
  62.  
  63. 200 用户认证成功
  64. 201 命令可以执行
  65. 202 磁盘空间够用
  66. 203 文件具有一致性
  67. 205 续传
  1. # 作者介绍:
  2. author: hkey
  3.  
  4. # 博客地址:
  5. http://www.cnblogs.com/hukey/p/8909046.html
  6.  
  7. # 功能实现:
  8.  
  9. 作业:开发一个支持多用户在线的FTP程序
  10.  
  11. 要求:
  12.  
  13. 用户加密认证
  14. 允许同时多用户登录
  15. 每个用户有自己的家目录 ,且只能访问自己的家目录
  16. 对用户进行磁盘配额,每个用户的可用空间不同
  17. 允许用户在ftp server上随意切换目录
  18. 允许用户查看当前目录下文件
  19. 允许上传和下载文件,保证文件一致性
  20. 文件传输过程中显示进度条
  21. 附加功能:支持文件的断点续传
  22.  
  23. # 目录结构:
  24.  
  25. FTP/
  26. ├── ftp_client/ # ftp客户端程序
  27.    ├── ftp_client.py # 客户端主程序
  28.    ├── __init__.py
  29. └── ftp_server/ # ftp服务端程序
  30. ├── conf/ # 配置文件目录
  31.    ├── __init__.py
  32.    └── settings.py
  33. ├── database/ # 用户数据库
  34.    ├── hkey.db
  35.    └── xiaofei.db
  36. ├── ftp_server.py
  37. ├── home/ # 用户家目录
  38.    ├── hkey/
  39.    └── xiaofei/
  40. ├── __init__.py
  41. ├── log/
  42. └── modules/ # 程序核心功能目录
  43. ├── auth_user.py
  44. ├── __init__.py
  45. └── socket_server.py
  46.  
  47. # 功能实现:
  48.  
  49. 1. 初始化配置在conf下的settings.py 文件里声明,第一次运行创建用户家目录(home/)和数据文件(database/)
  50. 2. 每个用户的磁盘配额为10M, conf/settings.py 中声明, 可以修改
  51. 3. 本程序适用于windows,命令:cd / mkdir / pwd / dir / put / get
  52. 4. 实现了get下载续传的功能:
  53. 服务器存在文件, 客户端不存在,直接下载;
  54. 服务器存在文件, 客户端也存在文件,比较大小, 一致则不传,不一致则追加续传;
  55.  
  56. # 状态码:
  57. 400 用户认证失败
  58. 401 命令不正确
  59. 402 文件不存在
  60. 403 创建文件已经存在
  61. 404 磁盘空间不够
  62. 405 不续传
  63.  
  64. 200 用户认证成功
  65. 201 命令可以执行
  66. 202 磁盘空间够用
  67. 203 文件具有一致性
  68. 205 续传
  69.  
  70. 000 系统交互码

README

2、程序的结构

3、ftp客户端程序

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import socket
  4. import os, json, sys
  5.  
  6. class Myclient(object):
  7. def __init__(self, ip_port):
  8. self.client = socket.socket()
  9. self.ip_port = ip_port
  10.  
  11. def connect(self):
  12. self.client.connect(self.ip_port)
  13.  
  14. def start(self):
  15. self.connect()
  16. while True:
  17. username = input('输入用户名:').strip()
  18. password = input('输入密码:').strip()
  19. login_info = '%s:%s' % (username, password)
  20. self.client.sendall(login_info.encode())
  21. status_code = self.client.recv(1024).decode()
  22. if status_code == '':
  23. print('[%s] 用户密码错误!' % status_code)
  24. elif status_code == '':
  25. print('[%s] 登录成功!' % status_code)
  26. self.interactive()
  27.  
  28. def interactive(self):
  29. while True:
  30. command = input('-->').strip()
  31. if not command: continue
  32. command_str = command.split()[0]
  33. if hasattr(self, command_str):
  34. func = getattr(self, command_str)
  35. func(command)
  36.  
  37. def get(self, command):
  38. self.client.sendall(command.encode())
  39. status_code = self.client.recv(1024).decode()
  40. if status_code == '':
  41. filename = command.split()[1]
  42. print(filename)
  43. if os.path.isfile(filename):
  44. self.client.sendall(''.encode())
  45. revice_size = os.stat(filename).st_size
  46. response = self.client.recv(1024)
  47. self.client.sendall(str(revice_size).encode())
  48. status_code = self.client.recv(1024).decode()
  49. print('-----------------')
  50. if status_code == '':
  51. print('[%s] 续传' % status_code)
  52. self.client.sendall(''.encode())
  53. elif status_code == '':
  54. print('[%s] 文件一致。' % status_code)
  55. return
  56. else:
  57. self.client.sendall(''.encode())
  58. revice_size = 0
  59.  
  60. file_size = self.client.recv(1024).decode()
  61. file_size = int(file_size)
  62. response = self.client.sendall(''.encode())
  63. with open(filename, 'ab') as file:
  64. while revice_size != file_size:
  65. data = self.client.recv(1024)
  66. revice_size += len(data)
  67. file.write(data)
  68. self.__progress(revice_size, file_size, '下载中')
  69. else:
  70. print('[%s] Error!' % status_code)
  71.  
  72. def put(self, command):
  73. if len(command.split()) > 1:
  74. filename = command.split()[1]
  75. if os.path.isfile(filename):
  76. self.client.sendall(command.encode())
  77. response = self.client.recv(1024)
  78. file_size = os.stat(filename).st_size
  79. self.client.sendall(str(file_size).encode())
  80. status_code = self.client.recv(1024).decode()
  81. if status_code == '':
  82. with open(filename, 'rb') as file:
  83. for line in file:
  84. send_size = file.tell()
  85. self.client.sendall(line)
  86. self.__progress(send_size, file_size, '上传中')
  87.  
  88. elif status_code == '':
  89. print('[%s] Error!' % status_code)
  90.  
  91. else:
  92. print('[401] Error!')
  93.  
  94. def dir(self, command):
  95. self.__universal_method_data(command)
  96.  
  97. def pwd(self, command):
  98. self.__universal_method_data(command)
  99.  
  100. def mkdir(self, command):
  101. self.__universal_method_none(command)
  102.  
  103. def cd(self, command):
  104. self.__universal_method_none(command)
  105.  
  106. def __universal_method_none(self, command):
  107. self.client.sendall(command.encode())
  108. status_code = self.client.recv(1024).decode()
  109. if status_code == '':
  110. self.client.sendall(''.encode())
  111.  
  112. else:
  113. print('[%s] Error!' % status_code)
  114.  
  115. def __universal_method_data(self, command):
  116. self.client.sendall(command.encode())
  117. status_code = self.client.recv(1024).decode()
  118. print(status_code)
  119. if status_code == '':
  120. self.client.sendall(''.encode())
  121. result = self.client.recv(1024).decode()
  122. print(result)
  123. else:
  124. print('[%s] Error!' % status_code)
  125.  
  126. def __progress(self, trans_size, file_size, mode):
  127. bar_length = 100
  128. percent = float(trans_size) / float(file_size)
  129. hashes = '=' * int(percent * bar_length)
  130. spaces = ' ' * int(bar_length - len(hashes))
  131. sys.stdout.write('\r%s:%.2fM/%.2fM %d%% [%s]' \
  132. % (mode, trans_size/1048576, file_size/1048576, percent*100, hashes+spaces))
  133.  
  134. if __name__ == '__main__':
  135. client = Myclient(('localhost', 8000))
  136. client.start()

ftp_client.py

4、ftp服务端启动程序

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import os, json
  4. from conf import settings
  5. from modules import socket_server
  6. def create_db():
  7. user_database = {}
  8. limit_size = settings.LIMIT_SIZE
  9. for k, v in settings.USER_INFO.items():
  10. username = k
  11. password = v
  12. user_home_path = settings.HOME_DIR + r'\%s' % username
  13. user_db_path = settings.DATABASE_DIR + r'\%s.db' % username
  14. user_database['username'] = username
  15. user_database['password'] = password
  16. user_database['limitsize'] = limit_size
  17. user_database['homepath'] = user_home_path
  18. if not os.path.isfile(user_db_path):
  19. with open(user_db_path, 'w') as file:
  20. file.write(json.dumps(user_database))
  21.  
  22. def create_home():
  23. for username in settings.USER_INFO:
  24. user_home_path = settings.HOME_DIR + r'\%s' % username
  25. if not os.path.isdir(user_home_path):
  26. os.popen('mkdir %s' % user_home_path)
  27.  
  28. if __name__ == '__main__':
  29. create_db()
  30. create_home()
  31. server = socket_server.socketserver.ThreadingTCPServer(settings.IP_PORT, socket_server.Myserver)
  32. server.serve_forever()

ftp_server.py

5、conf配置文件

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import os, sys
  4.  
  5. # 程序主目录
  6. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  7. sys.path.insert(0, BASE_DIR)
  8.  
  9. # 数据库目录
  10. DATABASE_DIR = os.path.join(BASE_DIR, 'database')
  11.  
  12. # 用户家目录
  13. HOME_DIR = os.path.join(BASE_DIR, 'home')
  14.  
  15. # 用户配额
  16. LIMIT_SIZE = 10240000
  17.  
  18. # 用户信息
  19. USER_INFO = {'hkey': '', 'xiaofei': 'abc'}
  20.  
  21. # ip and port
  22. IP_PORT = ('localhost', 8000)

settings.py

6、database 用户数据库(初始化生成,生成程序 - conf/settings.py)

  1. {"homepath": "E:\\py_code\\FTP\\ftp_server\\home\\hkey", "username": "hkey", "limitsize": 10240000, "password": ""}

hkey.db

  1. {"homepath": "E:\\py_code\\FTP\\ftp_server\\home\\xiaofei", "username": "xiaofei", "limitsize": 10240000, "password": "abc"}

xiaofei.db

7、modules 核心功能模块

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import json, os
  4. from conf import settings
  5. class User_operation(object):
  6. def authentication(self, login_info):
  7. username, password = login_info.split(':')
  8. DB_FILE = settings.DATABASE_DIR + r'\%s' % username
  9. if os.path.isfile(DB_FILE):
  10. user_database = self.cat_database(DB_FILE)
  11. if username == user_database['username'] and \
  12. password == user_database['password']:
  13. return user_database
  14.  
  15. def cat_database(self, DB_FILE):
  16. with open(DB_FILE, 'r') as file:
  17. data = json.loads(file.read())
  18. return data

auth_user.py

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import socketserver
  4. import os, json
  5. from os.path import getsize, join
  6. from modules import auth_user
  7. from conf import settings
  8. class Myserver(socketserver.BaseRequestHandler):
  9. def handle(self):
  10. try:
  11. while True:
  12. login_info = self.request.recv(1024).decode()
  13. print(login_info)
  14. result = self.authenticat(login_info)
  15. status_code = result[0]
  16. self.request.sendall(status_code.encode())
  17. if status_code == '':
  18. continue
  19. self.user_db = result[1]
  20. self.user_current_path = self.user_db['homepath']
  21. self.user_home_path = self.user_db['homepath']
  22. while True:
  23. command = self.request.recv(1024).decode()
  24. command_str = command.split()[0]
  25. if hasattr(self, command_str):
  26. func = getattr(self, command_str)
  27. func(command)
  28. else:
  29. self.request.sendall(''.encode())
  30.  
  31. except ConnectionResetError as e:
  32. self.request.close()
  33. print('Error:', e)
  34.  
  35. def authenticat(self, login_info):
  36. auth = auth_user.User_operation()
  37. result = auth.authentication(login_info)
  38. if result:
  39. return '', result
  40. else:
  41. return '', result
  42.  
  43. def get(self, command):
  44. print('func: get()')
  45. if len(command.split()) > 1:
  46. filename = command.split()[1]
  47. user_file_path = self.user_current_path + r'\%s' % filename
  48. if os.path.isfile(user_file_path):
  49. print(user_file_path)
  50. self.request.sendall(''.encode())
  51. file_size = os.stat(user_file_path).st_size
  52. status_code = self.request.recv(1024).decode()
  53. if status_code == '':
  54. self.request.sendall(''.encode())
  55. has_send_data = int(self.request.recv(1024).decode())
  56. if has_send_data < file_size:
  57. self.request.sendall(''.encode())
  58. response = self.request.recv(1024).decode()
  59. else:
  60. self.request.sendall(''.encode())
  61. return
  62.  
  63. else:
  64. has_send_data = 0
  65.  
  66. self.request.sendall(str(file_size).encode())
  67. response = self.request.recv(1024)
  68. with open(user_file_path, 'rb') as file:
  69. file.seek(has_send_data)
  70. self.request.sendall(file.read())
  71.  
  72. else:
  73. self.request.sendall(''.encode())
  74. else:
  75. self.request.sendall(''.encode())
  76.  
  77. def put(self, command):
  78. filename = command.split()[1]
  79. file_path = self.user_current_path + r'\%s' % filename
  80. self.request.sendall(''.encode())
  81. file_size = self.request.recv(1024).decode()
  82. file_size = int(file_size)
  83. limit_size = self.user_db['limitsize']
  84. used_size = self.__getdirsize(self.user_home_path)
  85. if limit_size >= file_size + used_size:
  86. self.request.sendall(''.encode())
  87. revice_size = 0
  88. with open(file_path, 'wb') as file:
  89. while revice_size != file_size:
  90. data = self.request.recv(1024)
  91. revice_size += len(data)
  92. file.write(data)
  93.  
  94. else:
  95. self.request.sendall(''.encode())
  96.  
  97. def dir(self, command):
  98. if len(command.split()) == 1:
  99. self.request.sendall(''.encode())
  100. response = self.request.recv(1024)
  101. send_data = os.popen('dir %s' % self.user_current_path)
  102. self.request.sendall(send_data.read().encode())
  103. else:
  104. self.request.sendall(''.encode())
  105.  
  106. def pwd(self, command):
  107. if len(command.split()) == 1:
  108. self.request.sendall(''.encode())
  109. response = self.request.recv(1024)
  110. self.request.sendall(self.user_current_path.encode())
  111. else:
  112. self.request.sendall(''.encode())
  113.  
  114. def mkdir(self, command):
  115. if len(command.split()) > 1:
  116. dir_name = command.split()[1]
  117. dir_path = self.user_current_path + r'\%s' % dir_name
  118. if not os.path.isdir(dir_path):
  119. self.request.sendall(''.encode())
  120. response = self.request.recv(1024)
  121. os.popen('mkdir %s' % dir_path)
  122. else:
  123. self.request.sendall(''.encode())
  124. else:
  125. self.request.sendall(''.encode())
  126.  
  127. def cd(self, command):
  128. print(command)
  129. if len(command.split()) > 1:
  130. dir_name = command.split()[1]
  131. dir_path = self.user_current_path + r'\%s' % dir_name
  132. user_home_path = settings.HOME_DIR + r'\%s' % self.user_db['username']
  133. if dir_name == '..' and len(self.user_current_path) > len(user_home_path):
  134. self.request.sendall(''.encode())
  135. response = self.request.recv(1024)
  136. self.user_current_path = os.path.dirname(self.user_current_path)
  137. elif os.path.isdir(dir_path):
  138. self.request.sendall(''.encode())
  139. response = self.request.recv(1024)
  140. if dir_name != '.' and dir_name != '..':
  141. self.user_current_path += r'\%s' % dir_name
  142. else:
  143. self.request.sendall(''.encode())
  144. else:
  145. self.request.sendall(''.encode())
  146.  
  147. def __getdirsize(self, home_path):
  148. size = 0
  149. for root, dirs, files in os.walk(home_path):
  150. size += sum([getsize(join(root, name)) for name in files])
  151. return size

socket_server.py

程序运行效果图:

get 续传功能

[ python ] 项目一:FTP程序的更多相关文章

  1. 用python开发简单ftp程序

    根据alex老师视频开发的简单ftp程序,只能实现简单的get功能 ftp客户端程序: #!/usr/bin/env python #_*_ coding:utf-8 _*_ import socke ...

  2. python简单的ftp程序

    服务器端 '''1.读取文件名2.检测文件是否存在3.打开文件4.检测文件大小5.发送文件大小给客户端6.等客户端确认7.开始边读边发数据8.发送md5'''import socket,os,time ...

  3. Python开发【项目】:FTP程序

    作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...

  4. Python开发程序:FTP程序

    作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...

  5. python实现FTP程序

    python实现FTP程序 程序源码 上传功能 查看文件 cd功能 创建目录 程序源码 目录结构 服务端 主程序 import optparse import socketserver import ...

  6. (转)Python开发程序:支持多用户在线的FTP程序

    原文链接:http://www.itnose.net/detail/6642756.html 作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ...

  7. Jenkins构建Python项目提示:'python' 不是内部或外部命令,也不是可运行的程序

    问题描述: jenkin集成python项目,立即构建后,发现未执行成功,查看Console Output 提示:'Python' 不是内部或外部命令,也不是可运行的程序,如下图: 1.在 Windo ...

  8. 【Jenkins】jenkins构建python项目提示:'python' 不是内部或外部命令,也不是可运行的程序或批处理文件

    一.问题:jenkins构建python项目提示:'python' 不是内部或外部命令,也不是可运行的程序或批处理文件 二.原因:要在jenkins配置本地环境变量 三.解决方案:添加python.e ...

  9. 老男孩python作业7-开发一个支持多用户在线的FTP程序

    作业6:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...

随机推荐

  1. [bzoj] 3669 NOI2014 魔法森林 || LCT

    原题 copy一篇题解:原链接 将边按照a排序,然后从小到大枚举,加入图中. 在图中用lct维护一棵两点之间b最大值尽量小的生成树. 当加入一条边(u, v)时: 如果(u, v)不连通,则直接加入这 ...

  2. HDU4812 D tree 【点分治 + 乘法逆元】

    D树 时间限制:10000/5000 MS(Java / Others)内存限制:102400/102400 K(Java / Others) 总共提交5400个已接受的提交1144 问题描述 南京理 ...

  3. App.config的典型应用

    ----.net中XML的典型应用 第一种修改方式: 添加xml节点figguration内容, 微软提供了一种方案来读取connectionStrings里的内容 这样就可以拿到连接sql serv ...

  4. bzoj1878: [SDOI2009]HH的项链(主席树/离线+BIT)

     这题有离线和在线两种做法.  离线:将查询区间按左端点排序,预处理出所有数下一次的出现位置,一开始将所有第一次出现的数a[i]++,之后当扫到这个数的时候a[next[i]]++,相当于差分,给之后 ...

  5. YBT 2.4 AC自动机

    其实这个专题NOIP几乎不考 AC自动机,就是能让题自动AC的东西,是不是十分神奇 对的,就是这么神奇 AC自动机是解决多模式串与文本串匹配的问题 是KMP+Trie树的结合,也是一个毒瘤算法 Key ...

  6. JS深度合并对象

    /** * 如果target(也就是FirstOBJ[key])存在, * 且是对象的话再去调用deepObjectMerge, * 否则就是FirstOBJ[key]里面没这个对象,需要与Secon ...

  7. LVM分区

    使用LVM对磁盘进行初始化 pvcreate /dev/vdd 创建卷组 vgcreate vg /dev/vdd 备注:vg是卷组的名称,可改变. 查看卷组的详细信息 vgdisplay 下图是我执 ...

  8. Centos版本6的使用教程

    Centos版本6的使用教程 1.打开VMware workstation 12 PRO 创建新的虚拟机. 2.使用典型类型配置. 3.选择稍后安装操作系统,可以在后面进行安装. 4.选择安装的系统 ...

  9. SpringMVC源码解析-DispatcherServlet启动流程和初始化

    在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象. 先从Dis ...

  10. django-jet 中文文档

    关于 JET是新式的Django管理界面并且增强了功能.     内容 文档 开始 安装django-jet 安装仪表盘 配置 配置文件 自动补全 紧凑内联 过滤器 仪表盘 自定义仪表盘 仪表盘模块 ...