Python网络编程 03 实验:FTP详解
文章目录
- 一、小实验FTP程序需求
- 二、项目文件架构
- 三、服务端
- 1、conf/settings.py
- 2、conf/accounts.cgf
- 3、conf/STATUS_CODE.py
- 4、启动文件 bin/ftp_server.py
- 5、core/main.py
- 6、core/server.py
- 四、客户端
- 1、conf/STATUS_CODE.py
- 2、bin/ftp_client.py
- 五、在终端操作示例
一、小实验FTP程序需求
(1)用户加密认证
(2)允许同时多用户登录
(3)每个用户有自己的家目录,且只能访问自己的家目录
(4)对用户进行磁盘配额,每个用户的可用空间不同
(5)允许用户在FTP server上随意切换目录
(6)允许用户查看当前目录下文件
(7)允许上传和下载文件,保证文件一致性
(8)文件传输过程中显示进度条
(9)附加功能:支持文件的断点续传
二、项目文件架构
三、服务端
1、conf/settings.py
import os
BASE_DIE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))IP = "127.0.0.1"
PORT = 8000ACCOUNT_PATH = os.path.join(BASE_DIE, "conf", "accounts.cfg")
2、conf/accounts.cgf
[DEFAULT][LuMX]
Password = 123
Quotation = 100[root]
Password = root
Quotation = 100
3、conf/STATUS_CODE.py
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"
}
4、启动文件 bin/ftp_server.py
import os, sys# 获取启动模块所在目录的父级目录路径,
PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 将该目录路径添加到导入模块时要搜索的目录列表
sys.path.append(PATH)from core import mainif __name__ == "__main__":main.ArgvHandler() # 启动主函数
5、core/main.py
import optparse
import socketserver
from conf.settings import *
from core import serverclass ArgvHandler:def __init__(self):self.op = optparse.OptionParser()options, args = self.op.parse_args()self.verify_args(args)def verify_args(self,args):cmd = args[0]if hasattr(self, cmd):# 方便扩展,例如可以在终端执行 python ftp_server.py startfunc = getattr(self,cmd)func()def start(self):print("the server is working...")s = socketserver.ThreadingTCPServer((IP, PORT), server.ServerHandler)s.serve_forever()
6、core/server.py
import json,configparser
import os,hashlibfrom conf.STATUS_CODE import *
from conf import settings
import socketserver
class ServerHandler(socketserver.BaseRequestHandler):def handle(self):while True:data = self.request.recv(1024).strip()if not data:print("the connect is breaked")breakdata = json.loads(data.decode("utf-8"))if data.get("action"): # 字典data存在key为action,且不为空,执行下列代码func = getattr(self, data.get("action"))func(**data)else:print("Invalid cmd")def send_response(self, state_code):response = {"status_code": state_code}self.request.sendall(json.dumps(response).encode("utf-8"))def auth(self,**data):username = data["username"]password = data["password"]user = self.authenticate(username, password)if user:self.send_response(254)else:self.send_response(253)def authenticate(self,user,pwd):cfg = configparser.ConfigParser()cfg.read(settings.ACCOUNT_PATH)if user in cfg.sections():if cfg[user]["Password"]==pwd:self.user = userself.mainPath = os.path.join(settings.BASE_DIR,"home",self.user)print("passed authentication")return userdef put(self,**data):print("data",data)file_name = data.get("file_name")file_size = data.get("file_size")target_path = data.get("target_path")abs_path = os.path.join(self.mainPath,target_path,file_name)has_received=0if os.path.exists(abs_path):file_has_size=os.stat(abs_path).st_sizeif file_has_size < file_size:# 断点续传self.request.sendall("800".encode("utf-8"))choice = self.request.recv(1024).decode("utf-8")if choice=="Y":self.request.sendall(str(file_has_size).encode("utf-8"))has_received += file_has_sizef=open(abs_path,"ab")else:f=open(abs_path,"wb")else:# 文件存在,且完整self.request.sendall("801".encode("utf-8"))returnelse:# 文件不存在self.request.sendall("802".encode("utf-8"))f = open(abs_path,"wb")md5_obj = hashlib.md5()while has_received < file_size:md5_data = self.request.recv(32)f_data = self.request.recv(992)if self.md5_check(md5_obj,md5_data,f_data):self.send_response(900)f.write(f_data)has_received += len(f_data)else:print("md5 check error")self.send_response(901)breakf.close()def md5_check(self,md5_obj,md5_data,f_data):md5_obj.update(f_data)if md5_obj.hexdigest().encode("utf-8") == md5_data:return Truedef ls(self, **data):file_list = os.listdir(self.mainPath)file_str="\n".join(file_list)if not len(file_list):file_str="<empty dir>"self.request.sendall(file_str.encode("utf-8"))def cd(self,**data):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("utf-8"))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("create success".encode("utf-8"))else:self.request.sendall("dirname exist".encode("utf-8"))
四、客户端
1、conf/STATUS_CODE.py
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"
}
2、bin/ftp_client.py
import os, sys, hashlib
import optparse,socket,jsonPATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(PATH)from conf.STATUS_CODE import STATUS_CODEclass 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()self.verify_args(self.options)self.make_connection()self.mainPath=os.path.dirname(os.path.abspath(__file__))def verify_args(self,options):'''验证端口号是否合法'''port = options.portif 0 <= int(port) <= 65535:return Trueelse:exit("the port is not in 0-65535")def make_connection(self):'''处理链接'''self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)self.sock.connect((self.options.server, int(self.options.port)))def interactive(self):'''处理通讯'''print("begin to interactive...")if self.authenticate():while True:cmd_info = input("[%s]" %self.current_dir).strip()cmd_list = cmd_info.split()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_listlocal_path=os.path.join(self.mainPath,local_path)file_name=os.path.basename(local_path)file_size=os.stat(local_path).st_sizedata = {"action": "put","file_name": file_name,"file_size": file_size,"target_path": target_path}self.sock.send(json.dumps(data).encode("utf-8"))is_exist=self.sock.recv(1024).decode("utf-8")has_sent=0if is_exist=="800":# 文件不完整choice=input("the file exist,but not enough,do continue?[Y/N]").strip()if choice.upper()=="Y":self.sock.sendall("Y".encode("utf-8"))continue_position=self.sock.recv(1024).decode("utf-8")has_sent += int(continue_position)else:self.sock.sendall("N".encode("utf-8"))elif is_exist=="801":# 文件完全存在print("the file exist")returnf = open(local_path,"rb")f.seek(has_sent)md5_obj = hashlib.md5()while has_sent < file_size:f_data = f.read(992)if self.md5_check(md5_obj,f_data):has_sent += len(f_data)self.show_progress(has_sent,file_size)else:print("md5 check is error!")breakf.close()if has_sent == file_size:print("\n",end="")print("put success!")def md5_check(self,md5_obj,f_data):md5_obj.update(f_data)md5_data = md5_obj.hexdigest().encode("utf-8")data = md5_data + f_dataself.sock.sendall(data)response = self.response()if response["status_code"] == 900:return Truedef show_progress(self,has,total):'''显示进度条'''rate=int(float(has)/float(total)*10000)/10000rate_num=int(rate*100)sys.stdout.write("{:.2%} {}\r".format(rate,rate_num*"#"))# \r 表示光标移动到行首def ls(self,*cmd_list):data={"action": "ls"}self.sock.sendall(json.dumps(data).encode("utf-8"))data=self.sock.recv(1024).decode("utf-8")print(data)def cd(self,*cmd_list):data={"action": "cd","dirname": cmd_list[1]}self.sock.sendall(json.dumps(data).encode("utf-8"))data = self.sock.recv(1024).decode("utf-8")print(os.path.basename(data))self.current_dir=os.path.basename(data)def mkdir(self,*cmd_list):data={"action": "mkdir","dirname": cmd_list[1]}self.sock.sendall(json.dumps(data).encode("utf-8"))data = self.sock.recv(1024).decode("utf-8")print(data)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 response(self):data = self.sock.recv(1024).decode("utf-8")data = json.loads(data)return datadef get_auth_result(self,user,pwd):data = {"action":"auth","username":user,"password":pwd}self.sock.send(json.dumps(data).encode("utf-8"))response=self.response()print("response:",response["status_code"])if response["status_code"]==254:self.user = userself.current_dir=userprint(STATUS_CODE[254])return Trueelse:print(STATUS_CODE[response["status_code"]])ch = ClientHandler()
ch.interactive()
五、在终端操作示例
服务端
客户端
相关文章:
Python网络编程 03 实验:FTP详解
文章目录 一、小实验FTP程序需求二、项目文件架构三、服务端1、conf/settings.py2、conf/accounts.cgf3、conf/STATUS_CODE.py4、启动文件 bin/ftp_server.py5、core/main.py6、core/server.py 四、客户端1、conf/STATUS_CODE.py2、bin/ftp_client.py 五、在终端操作示例 一、小…...
个人银行账户管理程序(2)
在(1)的基础上进行改进 1:增加一个静态成员函数total,记录账户总金额和静态成员函数getTotal 2对不需要改变的对象进行const修饰 3多文件实现 account。h文件 #ifndef _ACCOUNT_ #define _ACCOUNT_ class SavingAccount {pri…...
2024.04.19校招 实习 内推 面经
绿*泡*泡VX: neituijunsir 交流*裙 ,内推/实习/校招汇总表格 1、校招&转正实习 | 美团无人机业务部招聘(内推) 校招&转正实习 | 美团无人机业务部招聘(内推) 2、校招&实习 | 快手 这些岗位…...
Python并发编程 04 进程与线程基础
文章目录 一、操作系统简介二、进程三、线程四、线程的调用1、示例2、join方法3、setDaemon方法4、继承式调用(不推荐)5、其他方法 一、操作系统简介 ①操作系统是一个用来协调、管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用…...
模板引擎Freemarker
什么是模板引擎 根据前边的数据模型分析,课程预览就是把课程的相关信息进行整合,在课程预览界面进行展示,课程预览界面与课程发布的课程详情界面一致。 项目采用模板引擎技术实现课程预览界面。什么是模板引擎? 早期我们采用的…...
刷题训练之模拟
> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:熟练掌握模拟算法。 > 毒鸡汤:学习,学习,再学习 ! 学,然后知不足。 > 专栏选自:刷题训…...
视频监控平台:交通运输标准JTT808设备SDK接入源代码函数分享
目录 一、JT/T 808标准简介 (一)概述 (二)协议特点 1、通信方式 2、鉴权机制 3、消息分类 (三)协议主要内容 1、位置信息 2、报警信息 3、车辆控制 4、数据转发 二、代码和解释 (一…...
【C++】多态 — 多态的细节补充(下篇)
前言: 我们学习了多态的形式和如何使用多态,这一章我们将来讲一讲多态的原理… 目录 动态绑定与静态绑定: 动态绑定与静态绑定: 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为,也称为静态多态,比如…...
系统安全与应用【2】
1.开关机安全控制 1.1 GRUB限制 限制更改GRUB引导参数 通常情况下在系统开机进入GRUB菜单时,按e键可以查看并修改GRUB引导参数,这对服务器是一个极大的威胁。可以为GRUB 菜单设置一个密码,只有提供正确的密码才被允许修改引导参数。 实例&…...
EtherCAT总线速度轴控制功能块(COSESYS ST源代码)
测试环境为汇川PLC,型号 AM402-CPU1608TP、伺服驱动器为禾川X3E,具体通信配置可以参考下面文章链接: 1、使能和点动控制 汇川AM400PLC通过EtherCAT总线控制禾川X3E伺服使能和点动控制-CSDN博客文章浏览阅读31次。进行通信之前需要安装禾川X3E的XML文件,具体方法如下:1、汇…...
【码银送书第十九期】《图算法:行业应用与实践》
作者:嬴图团队 01 前言 在当今工业领域,图思维方式与图数据技术的应用日益广泛,成为图数据探索、挖掘与应用的坚实基础。本文旨在分享嬴图团队在算法实践应用中的宝贵经验与深刻思考,不仅促进业界爱好者之间的交流,…...
无监督式学习
1.是什么? 无监督式学习与监督式学习**最大的区别就是:**没有事先给定的训练实例,它是自动对输入的示例进行分类或者分群; 优点:不需要标签数据,极大程度上扩大了我们的数据样本,其次不受监督信…...
docker 安装镜像及使用命令
目录 1. Mysql2. Redis3. Nginx4. Elasticsearch官网指导 docker pull 容器名:版本号 拉取容器, 不指定版本号默认最新的 run 运行 -d 后台运行 -p 3306:3306 -p是port 对外端口:对内端口 –name xyy_mysql 容器名称 -e MYSQL_ROOT_PASSWORD123456 环境变量 -v 系统地址:docker…...
Python运维之多进程!!
本节的快速导航目录如下喔!!! 一、创建进程的类Process 二、进程并发控制之Semaphore 三、进程同步之Lock 四、进程同步之Event 五、进程优先队列Queue 六、多进程之进程池Pool 七、多进程之数据交换Pipe 一、创建进程的类Process mu…...
Redis(无中心化集群搭建)
文章目录 1.无中心化集群1.基本介绍2.集群说明 2.基本环境搭建1.部署规划(6台服务器)2.首先删除上次的rdb和aof文件(对之前的三台服务器都操作)1.首先分别登录命令行,关闭redis2.清除/root/下的rdb和aof文件3.把上次的…...
基于springboot+jsp+Mysql的商务安全邮箱邮件收发
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...
三.Django--ORM(操作数据库)
目录 1 什么是ORM 1.1 ORM优势 1.2ORM 劣势 1.3 ORM与数据库的关系 2 ORM 2.1 作用 2.2 连接数据库 2.3 表操作--设置字段 2.4 数据库的迁移 写路由增删改查操作 项目里的urls.py: app里的views.py: 注意点: 1 什么是ORM ORM中文---对象-关系映射 在MTV,MVC设计…...
【华为】AC直连二层组网隧道转发实验配置
【华为】AC直连二层组网隧道转发实验配置 实验需求拓扑配置AC数据规划表 AC的配置顺序AC1基本配置(二层通信)AP上线VAP组关联--WLAN业务流量 LSW1AR1STA获取AP的业务流量 配置文档 实验需求 AC组网方式:直连二层组网。 业务数据转发方式:隧道转发。 DHC…...
第 129 场 LeetCode 双周赛题解
A 构造相同颜色的正方形 枚举:枚举每个 3 3 3\times 3 33的矩阵,判断是否满足条件 class Solution {public:bool canMakeSquare(vector<vector<char>>& grid) {for (int i 0; i < 2; i)for (int j 0; j < 2; j) {int c1 0, c…...
GStreamer日志调试笔记
1、查询所有分类 #gst-launch-1.0 --gst-debug-help 2、查询videotestsrc的日志 #gst-launch-1.0 --gst-debug-help | findstr videotestsrc 结果: 3、使用--gst-debug设置相应日志类型的相应等级,越大显示日志越多,排查内存泄露可以设置为9 …...
【api接口开通教程】YouTube Data API v3申请流程
一、背景调查 1.1 API接口介绍 采集youtube数据,大体分为两种方案:一种是基于爬虫,一种是基于API接口。 说人话就是:爬虫相当于走后门、爬窗户(利用技术手段窃取,人家没说给,但我硬拿&#x…...
.net 6.0 框架集成ef实战,步骤详解
一、代码框架搭建 搭建如下代码架构: 重点含EntityFrameworkCore工程,该工程中包含AppDbContext.cs和数据表实体AggregateObject 1、AppDbContext 代码案例 //AppDbContext 代码案例using Microsoft.EntityFrameworkCore;namespace EntityFrameworkCo…...
[C/C++] -- 观察者模式
观察者模式是一种行为型设计模式,用于定义对象间的一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。 观察者模式涉及以下几个角色: 主题(Subject)&…...
秋招算法刷题8
20240422 2.两数相加 时间复杂度O(max(m,n)),空间复杂度O(1) public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode headnull,tailnull;int carry0;while(l1!null||l2!null){int n1l1!null?l1.val:0;int n2l2!…...
Docker使用方法
Docker是一种容器化平台,它可以帮助开发人员将应用程序和其依赖项打包成一个独立的、可移植的容器,以便在不同的环境中运行。 以下是使用Docker的基本步骤: 安装Docker:首先,您需要在您的机器上安装Docker。您可以从D…...
HTML学习|网页基本信息、网页基本标签、图像标签、超链接标签、列表标签、表格标签、媒体元素、页面结构分析、iframe内联框架
网页基本信息 DOCTYPE是设置使用什么规范,网页整个信息都在html标签中,head标签里包含字符集设置,网页介绍等信息,title标签是网页的名称,网页的主干都在body标签中 网页基本标签 标题标签 h1~h6都是标题标签&#x…...
001 websocket(评论功能demo)(消息推送)
文章目录 ReviewController.javaWebSocketConfig.javaWebSocketProcess.javaServletInitializer.javaWebsocketApplication.javareadmeindex.htmlapplication.yamlpom.xml ReviewController.java package com.example.controller;import com.example.websocket.WebSocketProces…...
二分查找向下取整导致的死循环69. x 的平方根
二分查找向下取整导致的死循环 考虑伪题目:从数组arr中查找出目标元素target对应的下标,如果数组中不存在目标元素,找 到第一个元素值小于target的元素的下标。 编写二分查找算法如下: Testvoid testBinarySearch(){int[] arr n…...
Kivy 异步任务
如果要进行一些非常耗时的操作(例如:爬虫等),那么页面就会在这里卡住,而系统就会以为这个软件无响应,并提示关闭,可以说明用户体验极差,因此我们在此处引入异步操作。 在py中引入事件调节器,并在…...
DEV--C++小游戏(吃星星(0.1))
目录 吃星星(0.1) 简介 头文件 命名空间变量 副函数 清屏函数 打印地图函数 移动函数 主函数 0.1版完整代码 吃星星(0.1) 注:版本<1为未实现或只实现部分 简介 用wasd去吃‘*’ 头文件 #include<bi…...
备案网站名称 怎么填写/电商运营转行后悔了
前端面试题(3) 1、iframe有那些缺点? iframe会阻塞主页面的Onload事件;搜索引擎的检索程序无法解读这种页面,不利于SEO;iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页…...
wordpress用markdown/深圳网站建设
很早之前就遇到过这个问题,相信很多同学也曾为这个问题苦恼过N久。问题是这样的:DateTime.Today.ToString("yyyy-MM-dd") --> "2011-06-14"DateTime.Today.ToString("yyyy/MM/dd") --> "2011-06-14"神奇…...
平台推广策划文案/福州百度推广排名优化
最近几年,实体店的日子越来越不好过,很多实体店都面临着获客难的窘境。因此,很多实体店想知道:"用什么样的推广工具、方式,能获得大量流量"。诞生于2017年的微信小程序就是一款能够带来大量流量的推广工具。…...
私做政府网站什么罪/深圳网络推广优化
【来信】 贺老师你好,我是一名普通二本网络工程专业的大三学生。眼看着大三上学期又要结束了,非常的焦虑。之前一直没有好好学习,学的东西少之又少,大三下学期结束就要开始找实习了。学校开了java基础课程,这学期就…...
长沙做网站seo优化外包/如何在百度发布广告
:%!python -m json.tool https://www.jianshu.com/p/91c2d7a54eb7...
怎么做自己的淘宝网站/站长工具ip地址
本篇文章小编给大家分享一下Java虚拟机内存溢出与内存泄漏代码原理解析,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。一、基本概念内存溢出:简单地说内存溢出就是指…...