SELECT版FTP
- 功能:
1、使用SELECT或SELECTORS模块实现并发简单版FTP
2、允许多用户并发上传下载文件
环境:
python 3.5
特性:
select 实现并发效果
运行:
get 文件名 #从服务器下载文件
put 文件名 #向服务器上传文件
helps #帮助信息
其他命令 #变大写返回给客户端
主要知识点:
os模块的应用
json模块的运用
select模块的运用
socket通信
queue数据交互
粘包
原理:
这个程序通过select实现了并发,主要原理为它通过一个select()系统调用来监视多个文件描述符的数组(在linux中一切事物皆文
件,块设备,socket连接等。),当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位(变成ready),使得进程
可以获得这些文件描述符从而进行后续的读写操作(select会不断监视网络接口的某个目录下有多少文件描述符变成ready状态【在
网络接口中,过来一个连接就会建立一个'文件'】,变成ready状态后,select就可以操作这个文件描述符了)。
通过不同链接的交替,实现并发效果。
主要代码:
- readable, writeable, exeptional = select.select(inputs,outputs,inputs) #如果没有任何fd就绪,那程序就会一直阻塞在这里
- # select中第1个参数表示inputs中发生变化的句柄放入readable。
- # select中第2个参数表示outputs中的值原封不动的传递给writeable。
- # select中第3个参数表示inputs中发生错误的句柄放入exeptional.
- import json
- import select
- import socket
- import queue
- import os
- os.chdir(os.pardir)
- server = socket.socket()
- server_addr = ("localhost",1000)
- server.bind(server_addr)
- server.listen(7)
- inputs = [server,]
- outputs = []
- message_queue ={}
- while True:
- readable,writeable,exeptional = select.select(inputs,outputs,inputs)
- #
- # 存放所有的活动
- for sock in readable:
- if sock is server:
- conn, client_addr = sock.accept()
- inputs.append(conn)
- message_queue[conn] = queue.Queue() #为防阻塞,先把信息存入队列
- else:
- data = sock.recv(1024)
- if data:
- message_queue[sock].put(data)
- if sock not in outputs:
- outputs.append(sock)
- else:
- if sock in outputs:
- outputs.remove(sock)
- inputs.remove(sock)
- del message_queue[sock]
- #
- # 存放连接信息
- #
- for sock in writeable:
- try:
- cmd = message_queue[sock].get_nowait()
- except queue.Empty:
- outputs.remove(sock)
- else:
- print("recv data:", cmd)
- data = json.loads(cmd.decode())
- if data.get('action') is not None:
- #
- # 上传文件
- if data['action'] == 'put':
- # client sends file to server
- file_obj = open('data/'+data['filename'], 'wb')
- received_size = 0
- sock.send(b'')
- while True:
- if received_size == data['size']:
- break
- recv_data = sock.recv(1024)
- file_obj.write(recv_data)
- received_size += len(recv_data)
- if received_size == data['size']:
- print('Successfully received file ', data['filename'])
- file_obj.close()
- #
- # 下载文件
- elif data['action'] == 'get':
- if os.path.isfile(data['filename']):
- data['file_size'] = os.path.getsize(data['filename'])
- data['ERROR'] = ''
- else:
- data['ERROR'] = '' #ERROR标识
- sock.send(json.dumps(data).encode())
- if os.path.isfile(data['filename']):
- if sock.recv(1) == b'': #等待客户端响应,防粘包
- if data['ERROR'] == '':
- file_obj = open(data['filename'], 'rb')
- for line in file_obj:
- sock.send(line)
- #
- # 其他命令
- else:
- data['cmd'] = data['cmd'].upper()
- sock.send(json.dumps(data).encode())
- #
- # 错误链接
- for sock in exeptional:
- if sock in outputs:
- outputs.remove(sock)
- inputs.remove(sock)
- del message_queue[sock]
server端
- import json
- import socket
- import os
- os.chdir(os.pardir)
- server_address = ('localhost', 1000)
- sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- sock.connect(server_address)
- print('''------Welcome!!-----
- (helps:帮助信息)''')
- while True:
- cmd = input(">>>").strip()
- cmd_list = cmd.split()
- #
- #上传文件
- if cmd_list[0] == 'put':
- if len(cmd_list) == 1: #命令不能识别
- print('No filename follows after put cmd!')
- continue
- filename = 'data/'+cmd_list[1] #将所有的文件都归入data文件夹
- if os.path.isfile(filename):
- file_obj = open(filename,'rb')
- base_filename = filename.split('/')[-1]
- data_header = {
- 'action':'put',
- 'filename':base_filename,
- 'size':os.path.getsize(filename)
- }
- sock.send(json.dumps(data_header).encode())
- if sock.recv(1) == b'': #防止粘包
- for line in file_obj:
- sock.send(line)
- file_obj.close()
- print('put all file..')
- else:
- print('File is not valid')
- continue
- #
- # 下载文件
- elif cmd_list[0] == 'get':
- if len(cmd_list) == 1:
- print('No filename follows after get cmd!')
- continue
- filename = 'data/'+ cmd_list[1]
- data_header = {
- 'action':'get',
- 'filename':filename,
- 'ERROR':''
- }
- sock.send(json.dumps(data_header).encode())
- data_header = json.loads(sock.recv(1024).decode())
- if data_header['ERROR'] == '':
- file_obj = open(data_header['filename'], 'wb')
- received_size = 0
- sock.send(b'')
- while True:
- if received_size == data_header['file_size']:
- break
- recv_data = sock.recv(1024)
- file_obj.write(recv_data)
- received_size += len(recv_data)
- print('Successfully received file ', data_header['filename'])
- file_obj.close()
- #
- # 帮助信息
- elif cmd_list[0] == 'helps':
- print('''
- put 文件名 #上传文件
- get 文件名 #下载文件
- 其他命令 #返回大写''')
- #
- # 其他命令
- else:
- data_header = {
- 'action':'else',
- 'cmd':cmd
- }
- sock.send(json.dumps(data_header).encode())
- data_recv = json.loads(sock.recv(1024).decode())
- print(data_recv['cmd'])
client端
SELECT版FTP的更多相关文章
- python作业Select版本FTP(第十周)
SELECT版FTP: 使用SELECT或SELECTORS模块实现并发简单版FTP 允许多用户并发上传下载文件 思路解析: 1. 使用IO多路复用的知识使用SELECTORS封装好的SELECTOR ...
- SELECTORS模块实现并发简单版FTP
环境:windows, python 3.5功能:使用SELECTORS模块实现并发简单版FTP允许多用户并发上传下载文件 结构:ftp_client ---| bin ---| start_clie ...
- jquery双向列表选择器select版
这个是select版的,若想美化某些样式是不支持得,可以用div模拟版的,功能基本实现能用了,需要其他功能自己加上. div模拟版链接:http://www.cnblogs.com/tie123abc ...
- Android版Ftp服务端软件
分享一款开发的Android版Ftp服务端软件,支持Android4.0及以上版本,可以实现局域网无线传输文件到手机,或者把手机上的多媒体文件分享到iPad等设备来扩展这些设备的存储空间,详情请见软件 ...
- java版ftp简易客户端(可以获取文件的名称及文件大小)
java版ftp简易客户端(可以获取文件的名称及文件大小) package com.ccb.ftp; import java.io.IOException; import java.net.Socke ...
- IO多路复用版FTP
需求: 实现文件上传及下载功能 支持多连接并发传文件 使用select or selectors 流程图 import socket import pickle import sys import t ...
- C# socket实践 - 简易版FTP(Server & Client)
写了个简易版的ftp(服务器和客户端),运行效果如下图: click download下载中的UI: 原理:模仿正规ftp方式,分成2个socket连接:文本命令socket.数据信道socket. ...
- Serv-U精简版FTP服务端
Window搭建自己的FTP,Serv-U是很不错的选择... 00.运行视图 注意: 此版本是绿色破解版,个人使用很便捷的.不建议商业使用... download: https://pan.baid ...
- 170404、java版ftp操作工具类
package com.rick.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotF ...
随机推荐
- Java面试——线程池
1.类比介绍 假如有一个工厂,工厂里面有10个工人,每个工人同时只能做一件任务. 因此只要当10个工人中有工人是空闲的,来了任务就分配给空闲的工人做: 当10个工人都有任务在做时,如果还来了任务,就把 ...
- threading join用法
join():在子线程完成运行之前,这个子线程的父线程将一直被阻塞 import threading #线程import time def Beijing(n): print('Beijing tim ...
- 30_react_router基本使用
项目结构: import React from 'react' import {render} from 'react-dom' import {BrowserRouter} from 'react- ...
- 应用脚手架创建一个React项目
安装脚手架,这里会自动安装到你的nodejs里面 npm install create-react-app -g 进入创建目录 我这里创建一个为 react03的项目,等待下载..... create ...
- C# 导出dataGridView中的值到Excel
C# 怎么导出dataGridView中的值到Excel 1 2 3 4 5 6 在系统应用过程中,数据是系统的核心.如果直接在应用软件中看数据,有时也有些不便,所以就会把系统数据转换成Excel格式 ...
- Unity中的点击,长按,划动
public void GetClickType() { if(Input.GetMouseButtonDown(0)) { if(isGetBeginPos) { beginPosition = I ...
- cdn节点自定义防CC代码在哪里抄
1. 登陆节点的3311后台 1. http redirect(普通) HTTP/1.1 302 FOUNDConnection: keep-aliveLocation: {{url}} <ht ...
- 十、Strategy 策略模式
需求:使用不同的算法解决相同的问题 设计原理: 代码清单: 接口 Strategy public interface Strategy { public abstract Hand nextHand( ...
- Python设计模式 - 基础 - 封装 & 继承 & 多态
面向对象的核心是对象,世间万物都可以看作对象,任何一个对象都可以通过一系列属性和行为来描述,可以包含任意数量和类型的数据或操作.类是用来描述具有相同属性和方法的所有对象的集合.类通常是抽象化的概念,而 ...
- oracle可重复执行脚本(添加字段)
--添加债券期限字段 declare cn integer; begin cn := 0; select count(*) into cn from user_tab_cols t where t.t ...