侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

python 实现简单的FTP程序

Python  /  管理员 发布于 7年前   152

FTP即文件传输协议;它基于客户机-服务器模型体系结构,应用广泛。它有两个通道:一个命令通道和一个数据通道。命令通道用于控制通信,数据通道用于文件的实际传输。使用FTP可以做很多事情,比如移动、下载、复制文件等。

一、开发环境

server端:centos 7  python-3.6.2

客户端:Windows 7 python-3.6.2 pycharm-2018

程序目的:1、学习使用socketserver实现并发处理多个客户端。

             2、了解使用struct解决TCP粘包。

二、程序设计

(本人菜鸟一枚,对于开发规范,接口设计完全不懂,完全是随心所欲,自娱自乐。写博客主要是记录自己学习的点点滴滴,如有不足之处还请见谅。)

1、server端

1.1 目录结构如下:

 1.2 目录简介:

FTP_SERVER:程序主目录

app:程序主逻辑目录,目录下有四个模块:

          FTPserver.py:FTP  Server端启动入口。

          login.py:认证注册模块,用于处理用户注册,登录认证。

          dataAnalysis.py:命令解析模块,负责解析,执行客户端命令。

          FileOpertion.py:负责文件读,写。数据发送,数据接收。

db:存放user_pwd.db文件,用于存放用户信息(用户名,密码,FTP目录总空间,已使用空间等)

lib:存放公共数据。

1.3 模块中类的继承关系

1.4 执行流程

1.4.1 程序启动文件FTPserver.py,程序启动后进入监听状态。核心代码如下:

class MyFtpServer(socketserver.BaseRequestHandler):  def handle(self): # 重写handle方法,处理socket请求 print(f"连接来自{self.client_address}的客户端") commom_obj = Commom() data_analy = DataAnalysis() login_obj = Login() while 1: # 执行用户选项:1、登陆系统 2、注册账号。并返回一个结果 status_id = login_obj.run_client_choice(self.request, commom_obj) if status_id == "01": # 登陆成功 if not self.run_ftp_server(data_analy,commom_obj): # 执行ftpserver主功能  break elif int(status_id) == -1: # client断开连接了 break print(f"客户端{self.client_address}断开了连接") def run_ftp_server(self,data_analy,commom_obj): """" 登陆成功后,接收客户端发来的命令,并进行处理 :param data_analy:负责解析,执行客户端命令的对象 :param commom_obj:程序执行时所需的数据对象 :return 返回false代表客户端断开连接了 """ while True: try: cmd_len_pack = self.request.recv(4)  cmd_len = struct.unpack('i',cmd_len_pack)[0] # 获取命令长度,防止粘包  except Exception: break recv_data = self.request.recv(cmd_len).decode('utf-8') # 接收客户端数据 if recv_data.upper() == "Q": # 客户端提出断开连接了 break # 解析,处理客户端的命令 data_analy.syntax_analysis(recv_data, self.request, commom_obj) return Falseif __name__ == '__main__': print('运行FTP服务') ip_port = ('192.168.10.10',9000) # 创建并发服务端对象 server = socketserver.ThreadingTCPServer(ip_port, MyFtpServer) # 开启服务 server.serve_forever()

 1.4.2 服务端进入监听状态后,客户端发起连接请求,服务端接收连接请求后会等待客户单发来状态码,1表示请求登录FTP服务器,2表示客户端要注册用户,注册用户需要服务端手动反馈状态码1才可注册。处理用户登录,注册模块login.py核心代码如下:

