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 多路复用的原理 事件选择器与 ...
随机推荐
- antd-design TextArea initialValue 不生效可能原因
<Form.Item label="展会介绍"> {getFieldDecorator('introduce', { initialValue:record.intro ...
- 介绍Kubernetes监控Heapster
什么是Heapster? Heapster是容器集群监控和性能分析工具,天然的支持Kubernetes和CoreOS,Kubernetes有个出名的监控agent—cAdvisor.在每个kubern ...
- Javascript在使用import 与export 区别及使用
一.import与export的用法 1.import的几种用法 import defautName from 'modules.js'; import { export } from 'module ...
- Java8将List转为Map
1.实体 public class Hosting { private int id; private String name; private long websites; public Hosti ...
- Qt文档阅读笔记-QGraphicsItem::paint中QStyleOptionGraphicsItem *option的进一步认识
官方解析 painter : 此参数用于绘图;option : 提供了item的风格,比如item的状态,曝光度以及详细的信息:widget : 想画到哪个widget上,如果要画在缓存区上,这个参数 ...
- PHP7.1 mcrypt_module_open() is deprecated
PHP7.1 mcrypt_module_open() is deprecated 一:函数前添加抑制符 @ mcrypt_module_open....;->@mcrypt_module_op ...
- 读 vue 源码一 (为什么this.message能够访问data里面的message)
12月离职后,打算在年后再找工作了,最近陆陆续续的看了黄轶老师的vue源码解析,趁着还有几天过年时间记录一下. 目标:vue如何实现通过this.key,就能直接访问data,props,method ...
- iOS imageNamed 与 imageWithContentsOfFile 的区别
imageNamed 方法 1)后面的参数是icon的名字,图片可以存在项目中,也可以存在Asset中 2)该方法只适合一些中小型的图片读取,而一些比较大的资源图片并不适合用这个方法 3)这个方法加载 ...
- Android中在不同activity中进行自定义广播的解析
相信有不少人和我一样曾经尝试过在同一个项目中的两个activity进行广播,发现怎么都实现不了.我也是困惑了好久才发现,这么搞本来就是不行的.首先在同一个项目下不同的activity之间广播没有意义, ...
- kali网络配置
touch 1.txt#创建一个文件 配置网卡 auto eth0iface eth0 inet staticaddress 172.16.30.102#要设置的主机IP地址netmask 255.2 ...