教你写一个ftp协议(文件传输协议)

您所在的位置:网站首页 ftp文件传输基于哪种协议 教你写一个ftp协议(文件传输协议)

教你写一个ftp协议(文件传输协议)

#教你写一个ftp协议(文件传输协议)| 来源: 网络整理| 查看: 265

本文链接:https://blog.csdn.net/weixin_42898819/article/details/81502058

 

FTP协议的C语言实现

https://blog.csdn.net/Zhu_Zhu_2009/article/details/82147473

 

一、FTP协议简介

FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件。在FTP的使用当中,用户经常遇到两个概念:”下载”(Download)和”上传”(Upload)。”下载”文件就是从远程主机拷贝文件至自己的计算机上;”上传”文件就是将文件从自己的计算机中拷贝至远程主机上。用Internet语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。

二、FTP Server的用户分类及权限归属

在考虑FTP服务器安全性工作的时候,第一步要考虑的就是谁可以访问FTP服务器。以下有三种客户可以访问FTP Server: 一类是Real帐户。这类用户是指在FTP服务上拥有帐号。当这类用户登录FTP服务器的时候,其默认的主目录就是其帐号命名的目录。但是,其还可以变更到其他目录中去。如系统的主目录等等。 第二类帐户是Guest用户。在FTP服务器中,我们往往会给不同的部门或者某个特定的用户设置一个帐户。但是,这个账户有个特点,就是其只能够访问自己的主目录。服务器通过这种方式来保障FTP服务上其他文件的安全性。拥有这类用户的帐户,只能够访问其主目录下的目录,而不得访问主目录以外的文件。 第三类帐户是Anonymous(匿名)用户,这也是我们通常所说的匿名访问。这类用户是指在FTP服务器中没有指定帐户,但是其仍然可以进行匿名访问某些公开的资源。

三、写一个简单的ftp协议

下面我们写一个简单的匿名用户可以访问的ftp协议,前两种账户的功能我会在后续博客中逐一完善。在写一个ftp协议之前你需要了解以下几点:

ftp作为一个服务器端和客户端相互传输文件的协议,我们在写的时候就要分别写服务器端程序server_ftp.py和客户端程序client_ftp.py。

我们要实现多个客户端可以同时访问服务器端,所以要通过多线程的方式来使得多个客户端访问,在这里我们服务器端通过socketserver来写。

最后通过将一个txt文件通过客户端上传到服务器端来验证所写代码的准确性。在下面的代码中我会详细备注每条语句完成的功能。

客户端代码: import socket #导入socket模块,用来实现socket通信 import os #导入os模块,主要用来调用系统命令,获得路径 import json #导入json模块,将字符串形式的json数据转化为字典,也可以将Python中的字典数据转化为字符串形式的json数据 class FtpClient(object ): def __init__(self): self.client=socket.socket() #声明客户端利用socket通信 def help(self): #写一个打印一些指令的帮助信息函数, msg=''' ls pwd cd../.. get filename put filename ''' def connect(self,ip,port): #定义一个连接服务器函数,调用client.connect()方法,连接服务器端 self.client.connect((ip,port)) def interactive(self): #定义一个与服务器交互的函数 while True: cmd=input('>>').strip() #用户在客户端输入指令,strip()去掉用户输入指令的空格和换行符 if len(cmd)==0:continue cmd_str=cmd.split()[0] #拆分指令的第一个字符赋给cmd_str,永远都是指令help() #反射 if hasattr(self,'cmd_%s'%cmd_str ): #hasattr() 函数用于判断对象是否包含对应的属性 func=getattr(self,'cmd_%s'%cmd_str) # 函数用于返回一个对象属性值 func(cmd) #取到help中的指令 ls,pwd,get ,put。然后传入后面的 filename,这样后面的函数名字就叫做cmd_put cmd_get... else: self.help() def cmd_put(self,*args): #写一个通过客户端上传文件的函数,*args为了接收更多数据 #上传一个文件 cmd_split= args[0].split() #将传入的第一个参数赋值给cmd_split,变为列表 if len(cmd_split)>1: #这里大于1 因为最后我们输入put filename.txt进行验证,由于存在put所以大于1 filename=cmd_split[1] if os.path.isfile(filename): #判断要上传的文件是否存在 filesize=os.stat(filename).st_size #获取文件大小 #发送文件大小,文件名,进行的操作(这里我们默认put上传数据)给服务器,所以写成json字典形式,需要扩展直接在这加 msg_dic={ 'action':'put', 'filename':filename, 'size':filesize } self.client.send(json.dumps(msg_dic).encode('utf-8'))#发给服务器端,json.dumps()字典转换为json格式 server_response=self.client.recv(1024) #等待服务器响应 f=open(filename ,'rb') #打开文件,发送给服务器 for i in f: self.client.send(i) else: print('文件传输完毕') f.close() else: print(filename ,'is not exist') def cmd_get(self): #定义一个从服务器下载文件函数,这里和上面大同小异,先不写 pass ftp=FtpClient() #实例化 ftp.connect('localhost',9999) #连接服务器端口 ftp.interactive() #调用和服务器交互函数   服务器端代码 import socketserver #利用socketserver来写 import json ,os #自己写一个请求处理类,继承BaseRequestHandler class MyTCPHandler(socketserver.BaseRequestHandler): def put(self,*args): #接收客户端文件 cmd_dic=args[0] filename=cmd_dic['filename'] #获取文件名 filesize=cmd_dic['size'] #获取文件大小 if os.path.isfile(filename ): #如果已经存在上传文件,新建一个文件 f=open(filename+'.new','wb') else: #如果不存在 给客户端响应上传 f=open(filename ,'wb') self.request.send(b'200 ok') #响应客户端 received_size=0 while received_size < filesize : #循环接收文件 data=self.request.recv(1024) f.write(data) received_size +=len(data) else: print('file[%s] has overload..'%filename ) #文件传输完成 #跟客户端的交互在handle中 def handle(self): while True : try: self.data=self.request.recv(1024).strip() #format格式化 打印客户端ip地址 print('{}wrote:'.format(self.client_address[0])) print(self.data) cmd_dic=json.loads(self.data.decode())#json字符串转为字典 action=cmd_dic['action'] #获取进行的操作 这里默认是put #反射 if hasattr(self,action ): #判断put操作是否存在 func=getattr(self ,action ) func(cmd_dic) except ConnectionResetError as e: print(e) break if __name__ =='__main__': HOST,POST='localhost',9999 # 实例化TCPServer server=socketserver.ThreadingTCPServer((HOST,POST),MyTCPHandler ) #ThreadingTCPServer:多线程,多个客户端可以请求 #这样此服务器就可以让多个客户端连接 #处理多个请求 server.serve_forever() 运行结果

我们把需要测试的文件lianxiren.txt放在客户端目录下,先运行服务器,在运行客户端,并且输入put lianxiren.txt 可以发现文件传输完成,在服务器的文件夹中会发现传输过去的txt文件。这里写图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3