class Login(FileOperation): """ 登陆注册类。主要负责用户的登陆认证,和用户注册。 """ def run_client_choice(self,socket_obj,commom): """ 获取客户端的请求,1是登陆,2是注册用户 :param socket_obj: socket对象 :param commom: ftpserver运行时所需要的数据对象 :return: """ recv_choice = socket_obj.recv(1).decode("utf-8") # 获取用户选项:1是登陆,2是注册用户 if recv_choice == "1": # client请求登陆 return self.login_authen(socket_obj,commom) elif recv_choice == "2": # client请求注册账号 return self.register_user(socket_obj,commom) else: return -1 # client断开连接了 # 用户登陆认证 def login_authen(self,socket_obj,commom): """ 客户端登陆认证 :param socket_obj: socket对象 :param commom: ftpserver运行时需要的数据对象 :return:返回1代表登陆成功 """ # 接收client发来的用户名,密码 recv_userPwd = self.recv_data(socket_obj).decode("utf-8").split("|")  # 效验用户名密码 check_ret = self.check_user_pwd(recv_userPwd, socket_obj,commom) if check_ret: # 用户名密码正确 self.check_user_home_dir(commom,recv_userPwd[0]) # 检测用户家目录 return commom.status_info["login_success"] else: return commom.status_info["login_fail"] ... # 注册用户 def register_user(self,socket_obj,commom): """ :param socket_obj: :param commom: :return: 返回是否允许注册的结果,1允许客户端注册,2拒绝客户端注册 """ while True: choice_id = input("请输入回应码:1是允许注册,2是不允许注册:") if choice_id.isdigit() and 3 > int(choice_id) > 0: socket_obj.send(choice_id.encode("utf-8")) # 发通知告知客户端,处理结果 if choice_id == "1": # 注册用户  return self.client_register(socket_obj, commom) return choice_id else: print("您输入的信息有误,请重新输入。") ...

 1.4.3 客户端登录成功后,服务端会等待接收客户端发来的命令,命令的解析,执行由dataAnalysis.py模块执行,核心代码如下:

class DataAnalysis(FileOperation): """ 数据分析处理类,主要负责解析client发送过来的指令。 """ def syntax_analysis(self,recv_data, socket_obj, commom): """ 负责解析客户端传来的数据。 :param recv_data:接收到的客户端用户数据 :param socket_obj:socket对象 :param commom:数据对象 :return: """ clientData = recv_data.split(" ") if hasattr(self,clientData[0]): # 判断对象方法是否存在 get_fun = getattr(self,clientData[0])#获取对象方法 get_fun(clientData,socket_obj,commom) # 运行对象方法 else: pass ...

执行客户端命令后,继续等待接收客户端发来的命令,如此循环...。

2、客户端

2.1 目录结构如下:

2.2 目录简介:

client:程序主目录。

bin:程序入口,程序启动文件main.py用于建立socket连接,然后调用FTPclient.py模块下的run_ftp_client方法运行程序。

app:程序主逻辑,目录下有四个模块如下:

          FTPclient.py:FTP客户端,根据用户选项,执行用户指令。

          login.py:认证注册模块,用于处理用户注册,登录认证。

          dataAnalysis.py:命令解析模块,解析用户输入的命令,发给服务端获取结果。

          FileOpertion.py:负责文件读,写。

lib:存放公共数据,有两个文件:

       commom.py:主要存放的是公共变量。

       help.txt:存放的是帮助文档,当用户执行help命令时会调用该文件。

2.3 模块中类的继承关系

2.4 执行流程

2.4.1 程序入口main.py,启动后会与FTP服务端建立连接,与服务端连接成功后会调用FTPclient.py模块下的run_ftp_client方法,执行用户功能。核心代码如下:

socket_obj = socket.socket(socket.AF_INET,socket.SOCK_STREAM)socket_obj.connect(("192.168.10.10",9000))client_obj = Client()client_obj.run_ftp_client(socket_obj) # 接收用户输入的选项,执行对应的功能

2.4.2 FTPclient.py模块下的run_ftp_client方法会打印菜单,并等待用户输入选项,执行相应功能,核心代码如下:

