python 实现简单的FTP程序
FTP即文件传输协议;它基于客户机-服务器模型体系结构,应用广泛。它有两个通道:一个命令通道和一个数据通道。命令通道用于控制通信,数据通道用于文件的实际传输。使用FTP可以做很多事情,比如移动、下载、复制文件等。
一、开发环境
server端:centos7 python-3.6.2
客户端:Windows7python-3.6.2pycharm-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,程序启动后进入监听状态。核心代码如下:
classMyFtpServer(socketserver.BaseRequestHandler): defhandle(self):#重写handle方法,处理socket请求 print(f"连接来自{self.client_address}的客户端") commom_obj=Commom() data_analy=DataAnalysis() login_obj=Login() while1: #执行用户选项:1、登陆系统2、注册账号。并返回一个结果 status_id=login_obj.run_client_choice(self.request,commom_obj) ifstatus_id=="01":#登陆成功 ifnotself.run_ftp_server(data_analy,commom_obj):#执行ftpserver主功能 break elifint(status_id)==-1:#client断开连接了 break print(f"客户端{self.client_address}断开了连接") defrun_ftp_server(self,data_analy,commom_obj): """" 登陆成功后,接收客户端发来的命令,并进行处理 :paramdata_analy:负责解析,执行客户端命令的对象 :paramcommom_obj:程序执行时所需的数据对象 :return返回false代表客户端断开连接了 """ whileTrue: try: cmd_len_pack=self.request.recv(4) cmd_len=struct.unpack('i',cmd_len_pack)[0]#获取命令长度,防止粘包 exceptException: break recv_data=self.request.recv(cmd_len).decode('utf-8')#接收客户端数据 ifrecv_data.upper()=="Q":#客户端提出断开连接了 break #解析,处理客户端的命令 data_analy.syntax_analysis(recv_data,self.request,commom_obj) returnFalse if__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核心代码如下:
classLogin(FileOperation): """ 登陆注册类。主要负责用户的登陆认证,和用户注册。 """ defrun_client_choice(self,socket_obj,commom): """ 获取客户端的请求,1是登陆,2是注册用户 :paramsocket_obj:socket对象 :paramcommom:ftpserver运行时所需要的数据对象 :return: """ recv_choice=socket_obj.recv(1).decode("utf-8")#获取用户选项:1是登陆,2是注册用户 ifrecv_choice=="1":#client请求登陆 returnself.login_authen(socket_obj,commom) elifrecv_choice=="2":#client请求注册账号 returnself.register_user(socket_obj,commom) else: return-1#client断开连接了 #用户登陆认证 deflogin_authen(self,socket_obj,commom): """ 客户端登陆认证 :paramsocket_obj:socket对象 :paramcommom: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) ifcheck_ret:#用户名密码正确 self.check_user_home_dir(commom,recv_userPwd[0])#检测用户家目录 returncommom.status_info["login_success"] else: returncommom.status_info["login_fail"] ... #注册用户 defregister_user(self,socket_obj,commom): """ :paramsocket_obj: :paramcommom: :return:返回是否允许注册的结果,1允许客户端注册,2拒绝客户端注册 """ whileTrue: choice_id=input("请输入回应码:1是允许注册,2是不允许注册:") ifchoice_id.isdigit()and3>int(choice_id)>0: socket_obj.send(choice_id.encode("utf-8"))#发通知告知客户端,处理结果 ifchoice_id=="1":#注册用户 returnself.client_register(socket_obj,commom) returnchoice_id else: print("您输入的信息有误,请重新输入。") ...
1.4.3客户端登录成功后,服务端会等待接收客户端发来的命令,命令的解析,执行由dataAnalysis.py模块执行,核心代码如下:
classDataAnalysis(FileOperation): """ 数据分析处理类,主要负责解析client发送过来的指令。 """ defsyntax_analysis(self,recv_data,socket_obj,commom): """ 负责解析客户端传来的数据。 :paramrecv_data:接收到的客户端用户数据 :paramsocket_obj:socket对象 :paramcommom:数据对象 :return: """ clientData=recv_data.split("") ifhasattr(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.2FTPclient.py模块下的run_ftp_client方法会打印菜单,并等待用户输入选项,执行相应功能,核心代码如下:
classClient(Login,DataAnalysis): defrun_ftp_client(self,socket_obj): """ 运行用户输入的选项:1、是登陆2、是注册账号 :return: """ whileTrue: self.login_menu()#打印系统菜单 choice_id=self.get_user_choice()#获取用户输入的选项 ifchoice_id: ifself.run_user_choice(choice_id,socket_obj): break else: print("您输入的有误") defget_user_choice(self): """ 获取用户输入的选项 :return: """ choice_id=input("请输入选项:") ifchoice_id.isdigit()and4>int(choice_id)>0orchoice_id.upper()=="Q": returnchoice_id returnFalse defrun_user_choice(self,choice_id,socket_obj): ifchoice_id=="1":#登陆系统 socket_obj.send(choice_id.encode("utf-8"))#发通知告知服务器准备登陆 ifself.run_login(socket_obj)==True:#执行登陆 returnTrue elifchoice_id=="2":#注册用户 socket_obj.send(choice_id.encode("utf-8"))#请求服务器,注册用户 self.register_user(socket_obj)#执行注册 elifchoice_id.upper()=="Q":#退出程序 socket_obj.send(choice_id.encode("utf-8"))#通知服务器,准备退出程序 socket_obj.close() print("程序正常退出") returnTrue defrun_login(self,socket_obj,): """ 运行登陆认证模块,如果登陆成功执行程序主逻辑,否则重新登陆。 :paramsocket_obj: :return: """ ifself.login_authention(socket_obj): whileTrue: send_data=input(">>>").strip("")#获取发送数据(用户执行的命令) ifsend_data.upper()=="Q":#正常退出程序 socket_obj.send(send_data.encode("utf-8"))#通知服务区断开连接 socket_obj.close() print("程序正常退出") returnTrue ifself.syntax_analysis(send_data,socket_obj):#解析用户数据并处理数据 print("异常退出") returnTrue returnFalse deflogin_menu(self): print("-"*41) print("欢迎登陆迷你FTPv1.0") print("-"*41) print("1、登陆系统") print("2、用户注册") print("Q、退出程序")
2.4.3login.py模块主要用于处理注册和登录的功能,核心代码如下:
classLogin(Commom): deflogin_authention(self,socket_obj): """ 登陆认证 :paramsocket_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])#打印状态码对应的结果 ifself.status_info[recv_status]=='登录成功': returnTrue returnFalse ... defregister_user(self,socket_obj): """ 等待服务端反馈是否允许注册用户。 :paramsocket_obj: :return: """ print("请等待服务端回应.....") recv_status=socket_obj.recv(1).decode("utf-8") ifrecv_status=="1":#服务端同意申请账号 user_pwd=self.get_regist_user_pwd()#获取注册用户名和密码 ifuser_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("服务端拒绝了您申请账号的请求,请与管理员取得联系。") returnFalse ...
2.4.4用户登录成功后,会等待接收用户输入命令,由dataAnalysis.py模块负责解析用户输入的命令,并将命令发给FTP服务器,然后接收服务器的反馈。核心代码如下:
classDataAnalysis(FileOperation): defsyntax_analysis(self,cmd,socket_obj): """ 解析用户输入的命令。 :paramcmd:用户执行的命令,如:put上传的文件 :paramsocket_obj:socket对象发送和接收数据 :return: """ cmd_split=cmd.split("")#将字符串命令分割成列表,用于验证命令是否存在 ifhasattr(self,cmd_split[0]): run_fun=getattr(self,cmd_split[0]) run_fun(cmd_split,socket_obj) else: print("无效的命令") ...
总结
以上所述是小编给大家介绍的python实现简单的FTP程序,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。