服务器利用 socketserver 模块 构造, 实现了 多进程.

客户端仍然利用的是底层的 socket模块. 只不过进行了更深度的 解耦, 新加或者删除 某些功能 更方便

在上一个版本的基础上,增加了 新建文件夹的功能, 并且将vip用户的名字加上了颜色, 变成了黄金 vip.

服务器端设置了两个文件, 1, info( 存储用户密码); 2, vipinfo (存储所有的vip用户的名字)

还需要再补充一个log文件夹,里面用来保存所有客户的访问记录. ps: 此功能还没添加.

下面是代码:

服务器端:

 import socketserver
import struct
import pickle
import os class Myserver(socketserver.BaseRequestHandler):
def __init__(self, request, client_address, server):
self.dic_cho = {
'login': self.login, # 登录
'register': self.register, # 注册
'new_file': self.new_file, # 创建新的文件夹
'down_dir': self.down_dir, # 进入下一层
'up_dir': self.up_dir, # 进入上一层
'upload': self.upload, # 上传
'download': self.download, # 下载
'vip': self.vip, # 升级vip
'end': self.end, # 结束
'size': 102400
}
self.flag = False
self.flag_end = True
super().__init__(request, client_address, server) def my_reve(self): # 因为每次接收后的内容都会转成字典, 所以重写了接收的函数
return pickle.loads(self.request.recv(struct.unpack('i', self.request.recv(4))[0])) def my_send(self, dic): # 重写了 发送方法.
dic_pic = pickle.dumps(dic)
return self.request.send(struct.pack('i', len(dic_pic)) + dic_pic) def isvip(self, server_dict, client_dic):
"""此函数是 login函数的附属函数, 只是用来判断该用户是否为Vip :param server_dict: 服务器需要发送的字典
:param client_dic: 服务器接收的客户端发来的字典
:return: None
"""
with open('vipinfo', encoding='utf-8') as f:
for name in f:
if client_dic['username'] == name.strip():
self.flag = True
server_dict['return'] = '登录成功, 欢迎尊敬的VIP用户:\033[1;33;m%s\033[0m 访问ftp' % client_dic['username']
self.dic_cho['size'] = 10240000
server_dict['size'] = '容量:(单位:字节)%s/10240000' % os.path.getsize(self.dir_path)
return def login(self, client_dic, server_dict):
self.dir_path = os.path.join(os.path.dirname(__file__), client_dic['username'])
# 第一步 判断用户名+密码 是否正确
with open('info', encoding='utf-8') as f:
for line in f:
if client_dic['username'] + '\t' + client_dic['password'] == line.strip():
server_dict['return'] = '登录成功, 欢迎%s 用户访问ftp' % client_dic['username']
server_dict['size'] = f'容量:(单位:字节){os.path.getsize(self.dir_path)}/102400'
server_dict['dir_list'] = os.listdir(self.dir_path)
# 第二步 判断此人是不是会员, 有没有vip文件中
self.isvip(server_dict, client_dic)
# 第三步, 将字典发送给 客户端并且 结束函数
self.my_send(server_dict)
return
server_dict['return'] = '错误:输入错误'
self.my_send(server_dict) def register(self, client_dic, server_dict):
self.dir_path = os.path.join(os.path.dirname(__file__), client_dic['username'])
with open('info', encoding='utf-8') as f:
for line in f:
username, password = line.strip().split('\t')
if client_dic['username'] == username:
server_dict['return'] = '错误:用户名已存在'
self.my_send(server_dict)
return
with open('info', 'a+', encoding='utf-8') as f:
f.write(client_dic['username'] + '\t' + client_dic['password'] + '\n')
self.flag = True
server_dict['return'] = '注册成功,自动登录中'
os.mkdir(client_dic['username'])
server_dict['dir_list'] = os.listdir(self.dir_path)
server_dict['size'] = f'容量:(单位:字节){os.path.getsize(self.dir_path)}/102400'
self.my_send(server_dict) def new_file(self, client_dic, server_dict):
"""
此函数和下面的六个函数 被执行的前提是客户已经登录成功了,
且已经在客户端显示出来了文件列表, 若没有登录, 该用户访问不到此方法 此函数的功能是 在当前工作列表中新建文件夹
:param client_dic:
:param server_dict:
:return:
"""
new_name = client_dic['new_dir_name']
os.mkdir(os.path.join(self.dir_path, new_name))
server_dict['return'] = '%s 文件夹新建成功' % new_name
self.my_send(server_dict) def down_dir(self, client_dic, server_dict):
down_dir_name = client_dic['down_dir_name']
self.dir_path = os.path.join(self.dir_path, down_dir_name)
server_dict['dir_list'] = os.listdir(self.dir_path)
self.my_send(server_dict) def up_dir(self, client_dic, server_dict):
dir_path_if = os.path.dirname(self.dir_path)
if dir_path_if == os.path.dirname(__file__):
server_dict['return'] = '已经是最上层目录了'
else:
self.dir_path = dir_path_if
server_dict['dir_list'] = os.listdir(self.dir_path)
self.my_send(server_dict) def upload(self, client_dic, server_dict):
filesize = client_dic['upload_file_size']
size = os.path.getsize(self.dir_path)
if filesize+size >= self.dic_cho['size']:
server_dict['return'] = '内存不足'
self.my_send(server_dict)
return
filename = os.path.join(self.dir_path, client_dic['upload_file_name'])
with open(filename, 'wb') as f:
while filesize:
if filesize < 1024:
content = self.request.recv(filesize)
else:
content = self.request.recv(1024)
f.write(content)
filesize -= len(content)
server_dict['return'] = '上传成功'
server_dict['dir_list'] = os.listdir(self.dir_path)
self.my_send(server_dict) def download(self, client_dic, server_dict):
filename = os.path.join(self.dir_path, client_dic['download_file_name'])
filesize = os.path.getsize(filename)
server_dict['file_size'] = filesize
self.my_send(server_dict)
with open(filename, 'rb') as f:
while filesize:
if filesize > 1024:
content = f.read(filesize)
else:
content = f.read(1024)
self.request.send(content)
filesize -= len(content)
ok = self.request.recv(2)
print(ok)
self.request.send(b'download ok') if ok == b'ok' else self.request.send(b'download no') def vip(self, client_dic, server_dict):
with open('vipinfo', 'r+', encoding='utf-8') as f:
for line in f:
if client_dic['username'] == line.strip():
server_dict['return'] = '您已经是尊敬的Vip用户了'
self.my_send(server_dict)
return
f.seek(0, 2)
f.write(client_dic['username'] + '\n')
self.isvip(server_dict, client_dic)
self.my_send(server_dict) def end(self, client_dic, server_dict):
self.flag_end = False
server_dict['return'] = '程序结束'
self.my_send(server_dict) def handle(self):
server_dict = {}
flag = self.flag_end
while flag:
try:
client_dic = self.my_reve()
self.dic_cho[client_dic['opt']](client_dic, server_dict)
except Exception:pass server = socketserver.TCPServer(('127.0.0.1', 9090), Myserver)
server.serve_forever()

