需求:

  1. 实现文件上传及下载功能
  2. 支持多连接并发传文件
  3. 使用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的更多相关文章

  1. python IO多路复用版FTP

    需求: 实现文件上传及下载功能 支持多连接并发传文件 使用select or selectors

  2. gevent协程、select IO多路复用、socketserver模块 改造多用户FTP程序例子

    原多线程版FTP程序:http://www.cnblogs.com/linzetong/p/8290378.html 只需要在原来的代码基础上稍作修改: 一.gevent协程版本 1. 导入geven ...

  3. 非阻塞套接字与IO多路复用(转,python实现版)

    非阻塞:指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回.epoll工作在非阻塞模式时,才会发挥作用. 我们了解了socket之后已经知道,普通套接字实现的服务端的缺陷:一次只能服务一个 ...

  4. IO多路复用概念性

    sellect.poll.epoll三者的区别 先来了解一下什么是进程切换 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行,这种行为为进程的切换,任务切换 ...

  5. IO多路复用的几种实现机制的分析

    http://blog.csdn.net/zhang_shuai_2011/article/details/7675797 select,poll,epoll都是IO多路复用的机制.所谓I/O多路复用 ...

  6. 协程 IO多路复用

    -----------------------------------------------------------------试试并非受罪,问问并不吃亏.善于发问的人,知识丰富. # # ---- ...

  7. 7.24 IO多路复用和协程代码笔记

    1. 复习 # !/usr/bin/env python # !--*--coding:utf-8 --*-- # !@Time :2018/7/23 11:49 # !@Author TrueNew ...

  8. 协程IO多路复用

    协程:单线程下实现并发并发:伪并行,遇到IO就切换,单核下多个任务之间切换执行,给你的效果就是貌似你的几个程序在同时执行.提高效率任务切换 + 保存状态并行:多核cpu,真正的同时执行串行:一个任务执 ...

  9. Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

    Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...

随机推荐

  1. 莫名奇妙虚拟机 ip addr 不显示 ip 地址,连不上网络

    CentOS7 Failed to start LSB: Bring up/down networking. 说是mac地址不对.其实,本人并没有配置mac,按理说用的默认的.之前一直是可以正常工作的 ...

  2. 三月pat(转)

    转自https://blog.csdn.net/weixin_40688413/article/details/88082779 担心别人删除了就找不到了.因为九月要考. 7-1 Sexy Prime ...

  3. 2018-2019-2 20165215《网络攻防技术》Exp6 信息搜集与漏洞扫描

    目录 实验目的 实验内容 基础知识 实验步骤 (一)各种搜索技巧的应用 Google Hacking 搜索网址目录结构 搜索特定类型的文件 路由侦查 (二)DNS IP注册信息的查询 whois域名注 ...

  4. 实验1 C语言开发环境使用和数据类型,运算符,表达式

    part :验证性内容 .输出学号. #include<stdio.h> int main(void){ printf("); ; } .输入两个整数,求它们的乘积. #incl ...

  5. C# 多笔数据导入DB

    6万笔数据瞬间导入进DB 命名空间 using NPOI.HSSF.UserModel; using NPOI.XSSF.UserModel; //Filename为文件路径 public JsonR ...

  6. zigbee端口的理解

    在一个终端上,可以有多个端点endpoint,这个概念是很重要的. 一个节点可以有多个端点,0号endpoint是Zigbee device object(ZDO)用的一个端点,255号是用作广播.我 ...

  7. 接触node第一步

    趁着工作不忙,今天来系统记录一下安装node环境: 1.node下载地址为:https://nodejs.org/en/,检查是否安装成功:如果输出版本号,说明我们安装node环境成功:node -v ...

  8. xlrd & xlwd

    一.安装xlrd http://pypi.python.org/pypi/xlrd 二.使用介绍 1.导入模块 import xlrd 2.打开Excel文件读取数据 data = xlrd.open ...

  9. rabbitmq 3.7.8基于centos7部署文档

    rabbitmq 3.7.8部署文档 安装erlang 安装依赖环境 yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel ope ...

  10. 2019-4-21 - plan

    设计模式 idea中demo 在test1中使用单例测试ok