当前位置: 首页 > news >正文

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)

在&#xff08;1&#xff09;的基础上进行改进 1&#xff1a;增加一个静态成员函数total&#xff0c;记录账户总金额和静态成员函数getTotal 2对不需要改变的对象进行const修饰 3多文件实现 account。h文件 #ifndef _ACCOUNT_ #define _ACCOUNT_ class SavingAccount {pri…...

2024.04.19校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、校招&转正实习 | 美团无人机业务部招聘&#xff08;内推&#xff09; 校招&转正实习 | 美团无人机业务部招聘&#xff08;内推&#xff09; 2、校招&实习 | 快手 这些岗位…...

Python并发编程 04 进程与线程基础

文章目录 一、操作系统简介二、进程三、线程四、线程的调用1、示例2、join方法3、setDaemon方法4、继承式调用&#xff08;不推荐&#xff09;5、其他方法 一、操作系统简介 ①操作系统是一个用来协调、管理和控制计算机硬件和软件资源的系统程序&#xff0c;它位于硬件和应用…...

模板引擎Freemarker

什么是模板引擎 根据前边的数据模型分析&#xff0c;课程预览就是把课程的相关信息进行整合&#xff0c;在课程预览界面进行展示&#xff0c;课程预览界面与课程发布的课程详情界面一致。 项目采用模板引擎技术实现课程预览界面。什么是模板引擎&#xff1f; 早期我们采用的…...

刷题训练之模拟

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握模拟算法。 > 毒鸡汤&#xff1a;学习&#xff0c;学习&#xff0c;再学习 ! 学&#xff0c;然后知不足。 > 专栏选自&#xff1a;刷题训…...

视频监控平台:交通运输标准JTT808设备SDK接入源代码函数分享

目录 一、JT/T 808标准简介 &#xff08;一&#xff09;概述 &#xff08;二&#xff09;协议特点 1、通信方式 2、鉴权机制 3、消息分类 &#xff08;三&#xff09;协议主要内容 1、位置信息 2、报警信息 3、车辆控制 4、数据转发 二、代码和解释 &#xff08;一…...

【C++】多态 — 多态的细节补充(下篇)

前言&#xff1a; 我们学习了多态的形式和如何使用多态&#xff0c;这一章我们将来讲一讲多态的原理… 目录 动态绑定与静态绑定: 动态绑定与静态绑定: 静态绑定又称为前期绑定(早绑定)&#xff0c;在程序编译期间确定了程序的行为&#xff0c;也称为静态多态&#xff0c;比如…...

系统安全与应用【2】

1.开关机安全控制 1.1 GRUB限制 限制更改GRUB引导参数 通常情况下在系统开机进入GRUB菜单时&#xff0c;按e键可以查看并修改GRUB引导参数&#xff0c;这对服务器是一个极大的威胁。可以为GRUB 菜单设置一个密码&#xff0c;只有提供正确的密码才被允许修改引导参数。 实例&…...

EtherCAT总线速度轴控制功能块(COSESYS ST源代码)

测试环境为汇川PLC,型号 AM402-CPU1608TP、伺服驱动器为禾川X3E,具体通信配置可以参考下面文章链接: 1、使能和点动控制 汇川AM400PLC通过EtherCAT总线控制禾川X3E伺服使能和点动控制-CSDN博客文章浏览阅读31次。进行通信之前需要安装禾川X3E的XML文件,具体方法如下:1、汇…...

【码银送书第十九期】《图算法:行业应用与实践》

作者&#xff1a;嬴图团队 01 前言 在当今工业领域&#xff0c;图思维方式与图数据技术的应用日益广泛&#xff0c;成为图数据探索、挖掘与应用的坚实基础。本文旨在分享嬴图团队在算法实践应用中的宝贵经验与深刻思考&#xff0c;不仅促进业界爱好者之间的交流&#xff0c;…...

无监督式学习

1.是什么&#xff1f; 无监督式学习与监督式学习**最大的区别就是&#xff1a;**没有事先给定的训练实例&#xff0c;它是自动对输入的示例进行分类或者分群&#xff1b; 优点&#xff1a;不需要标签数据&#xff0c;极大程度上扩大了我们的数据样本&#xff0c;其次不受监督信…...

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运维之多进程!!

本节的快速导航目录如下喔&#xff01;&#xff01;&#xff01; 一、创建进程的类Process 二、进程并发控制之Semaphore 三、进程同步之Lock 四、进程同步之Event 五、进程优先队列Queue 六、多进程之进程池Pool 七、多进程之数据交换Pipe 一、创建进程的类Process mu…...

Redis(无中心化集群搭建)

文章目录 1.无中心化集群1.基本介绍2.集群说明 2.基本环境搭建1.部署规划&#xff08;6台服务器&#xff09;2.首先删除上次的rdb和aof文件&#xff08;对之前的三台服务器都操作&#xff09;1.首先分别登录命令行&#xff0c;关闭redis2.清除/root/下的rdb和aof文件3.把上次的…...

基于springboot+jsp+Mysql的商务安全邮箱邮件收发

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…...

三.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组网方式&#xff1a;直连二层组网。 业务数据转发方式&#xff1a;隧道转发。 DHC…...

第 129 场 LeetCode 双周赛题解

A 构造相同颜色的正方形 枚举&#xff1a;枚举每个 3 3 3\times 3 33的矩阵&#xff0c;判断是否满足条件 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 结果&#xff1a; 3、使用--gst-debug设置相应日志类型的相应等级&#xff0c;越大显示日志越多&#xff0c;排查内存泄露可以设置为9 …...

