IO多路复用版FTP
需求:
- 实现文件上传及下载功能
- 支持多连接并发传文件
- 使用select or selectors
流程图


import socket
import pickle
import sys
import time
import os A = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class Ftp_client(object):
def __init__(self):
self.client = socket.socket()
def connet(self, ip, port):
'''
链接服务器
:param ip:
:param port:
:return:
'''
self.client.connect((ip, port))
name = self.main()
self.ftp_main(name)
def login(self):
'''
登录
:return:
'''
name = input('请输入姓名').lower().strip()
password = input('请输入密码')
dict = {
'attr': 'login',
'name': name,
'password': password,
}
self.client.sendall(pickle.dumps(dict))
data = self.client.recv(1024)
print(data.decode())
if data.decode()=='输入有误':
return False
else:
return name def register(self):
'''
注册
:return:
'''
name = input('请输入姓名').lower().strip()
pd = input('请输入密码')
dict = {'attr': 'register', 'name': name, 'password': pd}
self.client.sendall(pickle.dumps(dict))
data = self.client.recv(1024)
print(data.decode())
if data.decode() == '用户名已存在,请重新输入':
return False
else:
return name def main(self):
while True:
a = input('请输入 1. 用户登录 2. 用户注册 3.退出')
if a == '':
res = self.login()
elif a == '':
res = self.register()
elif a == '':
exit()
else:
print('输入有误')
continue
if res is False:
continue
else:
return res def download(self, name):
'''
下载
:return:
'''
filename = input('请输入下载文件名')
dic = {'attr': 'download', 'filename': filename, 'name': name}
self.client.sendall(pickle.dumps(dic))
size = self.client.recv(1024).decode()
if size == '该文件不存在':
print ('该文件不存在')
return False
else:
size = int(size)
try:
f = open(os.path.join(A, 'client','db', 'file', filename), 'xb') #文件不存在新建
except Exception:
f = open(os.path.join(A, 'client','db', 'file', filename), 'wb')#文件存在打开重新下载
if size == 0:
f.close()
print('接收完成')
else:
r_size = 0
while r_size < size:
file = self.client.recv(1024)
f.write(file)
r_size += len(file)
view_bar(r_size, size)
time.sleep(0.1)
else:
print('接收完成')
f.close() def upload(self, name):
filename = input('请输入上传的文件名')
if os.path.exists(os.path.join(A, 'client', 'db', 'file',filename)) and filename !='.':
size = os.path.getsize(os.path.join(A, 'client', 'db', 'file', filename)) #文件size
f = open(os.path.join(A, 'client', 'db', 'file', filename), 'rb')
else:
print ('此文件不存在')
return False
if size == 0:
dic = {'attr': 'upload', 'filename': filename, 'size': size, 'name': name}
self.client.sendall(pickle.dumps(dic))
else:
for line in f:
dic = {'attr': 'upload', 'filename': filename, 'size': size, 'name': name, 'text': line}
self.client.sendall(pickle.dumps(dic))
num = f.tell() #查看文件上传位置
view_bar(num, size)
time.sleep(0.1)
f.close()
print ('接收完成')
return False def ftp_main(self, name):
while True:
a = input('请输入相应的指令, download: 下载; upload: 上传; exit:退出').strip()
if hasattr(self, a):
func = getattr(self, a)
func(name)
elif a == 'exit':
exit()
else:
print('输入有误') def view_bar(num, total):
'''进度条'''
rate = float(num) / float(total)
rate_num = int(rate * 100)
r = '\r%d%%' % (rate_num, ) #\r 回到到开头
sys.stdout.write(r)
sys.stdout.flush() #删除记录 ftp = Ftp_client()
ftp.connet('localhost', 9999)
client
import selectors
import socket
import pickle
import os
A = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sel = selectors.DefaultSelector() def accept(sock,mask):
conn, addr = sock.accept()
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read) #调用read函数 def read(conn, mask):
try:
data = conn.recv(1024)
except Exception:
sel.unregister(conn) #出现异常,取消注册的conn
conn.close()
else:
if data:
r_dic = pickle.loads(data)
if r_dic['attr'] == 'login':
login(conn, r_dic)
elif r_dic['attr'] == 'register':
register(conn, r_dic)
elif r_dic['attr'] == 'download':
download(conn, r_dic)
elif r_dic['attr'] == 'upload': upload(r_dic)
else:
print('链接断开')
sel.unregister(conn)
conn.close() def login(conn, dict):
'''
登录
:param conn:
:param dict:
:return:
'''
db_dict = pickle.load(open(os.path.join(A, 'server', 'db', 'register'),'rb'))
if dict['name'] in db_dict:
if dict['password']==db_dict[dict['name']][0]:
conn.sendall('登录成功'.encode())
else:
conn.sendall('输入有误'.encode())
else:
conn.sendall('输入有误'.encode()) def register(conn, r_dic):
'''
注册
:param conn:
:param r_dic:
:return:
'''
if os.path.exists(os.path.join(A, 'db', r_dic['name'])):
conn.sendall('用户名已存在,请重新输入'.encode())
else:
conn.sendall('注册成功'.encode())
os.makedirs(os.path.join(A, 'server', 'db', r_dic['name']))
n_dict = pickle.load(open(os.path.join(A, 'server', 'db', 'register'), 'rb'))
n_dict[r_dic['name']] = r_dic['password']
pickle.dump(n_dict,open(os.path.join(A, 'server','db', 'register'), 'wb')) def upload(dic):
'''
下载
:param dic:
:return:
'''
print(dic)
f_size = int(dic['size']) #上传文件大小
print(f_size)
filename = dic['filename']
name = dic['name']
try:
f = open(os.path.join(A, 'server','db', name, filename), 'xb')
file_size = 0
print(f_size)
except Exception:
f = open(os.path.join(A, 'server','db', name, filename), 'ab')
file_size = os.path.getsize(os.path.join(A, 'server', 'db', name, filename))
if f_size == 0:
f.close()
return False
else:
if file_size< f_size:
f.write(dic['text'])
f.flush()
else:
f.close()
return False def download(conn, dic):
'''
下载
:param conn:
:param dic:
:return:
'''
l_path = os.path.join(A, 'server','db', dic['name'], dic['filename'])
if os.path.exists(l_path) and dic['filename']!= '.': #检查文件是否存在,文件名不能等于.
f = open(l_path, 'rb')
size = os.path.getsize(l_path) #检查文件
conn.sendall(str(size).encode()) #要以字符串格式传数字
for line in f:
conn.sendall(line)
f.close()
else:
conn.sendall('该文件不存在'.encode()) sock = socket.socket()
sock.bind(('localhost', 9999))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
server
IO多路复用版FTP的更多相关文章
- python IO多路复用版FTP
需求: 实现文件上传及下载功能 支持多连接并发传文件 使用select or selectors
- gevent协程、select IO多路复用、socketserver模块 改造多用户FTP程序例子
原多线程版FTP程序:http://www.cnblogs.com/linzetong/p/8290378.html 只需要在原来的代码基础上稍作修改: 一.gevent协程版本 1. 导入geven ...
- 非阻塞套接字与IO多路复用(转,python实现版)
非阻塞:指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回.epoll工作在非阻塞模式时,才会发挥作用. 我们了解了socket之后已经知道,普通套接字实现的服务端的缺陷:一次只能服务一个 ...
- IO多路复用概念性
sellect.poll.epoll三者的区别 先来了解一下什么是进程切换 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行,这种行为为进程的切换,任务切换 ...
- IO多路复用的几种实现机制的分析
http://blog.csdn.net/zhang_shuai_2011/article/details/7675797 select,poll,epoll都是IO多路复用的机制.所谓I/O多路复用 ...
- 协程 IO多路复用
-----------------------------------------------------------------试试并非受罪,问问并不吃亏.善于发问的人,知识丰富. # # ---- ...
- 7.24 IO多路复用和协程代码笔记
1. 复习 # !/usr/bin/env python # !--*--coding:utf-8 --*-- # !@Time :2018/7/23 11:49 # !@Author TrueNew ...
- 协程IO多路复用
协程:单线程下实现并发并发:伪并行,遇到IO就切换,单核下多个任务之间切换执行,给你的效果就是貌似你的几个程序在同时执行.提高效率任务切换 + 保存状态并行:多核cpu,真正的同时执行串行:一个任务执 ...
- Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型
Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...
随机推荐
- bind 小测试
#测试其他功能临时搭建测试 主配置文件: [root@localhost named]# cat /etc/named.conf // // named.conf // // Provided by ...
- Python Iterables Iterators Generators
container 某些对象包含其它对象的引用,这个包含其它对象引用的对象叫容器.例如list可以包含int对象,或者由其它数据类型(或数据结构)的对象组成一个list. 对其他对象的引用是容器值的一 ...
- 【Django视图与网址进阶004】
一.在网页上做加减法 1. 采用 /add/?a=4&b=5 这样GET方法进行 django-admin.py startproject zqxt_views cd zqxt_views p ...
- Client not ready yet.....
提示Client not ready yet.....程序安装上就提示停止了 Logcat无提示 只有run里边提示 Client not ready yet....... 我尝试了 Clean ...
- 【JavaScript】标准日期、中国标准时间、时间戳、毫秒数互转
转载自:https://blog.csdn.net/IT429/article/details/78341847 看到的一篇比较有用的前端js时间转换方法,留个备份 首先要明确这三种格式是什么样子的: ...
- LintCode 846.多关键字排序
LintCode 846.多关键字排序 描述 给定 n 个学生的学号(从 1 到 n 编号)以及他们的考试成绩,表示为(学号,考试成绩),请将这些学生按考试成绩降序排序,若考试成绩相同,则按学号升序排 ...
- 比原链(Bytom)先知节点 Windows接入文档
系统要求 我们建议选择知名的VPS服务商,运行比原链节点对算力没有要求,但是请配置尽可能大的磁盘空间. 节点服务器最小配置: 操作系统: Windows/Linux/Docker CPU: 2核 内存 ...
- js回调函数以及同步与异步
1. 背景介绍javascript的单线程特性由于javascript语言是一门“单线程”的语言,所以,javascript就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任 ...
- # 常用linux 命令和相关问题解决
最近试着自己部署了服务器,在unbantu的环境下 学习了很多新知识 也遇到了很多问题,现在腾出手了,总结一下 常用Linux命令 目录操作 pwd: 查看当前路径 cd: 移动 cd .. : 返回 ...
- SSH无法连接到服务器
SSH服务器会无法连接,有时候并不是密码的问题,可能由于你上次改了密码(就算改成跟上次一样也是一个效果)导致家目录下的known_hosts(/root/.ssh/known_hosts)不一样了并且 ...