python实现FTP程序
python实现FTP程序
程序源码
目录结构
服务端
主程序
import optparse
import socketserver
import server
import configs class ArgvHandler():
def __init__(self):
#命令行解析
self.op=optparse.OptionParser()
self.op.add_option('-S', '--server', dest='server')
self.op.add_option('-P', '--port', dest='port')
options,args=self.op.parse_args() #options的值为添加对应的值,args为输入的无关值 #进行命令分发
self.verify_args(options,args)
#命令分发
def verify_args(self,options,args):
print(options,args)
cmd=args[0]
print(cmd)
if hasattr(self,str(cmd)):
func=getattr(self,str(cmd))
func()
#启动服务端
def start(self): #启动服务端
s=socketserver.ThreadingTCPServer((configs.IP,int(configs.PORT)),server.ServerHandler)
#永久启动服务端
s.serve_forever() #帮助信息
def help(self):
pass
if __name__ =='__main__':
ArgvHandler()
main.py
核心代码
import socketserver
import json
import configparser
import configs
import os ''' ''' STATUS_CODE={
250:"Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344}",
251:"Invalid cmd",
252:"Invalid auth data",
253:"Wrong username or password",
254:"Passed authentication",
255:"Filename doesn't provided",
256:"File doesn't exist on server",
257:"ready to send file",
258:"md5 verification",
800:"the file exist,but not enough,is continue",
801:"the file exist",
802:"ready to receive datas",
900:"md5 valdate success", } #服务端处理代码
class ServerHandler(socketserver.BaseRequestHandler):
def handle(self):
#接收客户端信息,循环接收处理
while 1:
try:
data=self.request.recv(1024).strip().decode('utf8')
except Exception as e:
continue
#将数据转成一个json字典的形式
if data :
data=json.loads(data)
print(data) #传过来的数据格式
# {'action':'auth',
# 'username':'admin',
# 'password':'123456'} #外层判断命令是否为空
#内层循环判断是否有这个命令
if data.get('action'):
if hasattr(self,data.get('action')):
func=getattr(self,data.get('action'))
func(**data)
else:
print()
else:
print('') #认证
def auth(self,**data):
username=data['username']
passwd=data['password']
print(username,passwd)
print(4)
username=self.authenticate(username,passwd) if username:
self.send_reponse(254)
else:
self.send_reponse(253) def authenticate(self,user,passwd):
print(5)
cfg=configparser.ConfigParser()
# cfg.read(configs.auth_path)
cfg.read('auth.cfg')
if user in cfg.sections(): if cfg[user]['passwd']==passwd:
#
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
self.user=user
#定义用户的本地目录,在home目录下
self.mainPath=os.path.join(BASE_DIR,'home',self.user)
print("登陆成功")
return user def send_reponse(self,state_code):
print(6)
response={"status_code":state_code,"status_mes":STATUS_CODE[state_code]}
self.request.sendall(json.dumps(response).encode("utf-8")) #上传
def put(self,**data):
print("data:",data)
file_name=data.get('file_name')
file_size=data.get('file_size')
target_path=data.get('target_path')
#这个路径对应的上传的完整路径:self.mainPath,target_path+file_name路径
#self.mainPath:home+username
#self.target:文件类型
#file_name:文件名 #完整的文件名
has_receive=0
abs_path=os.path.join(self.mainPath,target_path,file_name)
print(abs_path) #上传文件:
# 1.已经存在这个文件:如果文件完整,则返回文件存在,如果文件不完整,则返回选择续传还是不续传
# 2.没有这个文件:直接上传文件
#对应文件打开模式:不存在:wb 续传:ab 存在完整:不打开 # 文件存在
if os.path.exists(abs_path): file_has_size=os.stat(abs_path).st_size
print(file_size,file_has_size)
# 文件存在,且完整
if file_size==file_has_size:
print(1)
self.request.sendall(''.encode("utf8"))
return
#断点续传
elif file_has_size<file_size:
self.request.sendall(''.encode("utf8"))
choice=self.request.recv(1024).decode('utf8')
#续传
print(2)
if choice=="Y":
self.request.sendall(str(file_has_size).encode("utf8"))
has_receive+=file_has_size
#这里注意光标的位置,以追加方式打开,光标在文件里的位置在最后
f=open(abs_path,"ab")
#不续传,重传
else:
f = open(abs_path, "wb") else:
#文件不存在
print(3)
self.request.sendall(''.encode("utf8"))
f=open(abs_path,"wb")
#has_receive:已经接收到数据大小
while has_receive<file_size:
try:
data=self.request.recv(1024)
f.write(data)
has_receive+=len(data)
except Exception as e:
break
f.close()
#cd与ls都要依靠用户的self.mainPath去做处理
#而self.mainPath一直都是用户当前所在的目录
#查看文件
def ls(self,**data):
file_list=os.listdir(self.mainPath)
if len(file_list)==0:
file_str="<empty dir>"
else:
file_str="\n".join(file_list)
self.request.sendall(file_str.encode("utf8"))
#cd命令
def cd(self,**data):
#cd image
dirname=data.get("dirname")
if dirname=="..":
# 返回目录名
self.mainPath=os.path.dirname(self.mainPath)
else: self.mainPath=os.path.join(self.mainPath,dirname)
self.request.sendall(self.mainPath.encode('utf8'))
#创建目录
def mkdir(self,**data):
dirname=data.get("dirname")
path=os.path.join(self.mainPath,dirname)
if not os.path.exists(path):
if "/" in dirname:
os.makedirs(path)
else:
os.mkdir(path)
self.request.sendall("dirname create success".encode("utf8"))
else:
self.request.sendall("dirname exist".encode("utf8"))
server.py
日志文件
logger.py
配置文件
config.py
import os
IP="127.0.0.1"
PORT="" # BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# auth_path=os.path.join(BASE_DIR,"conf","auth.cfg")
数据文件
auth.cfg
[DEFAULT] [yuan]
passwd=123098 [root]
passwd=wenli
保存用户名与密码
客户端
import optparse
import socket
import json
import re
import os
import sys STATUS_CODE={
250:"Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344}",
251:"Invalid cmd",
252:"Invalid auth data",
253:"Wrong username or password",
254:"Passed authentication",
255:"Filename doesn't provided",
256:"File doesn't exist on server",
257:"ready to send file",
258:"md5 verification",
800:"the file exist,but not enough,is continue",
801:"the file exist",
802:"ready to receive datas",
900:"md5 valdate success", }
class ClientHandler():
def __init__(self):
self.op=optparse.OptionParser()
self.op.add_option('-S','--server',dest='server')
self.op.add_option('-P', '--port', dest='port')
self.op.add_option('-u', '--username', dest='username')
self.op.add_option('-p', '--password', dest='password')
self.options, self.args = self.op.parse_args()
#上传文件的绝对路径
#os.path.abspath(__file__):获得当前文件的绝对路径
# os.path.dirname(os.path.abspath(__file__)):获得上一级目录
self.mainPath=os.path.dirname(os.path.abspath(__file__))
self.last = 0 #下面两个函数是实例化类的时候就执行
#对参数进行处理
self.verify_args(self.options)
#连接服务端,进行用户操作
self.make_connection() # 对参数进行处理
def verify_args(self,options):
server=options.server
port=options.port
username=options.username
password=options.password
#对参数进行简单判断
if re.match(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",str(server)):
return True
else:
exit("IP vaild")
if int(port) and int(port) < 65535:
return True
else:
exit("the port is in 0-65535") if username is None:
return True
else:
exit("用户名为空") if password is None:
return True
else:
exit("密码为空") #连接服务端
def make_connection(self):
#创建socket
self.sock=socket.socket()
self.sock.connect((self.options.server,int(self.options.port))) # 用户操作
def interactive(self):
#先进行身份认证
if self.authenticate():
print('''请选择你要进行的操作:
1.上传文件示例:put filename file
2.查看文件:ls
3.进入目录:cd dirname
4.创建目录:mkdir dirname
5.退出:quit
''')
while 1:
cmd_info=input("[%s]:"%self.user).strip()#put test.py file cmd_list=cmd_info.split()#默认以空格分隔
if cmd_list[0]=="quit":break
if hasattr(self,cmd_list[0]):
func=getattr(self,cmd_list[0])
func(*cmd_list) #传输文件的路径必须和客户端路径同级
def put(self,*cmd_list):
action,local_path,target_path=cmd_list
print( action,local_path,target_path)
# os.path.join(self.mainPath, local_path):self.mainPath+local_path得到本地完全的图片的路径
#这里首先对格式进行判断 #获取文件完整路径
local_path=os.path.join(self.mainPath,local_path)
#获取文件的名字
file_name=os.path.basename(local_path)
#获取文件大小
file_size=os.stat(local_path).st_size
data = {
'action': 'put',
'file_name':file_name,
'file_size':file_size,
'target_path':target_path#类型
}
has_sent=0
self.sock.send(json.dumps(data).encode('utf-8'))
is_exist=int(self.sock.recv(1024).decode("utf-8"))
if is_exist==800:
print(STATUS_CODE[is_exist])
choice=input('请输入你的选择是否选择续传:[Y/N]')
if choice.upper()=="Y":
self.sock.sendall("Y".encode("utf8"))
continue_position=self.sock.recv(1024).decode("utf8")
has_sent+=int(continue_position)
else:
self.sock.sendall("N".encode("utf8"))
elif is_exist==801:
print(STATUS_CODE[is_exist])
return
else:
print(STATUS_CODE[is_exist]) f=open(local_path,"rb")
#将光标的位置调整到has_sent
f.seek(has_sent)
while has_sent<file_size:
data=f.read(1024)
self.sock.sendall(data)
has_sent+=len(data)
self.show_progress(has_sent,file_size)
f.close() def show_progress(self,has,total):
rate=float(has)/float(total)
rate_num=int(rate*100)
sys.stdout.write("%s%% %s\r"%(rate_num,"#"* rate_num)) def ls(self,*cmd_list):
data= {
'action': 'ls',
}
self.sock.sendall((json.dumps(data).encode("utf8")))
reponse=self.sock.recv(1024).decode("utf8")
print(reponse) def cd(self,*cmd_list):
data={
'action': 'cd',
'dirname':cmd_list[1]
}
self.sock.sendall((json.dumps(data).encode("utf8")))
reponse = self.sock.recv(1024).decode("utf8")
# self.current_dir=reponse
print("当前目录:"+str(reponse)) def mkdir(self,*cmd_list): data = {
'action': 'mkdir',
'dirname': cmd_list[1]
}
self.sock.sendall((json.dumps(data).encode("utf8")))
reponse = self.sock.recv(1024).decode("utf8")
print(reponse) #身份认证
def authenticate(self):
#如果用户名或者密码有一个为空,则要求再次输入,反之进入下一步
if self.options.username is None or self.options.password is None:
username=input('username:')
password=input('password')
return self.get_auth_result(username,password) return self.get_auth_result(self.options.username,self.options.password) #发送认证信息
def get_auth_result(self,username,password):
# 构建数据
dic={
'action':'auth',
'username':username,
'password':password
}
#发送认证信息
self.sock.send(json.dumps(dic).encode('utf-8'))
#判断服务端回复信息,进行认证
response=self.response()
if response['status_code']==254:
self.user=username
self.current_dir=username
print(STATUS_CODE[254])
else:
print(response['status_code']+response['status_mes'])
return True #接收信息
def response(self):
data = self.sock.recv(1024).decode('utf-8')
data = json.loads(data)
return data ch=ClientHandler()
# 用户操作,在用户操作里面会进行身份认证 ch.interactive()
FTP_Client.py
上传功能
查看文件
cd功能
创建目录
python实现FTP程序的更多相关文章
- python之FTP程序(支持多用户在线)
转发注明出处:http://www.cnblogs.com/0zcl/p/6259128.html 一.需求 1. 用户加密认证 (完成)2. 允许同时多用户登录 (完成)3. 每个用户有自己的家目录 ...
- Python开发程序:FTP程序
作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...
- 用python开发简单ftp程序
根据alex老师视频开发的简单ftp程序,只能实现简单的get功能 ftp客户端程序: #!/usr/bin/env python #_*_ coding:utf-8 _*_ import socke ...
- (转)Python开发程序:支持多用户在线的FTP程序
原文链接:http://www.itnose.net/detail/6642756.html 作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ...
- [ python ] 项目一:FTP程序
声明: 该项目参考学习地址: http://www.cnblogs.com/lianzhilei/p/5869205.html , 感谢博主分享,如有侵权,立即删除. 作业:开发一个支持多用户在线的F ...
- Python开发【项目】:FTP程序
作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...
- 老男孩python作业7-开发一个支持多用户在线的FTP程序
作业6:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...
- Python3学习之路~8.6 开发一个支持多用户在线的FTP程序-代码实现
作业: 开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...
- [源码]python Scapy Ftp密码嗅探
[源码]python Scapy Ftp密码嗅探 原理很简单,FTP密码明文传输的 截取tcp 21端口User和Pass数据即可 Scapy框架编译程序较大(一个空程序都25M),所以就不提供exe ...
随机推荐
- Magento 架构基础知识概述
Megento 架构基础知识概述 Magento整合了面向对象的基于PHP的应用程序的核心架构原则.这些一般原则的综合讨论既有在线的,也有印刷形式.以下讨论主要关注这些主题如何直接应用于Magento ...
- Pthread 用法笔记
什么是线程? 从技术上讲,一个线程被定义为一个独立的指令流. 一个进程可以包含一个或多个线程. 线程操作包括线程创建,终止,同步(连接,阻塞),调度,数据管理和进程交互. 进程内的所有线程共享: 相同 ...
- [luogu3380][bzoj3196]【模板】二逼平衡树【树套树】
题目地址 [洛谷传送门] 题目大意 区间查询k的排名,查找k排名的数,单点修改,区间前驱,区间后继. 感想 真的第一次写树套树,整个人都不对了.重构代码2次,发现样例都过不了,splay直接爆炸,可能 ...
- hdu 1848 简单SG函数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1848 Problem Description 任何一个大学生对菲波那契数列(Fibonacci num ...
- GoLang-Beego使用
1.beego 注意事项 beego的默认架构是mvc python的django默认是mtv package main import ( "github.com/astaxie/beego ...
- Subversion配置
1.下载Apache-Subversion-1.9.7:https://github.com/wangfajun/dev-tools 2.打开idea-->File-->Settings, ...
- Entity Framework入门教程(1)---Entity Framework简介
什么是Entity Framework 学习EF的前提:熟练使用Linq和Ado.net,因为在使用EF框架进行开发时,我们大多数情况使用Linq进行查询和操作,而EF的底层实现用的是Ado.net. ...
- 第十五节:深入理解async和await的作用及各种适用场景和用法
一. 同步VS异步 1. 同步 VS 异步 VS 多线程 同步方法:调用时需要等待返回结果,才可以继续往下执行业务 异步方法:调用时无须等待返回结果,可以继续往下执行业务 开启新线程:在主线程之外 ...
- MYSQL(三)
转载自https://www.cnblogs.com/wupeiqi/articles/5716963.html 1.索引 索引是表的目录,在查找内容之前可以先在目录中查找索引位置,以此快速定位查询数 ...
- HTTP协议09-响应首部字段
响应首部字段 响应首部字段是由服务器向客户端返回响应报文中所使用的字段,用于补充响应的附加信息.服务器信息,以及对客户端的附加要求等信息. 1)Accept-Ranges Accept-Range:b ...