基于ftplib的交互式ftp客户端实现

基于ftplib的交互式ftp客户端实现

1.简介

FTP(File Transfer
Protocol)是较为常用的一种协议,用于Internet上的控制文件实现双向传输,为了方便文件的上载、下载等操作,python默认提供了ftplib模块用于ftp客户端的开发实现,本文对ftplib做了二次封装,并自定义了一个控制台支持简单的交互命令,实现服务器连接、登录、目录读取、目前切换、上载、下载,关闭连接等操作。

2.Ftplib

Ftplib是一个ftp客户端操作实现封装,实例化的类名为FTP,本文涉及的FTP类主要包括如下的函数:

方法 说明
Connect 连接指定IP的FTP服务器,
login 以指定账号和密码登录FTP服务器
dir 浏览当前目录下的文件与下一级目录名称
storbinary 上传文件
retrbinary 下载文件
Quit 与服务器断开连接

3.设计实现

整个代码部分主要包括CustomConsole自定义值班台类和FTPClient客户端两个类,CustomConsole为主控,FTPClient为ftp访问的操作实现。

本程序依赖的模块主要包括

import ftplib
import os,socket
import threading

程序的main函数入口书写方式如下

if __name__ == _main_:
c = CustomConsole()
c.start()
c.join()

3.1 CustomConsole类

3.1.1 设计说明

CustomConsole为线程类,持续等待用户输入命令,支持的命令包括conn、login、ls、cd、get、put、quit等命令

  • conn是连接ftp服务器命令,之后需要输入希望连接的ftp服务器的ip

  • login是登录命令,之后需要输入用户名和密码用于登录

  • ls是浏览当前目录下的文件与下一级目录名称的命令

  • cd是切换目录命令,需要输入需要切换的目录名称,目前是实现较简单,只能网下级切换,不支持父目录切换

  • get是下载文件命令,之后需要指定ftp服务器上的待下载文件名称

  • put是上载文件命令,之后是本地需要上载的文件的绝对路径。

  • quit是断开与服务器连接并推出程序的命令。

    基于ftplib的交互式ftp客户端实现

3.1.2 代码实现

  1. class CustomConsole(threading.Thread):
    def __init__(self):
    self.cmd =
    threading.Thread.init(self)

    def run(self):

    print(‘*********Command Usaged************’)
    print(‘***conn :Connect to ftp server*****’)
    print(‘***login:Login ftp server**********’)
    print(‘***ls:List files and directories***’)
    print(‘***cd:Change directory*************’)
    print(‘***put:Upload File to ftp server***’)
    print(‘***get:Download from ftp server****’)
    print(‘***quit:disconnect with ftp server*’)

    while(True):
    cmd = input(‘Please input command:’)
    if(cmd == ‘quit’):
    self.ftp.Disconnect()
    break

    if (cmd == ‘conn’):
    serverip = input(‘Please input server ip:’)
    self.ftp = FTPClient()
    self.ftp.Connect(serverip)

    if (cmd == ‘login’):
    username = input(‘Please input username:’)
    password = input(‘Please input password:’)
    self.ftp.Login(username,password)

    if(cmd == ‘ls’):
    files = self.ftp.ListFile()

    if (cmd == ‘cd’):
    files = self.ftp.ListFile()
    subdir = input(‘Please input subdir:’)
    self.ftp.EnterDir(subdir)

    if (cmd == ‘get’):
    filename = input(‘Please input filename:’)
    self.ftp.DownloadFile(filename)

    if (cmd == ‘put’):
    filename = input(‘Please input filename:’)
    self.ftp.UPLoadFile(filename)

3.2 FTPClient类

3.2.1 设计说明

FTPClient主要对ftplib进行了封装,实现了部分功能,重点是节目的上载、下载。

3.2.2代码实现

class FTPClient:
def __init__(self):
self.curDir = ‘/’
self.cursize = 0

def ListFile(self):
self.ftp.dir(self.curDir)
pass

def Connect(self,host):
try:
self.ftp = ftplib.FTP(host)
except (socket.error, socket.gaierror) as e:
print(‘Er#ror:cannot reach%s’ % (host))
return

print(‘Conneted host:’, host)

def Login(self,user,password):
try:
self.ftp.login(user, password)
except ftplib.error_perm:
print(‘Error: cannot login anonymously’)
self.ftp.quit()
return
print(‘logined as ‘, user)
self.ListFile()

def EnterDir(self,dirname):
try:
#change dir
self.curDir = self.curDir+dirname
self.ftp.cwd(self.curDir)
except ftplib.error_perm:
print(‘Error: cannot CD into %s’ % (self.curDir))
self.ftp.quit()
return
print(‘Changed into %s folder’ % (self.curDir))

def DownloadFile(self, filename):
try:
#local file
self.cursize = 0
filehandle = open(filename, ‘wb’)

#remote file
self.totalsize = self.ftp.size(filename)

#define callback
chunkwrite = lambda chunk: self.ChunkWrite(chunk, filehandle)

self.ftp.retrbinary(‘RETR %s’ % (filename), chunkwrite)

except ftplib.error_perm:

print(‘Error: cannot read file “%s”’ % (filename))
os.unlink(filename)

filehandle.close()
print(‘….Download “%s” to Local’ % (filename))

def UPLoadFile(self, filename):
try:
#local
self.cursize = 0
filehandle = open(filename, ‘rb’)
self.totalsize = os.path.getsize(filename)

#remote
pathFormat = filename.split(‘\\’)
remotefile = pathFormat[len(pathFormat) - 1]

self.ftp.storbinary(‘STOR %s’ % (remotefile),filehandle,
1024,self.ChunkRead)

except ftplib.error_perm:

print(‘Error: cannot read file “%s”’ % (remotefile))
os.unlink(remotefile)

filehandle.close()
print(‘….UpLoad “%s” to FTP’ % (filename))

def ChunkWrite(self,chunk, filehandle):

# calc process
self.cursize = self.cursize + len(chunk)
process = self.cursize*100 / self.totalsize
print(str(round(process, 3))+‘%’,end = ‘\r’)

#save data to local
filehandle.write(chunk)

def ChunkRead(self, chunk):

#calc process
self.cursize = self.cursize + len(chunk)
process = self.cursize * 100 / self.totalsize
print(str(round(process, 3)) + ‘%’, end=‘\r’)

def Disconnect(self):
try:
self.ftp.quit()
except (socket.error, socket.gaierror) as e:
print(e)

4.存在的问题

整个功能模块实现较为简单,并且相关的验证机制也不健全,在命令、参数输入错误的情况下会出现异常,但是就实现思路来说基本上还是比较明确的。另外在windows上采用二进制方式上载本地exe和jpeg文件在用open函数打开的时候会有一些问题,python的官方文档对此进行了说明。具体原文地址为:https://docs.python.org/2/tutorial/inputoutput.html.

基于ftplib的交互式ftp客户端实现