【api接口开通教程】YouTube Data API v3申请流程

一、背景调查 1.1 API接口介绍 采集youtube数据&#xff0c;大体分为两种方案&#xff1a;一种是基于爬虫&#xff0c;一种是基于API接口。 说人话就是&#xff1a;爬虫相当于走后门、爬窗户&#xff08;利用技术手段窃取&#xff0c;人家没说给&#xff0c;但我硬拿&#x…...

.net 6.0 框架集成ef实战,步骤详解

一、代码框架搭建 搭建如下代码架构&#xff1a; 重点含EntityFrameworkCore工程&#xff0c;该工程中包含AppDbContext.cs和数据表实体AggregateObject 1、AppDbContext 代码案例 //AppDbContext 代码案例using Microsoft.EntityFrameworkCore;namespace EntityFrameworkCo…...

[C/C++] -- 观察者模式

观察者模式是一种行为型设计模式&#xff0c;用于定义对象间的一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都会得到通知并自动更新。 观察者模式涉及以下几个角色&#xff1a; 主题&#xff08;Subject&#xff09;&…...

秋招算法刷题8

20240422 2.两数相加 时间复杂度O&#xff08;max(m,n))&#xff0c;空间复杂度O&#xff08;1&#xff09; 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是一种容器化平台&#xff0c;它可以帮助开发人员将应用程序和其依赖项打包成一个独立的、可移植的容器&#xff0c;以便在不同的环境中运行。 以下是使用Docker的基本步骤&#xff1a; 安装Docker&#xff1a;首先&#xff0c;您需要在您的机器上安装Docker。您可以从D…...

HTML学习|网页基本信息、网页基本标签、图像标签、超链接标签、列表标签、表格标签、媒体元素、页面结构分析、iframe内联框架

网页基本信息 DOCTYPE是设置使用什么规范&#xff0c;网页整个信息都在html标签中&#xff0c;head标签里包含字符集设置&#xff0c;网页介绍等信息&#xff0c;title标签是网页的名称&#xff0c;网页的主干都在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 的平方根

二分查找向下取整导致的死循环 考虑伪题目&#xff1a;从数组arr中查找出目标元素target对应的下标&#xff0c;如果数组中不存在目标元素&#xff0c;找 到第一个元素值小于target的元素的下标。 编写二分查找算法如下&#xff1a; Testvoid testBinarySearch(){int[] arr n…...

Kivy 异步任务

如果要进行一些非常耗时的操作(例如&#xff1a;爬虫等)&#xff0c;那么页面就会在这里卡住&#xff0c;而系统就会以为这个软件无响应&#xff0c;并提示关闭&#xff0c;可以说明用户体验极差&#xff0c;因此我们在此处引入异步操作。 在py中引入事件调节器&#xff0c;并在…...

DEV--C++小游戏(吃星星(0.1))

目录 吃星星&#xff08;0.1&#xff09; 简介 头文件 命名空间变量 副函数 清屏函数 打印地图函数 移动函数 主函数 0.1版完整代码 吃星星&#xff08;0.1&#xff09; 注&#xff1a;版本<1为未实现或只实现部分 简介 用wasd去吃‘*’ 头文件 #include<bi…...

备案网站名称 怎么填写/电商运营转行后悔了

前端面试题&#xff08;3&#xff09; 1、iframe有那些缺点&#xff1f; iframe会阻塞主页面的Onload事件&#xff1b;搜索引擎的检索程序无法解读这种页面&#xff0c;不利于SEO;iframe和主页面共享连接池&#xff0c;而浏览器对相同域的连接有限制&#xff0c;所以会影响页…...

wordpress用markdown/深圳网站建设

很早之前就遇到过这个问题&#xff0c;相信很多同学也曾为这个问题苦恼过N久。问题是这样的&#xff1a;DateTime.Today.ToString("yyyy-MM-dd") --> "2011-06-14"DateTime.Today.ToString("yyyy/MM/dd") --> "2011-06-14"神奇…...

平台推广策划文案/福州百度推广排名优化

最近几年&#xff0c;实体店的日子越来越不好过&#xff0c;很多实体店都面临着获客难的窘境。因此&#xff0c;很多实体店想知道&#xff1a;"用什么样的推广工具、方式&#xff0c;能获得大量流量"。诞生于2017年的微信小程序就是一款能够带来大量流量的推广工具。…...

私做政府网站什么罪/深圳网络推广优化

【来信】   贺老师你好&#xff0c;我是一名普通二本网络工程专业的大三学生。眼看着大三上学期又要结束了&#xff0c;非常的焦虑。之前一直没有好好学习&#xff0c;学的东西少之又少&#xff0c;大三下学期结束就要开始找实习了。学校开了java基础课程&#xff0c;这学期就…...

长沙做网站seo优化外包/如何在百度发布广告

:%!python -m json.tool https://www.jianshu.com/p/91c2d7a54eb7...

怎么做自己的淘宝网站/站长工具ip地址

本篇文章小编给大家分享一下Java虚拟机内存溢出与内存泄漏代码原理解析&#xff0c;文章代码介绍的很详细&#xff0c;小编觉得挺不错的&#xff0c;现在分享给大家供大家参考&#xff0c;有需要的小伙伴们可以来看看。一、基本概念内存溢出&#xff1a;简单地说内存溢出就是指…...