客户端:

 import os
import socket
import struct
import pickle
import hashlib class Myclient(socket.socket):
def __init__(self):
super().__init__()
self.dic_cho = {
'login': self.login, # 登录
'regis': self.register, # 注册
'new_file': self.new_file, # 创建新的文件夹
'down_dir': self.down_dir, # 进入下一层
'up_dir': self.up_dir, # 进入上一层
'upload': self.upload, # 上传
'download': self.download, # 下载
'vip': self.vip, # 升级vip
'end': self.end, # 结束
}
self.flag = True def my_reve(self):
return pickle.loads(self.sk.recv(struct.unpack('i', self.sk.recv(4))[0])) def my_send(self, dic):
dic_pic = pickle.dumps(dic)
return self.sk.send(struct.pack('i', len(dic_pic)) + dic_pic) def login(self):pass def register(self):pass def my_md5(self, user, pwd):
md5_obj = hashlib.md5(user.encode('utf-8'))
md5_obj.update(pwd.encode('utf-8'))
return md5_obj.hexdigest() def new_file(self):
new_file_name = input('>>>请输入新建文件夹的名字:').strip()
self.client_dict['new_dir_name'] = new_file_name
self.my_send(self.client_dict)
server_dict = self.my_reve()
print(server_dict['dir_list']) def down_dir(self):
down_dir_name = input('>>>请输入下一级文件夹的名字:').strip()
self.client_dict['down_dir_name'] = down_dir_name
self.my_send(self.client_dict)
server_dict = self.my_reve()
print(server_dict['dir_list']) def up_dir(self):
self.my_send(self.client_dict)
server_dict = self.my_reve()
print(server_dict['dir_list']) def upload(self):
upload_file_path = input('>>>请输入上传文件绝对路径:').strip()
self.client_dict['upload_file_name'] = os.path.basename(upload_file_path)
self.client_dict['upload_file_size'] = os.path.getsize(upload_file_path)
filesize = self.client_dict['upload_file_size']
self.my_send(self.client_dict)
with open(upload_file_path, 'rb') as f:
while filesize:
if filesize > 1024:
content = f.read(filesize)
else:
content = f.read(1024)
self.sk.send(content)
filesize -= len(content)
server_dict = self.my_reve()
print(server_dict['return'])
print(server_dict['dir_list']) def download(self):
download_file_name = input('>>>请输入您要下载的文件的名字:').strip()
download_file_path = input('>>>请输入要下载到本地的绝对路径以及对该文件命名:').strip()
self.client_dict['download_file_name'] = download_file_name
self.my_send(self.client_dict)
server_dict = self.my_reve()
filesize = server_dict['file_size']
with open(download_file_path, 'wb') as f:
while filesize:
if filesize < 1024:
content = self.sk.recv(filesize)
else:
content = self.sk.recv(1024)
f.write(content)
filesize -= len(content)
self.sk.send(b'ok')
ok = self.sk.recv(11)
if ok == b'download ok':
print('下载成功')
else:
print('下载失败')
print(server_dict['dir_list']) def vip(self):
self.my_send(self.client_dict)
server_dict = self.my_reve()
print(server_dict['return'])
print(server_dict['size'])
print(server_dict['dir_list']) def end(self):
self.my_send(self.client_dict)
self.flag = False
server_dict = self.my_reve()
print(server_dict['return']) def main(self):
main_dict = {
'': self.new_file,
'': self.down_dir,
'': self.up_dir,
'': self.upload,
'': self.download,
'': self.vip,
'': self.end,
}
while 1:
print('1, 在当前目录新建文件夹\n'
'2, 进入下级目录\n'
'3, 返回上级目录\n'
'4, 上传文件\n'
'5, 下载文件\n'
'6, 升级Vip\n'
'7, 退出')
cho_main = input('>>>请输入功能选项ID:').strip()
try:
self.client_dict['opt'] = main_dict[cho_main].__name__
main_dict[cho_main]()
if cho_main == '':
break
except Exception:
print('选项输入不规范') def my_input(self, call_dict):
print('欢迎来到FTP\n1, 登录\n2, 注册')
cho = input('>>>请输入选项ID:').strip()
if cho != '' and cho != '':
return 3
username = input('>>>Username:').strip()
password = input('>>>Password:').strip()
self.client_dict['opt'] = call_dict[cho].__name__
self.client_dict['username'] = username
self.client_dict['password'] = self.my_md5(username, password)
self.my_send(self.client_dict) def main_main(self):
call_dict = {'': self.login, '': self.register}
self.client_dict = {}
flag = self.flag
while flag:
ret = self.my_input(call_dict)
if ret == 3:
print('输入错误')
continue
server_dict = self.my_reve()
print(server_dict['return'])
if server_dict['return'][0] != '错':
print(server_dict['size'])
print(server_dict['dir_list'])
self.main()
flag = self.flag def __call__(self, *args, **kwargs):
self.sk = socket.socket()
self.sk.connect(('127.0.0.1', 9090))
self.main_main()
self.sk.close() if __name__ == '__main__':
client = Myclient()
client() # 这个是 发送的字典的内容, 每次操作, 所对应的键值对 中的值都会发生改变.
# client_dict = {'opt': None, # 选项
# 'username': None, # 用户名
# 'password': None, # 密码
# 'new_dir_name': None, # 新建文件夹的名字
# 'down_dir_name': None, # 打开下一层文件夹的名字
# 'upload_file_name': None, # 上传到ftp里面的文件的名字
# 'upload_file_size': None, # 上传的文件的大小
# 'download_file_name': None, # 下载的文件名字
# }