class Client(Login,DataAnalysis): def run_ftp_client(self,socket_obj): """ 运行用户输入的选项:1、是登陆 2、是注册账号 :return: """ while True: self.login_menu() # 打印系统菜单 choice_id = self.get_user_choice() # 获取用户输入的选项 if choice_id: if self.run_user_choice(choice_id,socket_obj):  break else: print("您输入的有误") def get_user_choice(self): """ 获取用户输入的选项 :return: """ choice_id = input("请输入选项:") if choice_id.isdigit() and 4 > int(choice_id) > 0 or choice_id.upper() == "Q": return choice_id return False def run_user_choice(self,choice_id,socket_obj): if choice_id == "1": # 登陆系统 socket_obj.send(choice_id.encode("utf-8")) # 发通知告知服务器准备登陆 if self.run_login(socket_obj) == True: # 执行登陆 return True elif choice_id == "2": # 注册用户 socket_obj.send(choice_id.encode("utf-8")) # 请求服务器,注册用户 self.register_user(socket_obj) # 执行注册 elif choice_id.upper() == "Q": # 退出程序 socket_obj.send(choice_id.encode("utf-8")) # 通知服务器,准备退出程序 socket_obj.close() print("程序正常退出") return True def run_login(self,socket_obj,): """ 运行登陆认证模块,如果登陆成功执行程序主逻辑,否则重新登陆。 :param socket_obj: :return: """ if self.login_authention(socket_obj): while True: send_data = input(">>>").strip(" ") # 获取发送数据(用户执行的命令) if send_data.upper() == "Q": # 正常退出程序  socket_obj.send(send_data.encode("utf-8")) # 通知服务区断开连接  socket_obj.close()  print("程序正常退出")  return True if self.syntax_analysis(send_data, socket_obj): # 解析用户数据并处理数据  print("异常退出")  return True return False def login_menu(self): print("-"*41) print(" 欢迎登陆迷你FTPv1.0") print("-"*41) print("1、登陆系统") print("2、用户注册") print("Q、退出程序")

2.4.3 login.py模块主要用于处理注册和登录的功能,核心代码如下:

class Login(Commom): def login_authention(self,socket_obj): """ 登陆认证 :param socket_obj:socket 对象 :return: """ user_pwd = self.get_user_pwd() # 获取用户名密码 self.send_data(socket_obj,user_pwd) # 将用户名和密码发给服务器 recv_status = socket_obj.recv(2).decode("utf-8") # 等待接收状态码 print(self.status_info[recv_status]) # 打印状态码对应的结果 if self.status_info[recv_status] == '登录成功': return True return False ... def register_user(self,socket_obj): """ 等待服务端反馈是否允许注册用户。 :param socket_obj: :return: """ print("请等待服务端回应.....") recv_status = socket_obj.recv(1).decode("utf-8") if recv_status == "1": # 服务端同意申请账号 user_pwd = self.get_regist_user_pwd() # 获取注册用户名和密码 if user_pwd: self.send_data(socket_obj,user_pwd) result = socket_obj.recv(2).decode("utf-8") print(self.status_info[result]) else: print("用户名密码有误") else: # 客户端拒绝申请账号的请求 print("服务端拒绝了您申请账号的请求,请与管理员取得联系。") return False ...

2.4.4 用户登录成功后,会等待接收用户输入命令,由dataAnalysis.py模块负责解析用户输入的命令,并将命令发给FTP服务器,然后接收服务器的反馈。核心代码如下:

class DataAnalysis(FileOperation): def syntax_analysis(self,cmd,socket_obj): """ 解析用户输入的命令。 :param cmd:用户执行的命令,如:put 上传的文件 :param socket_obj:socket对象发送和接收数据 :return: """ cmd_split = cmd.split(" ") # 将字符串命令分割成列表,用于验证命令是否存在 if hasattr(self,cmd_split[0]): run_fun = getattr(self,cmd_split[0]) run_fun(cmd_split,socket_obj) else: print("无效的命令") ...

总结

以上所述是小编给大家介绍的python 实现简单的FTP程序,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!


  • 上一条:
    python打印n位数水仙花数(实例代码)
    下一条:
    python实现异常信息堆栈输出到日志文件
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客