项目: 更新(二) python 实现大概FTP的功能的更多相关文章

  1. 用 Python 自动监测 GitHub 项目更新

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: GitPython PS:如有需要Python学习资料的小伙伴可以加 ...

  2. 【Quick 3.3】资源脚本加密及热更新(二)资源加密

    [Quick 3.3]资源脚本加密及热更新(二)资源加密 注:本文基于Quick-cocos2dx-3.3版本编写 一.介绍 在前一篇文章中介绍了代码加密,加密方式是XXTEA.对于资源文件来说,同样 ...

  3. 风变编程笔记(二)-Python爬虫精进

    第0关  认识爬虫 1. 浏览器的工作原理首先,我们在浏览器输入网址(也可以叫URL),然后浏览器向服务器传达了我们想访问某个网页的需求,这个过程就叫做[请求]紧接着,服务器把你想要的网站数据发送给浏 ...

  4. 在大型项目上,Python 是个烂语言吗

    Robert Love, Google Software Engineer and Manager on Web Search. Upvoted by Kah Seng Tay, I was the ...

  5. 【开源】SpringBoot&Netty实现仿微信网页版项目更新

    阅读本文约“2.3分钟” 项目更新啦!V1.3.0 还记得那个聊天室的小项目吗? SpringBoot 加 Netty 实现聊天室 没错,这次已经完整进行了版本的替换,酥酥聊天室! 基于原项目的改动, ...

  6. web自动化 基于python+Selenium+PHP+Ftp实现的轻量级web自动化测试框架

    基于python+Selenium+PHP+Ftp实现的轻量级web自动化测试框架   by:授客 QQ:1033553122     博客:http://blog.sina.com.cn/ishou ...

  7. 十二. Python基础(12)--生成器

    十二. Python基础(12)--生成器 1 ● 可迭代对象(iterable) An object capable of returning its members one at a time. ...

  8. 二. Python基础(2)--语法

    二. Python基础(2)--语法 1.实现一个简单的登录系统 '''# 形式1 n = 1 while n < 4:     name = input("请输入姓名\n" ...

  9. H2O中的随机森林算法介绍及其项目实战(python实现)

    H2O中的随机森林算法介绍及其项目实战(python实现) 包的引入:from h2o.estimators.random_forest import H2ORandomForestEstimator ...

随机推荐

  1. HBase框架基础(三)

    * HBase框架基础(三) 本节我们继续讨论HBase的一些开发常识,以及HBase与其他框架协调使用的方式.在开始之前,为了框架之间更好的适配,以及复习之前HBase的配置操作,请使用cdh版本的 ...

  2. append生成新变量的时候,没有如预期(It's a feature,not a bug?)

    这是我在写一个项目中,遇到的一个golang的feature,如代码所示,我在for循环里,每次用append生成一个新的数组,(当然我以前一直以为可以这样,直到我在stackoverflow上发现不 ...

  3. SpringMVC学习一:SpringMVC的配置

    SpringMVC的配置主要分为两部分: 1.xml文件配置 2.注解的配置 SpringMVC配置的步骤如下: 1.在将SpringMVC的jar包导入到web项目中后,先配置web.xml 文件. ...

  4. JQ加载进度条动画

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. CRC校验的C语言实现

    文章转自 循环冗余校验(CRC)算法入门引导 - Ivan 的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/liyuanbhu/article/details/7 ...

  6. 【Codeforces Round #422 (Div. 2) B】Crossword solving

    [题目链接]:http://codeforces.com/contest/822/problem/B [题意] 让你用s去匹配t,问你最少需要修改s中的多少个字符; 才能在t中匹配到s; [题解] O ...

  7. 洛谷——P3368 【模板】树状数组 2

    https://www.luogu.org/problem/show?pid=3368 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入 ...

  8. Eclipse快捷键 10个最实用的快捷键

    Eclipse中10个最实用的快捷键组合  一个Eclipse骨灰级开发人员总结了他觉得最实用但又不太为人所知的快捷键组合.通过这些组合能够更加easy的浏览源代码.使得总体的开发效率和质量得到提升. ...

  9. Servlet深入学习,规范,理解和实现(中)——深入理解Tomcat(一)

    心得:在写这篇博客之前.我大致阅读一些关于Tomcat的书籍和博客等资料.有些资料由于时间的关系,解说的Tomcat版本号太老.有些资料能够非常好的说明Tomcat整理结构和设计思想可是非常多重要的问 ...

  10. 26.angularJS $routeProvider

    转自:https://www.cnblogs.com/best/tag/Angular/ O'Reilly书上的伪代码 var someModule = angular.module('someMod ...