前面描述的基于TCP/UDP协议的网络程序开发,主要是针对传输层协议的底层代码实现 在实际操作过程中,更多的情况是直接操作应用层的数据协议的网络程序开发,如文件传输协议FTP,邮件协议SMTP等等
这一部分针对应用层的协议下网络程序的开发做一个深入的处理
FTP:File Transfer Protocal 文件传输协议 工作在应用层的协议,由Jon Postel和Joyce Reynolds开发并记录在RPC959号文档中 FTP协议主要用于匿名下载文件或者在两台计算机之间进行文件的传输工作!
FTP协议底层采用的是TCP协议完成的网络数据传输,为了方便两台计算机上的文件正确的进行交互,FTP协议封装了两个套接字完成文件操作,第一个工作在21端口的套接字专门用于传输命令控制指令,第二个工作在20端口的套接字专门传输具体文件数据
FTP客户端-服务器连接处理方式
FTP网络程序的开发,我们不需要关注服务端的程序,服务端的软件程序开发和文件管理操作可以有大量的现成的工具去操作完成,而FTP如果作为应用软件的一部分功能,客户端程序的操作才是应用软件中最常规的操作
PYTHON中提供了对FTP操作友好的支持,通过内建标准模块ftplib提供
针对FTP客户端的逻辑流程,进行如下步骤分析:
客户端——连接到服务器 客户端——账号+密码登录服务器 发出服务请求——控制指令、数据传输指令——处理响应数据 客户端退出
伪代码操作如下
from ftplib import FTP
ftp = FTP(“ftp.server.com”)
[ftp.login(‘account](ftp://ftp.login('account)’, ‘password’)
# 数据交互
ftp.quit()
属性/方法 | 描述 |
---|---|
login(user=’anonymous’, passwd=’’, acct=’’) | 登录FTP服务器 |
pwd() | 查看当前路径 |
cwd(path) | 切换路径到指定的path路径 |
dir(path [,…[,cb]]) | 显示path路径中文件的内容 |
nlst([path [,….]]) | 类似dir(),返回文件名称列表 |
retrlines(cmd [, cb]) | 给定ftp命令,下载文本文件;回调函数cb用于处理每一行文本 |
retrbinary(cmd, cb [, bs=8192 [, ra]]) | 给定ftp命令,下载二进制文件;回调函数cb处理每次读取的8k数据 |
storlines(cmd, f) | 给定ftp命令,上传文本文件f |
storbinary(cmd, f [, bs=8192]) | 给定ftp命令,上传二进制文件f |
rename(old, name) | 重命名old文件为new |
delete(path) | 删除path指定的某个文件 |
mkd(directory) | 创建一个目录directory |
rmd(directory) | 删除指定的目录directory |
quit() | 关闭连接,退出FTP |
搭建好我们的服务器环境,指定连接的FTP服务器信息、文件路径信息
# 引入需要的模块
import ftplib, socket
# 定义FTP主机信息
HOST = '192.168.1.108'
DIRN = '/home/damu/ftpwork/'
FILE = 'my_demo.tar.gz'
class FtpClient:
'''自定义FTP客户端类型'''
def __init__(self, host, username, password):
'''
初始化方法
:param host:目标主机
:param directory:目标主机目录
:param files:要下载的文件
:param username:登录账号
:param password:登录密码
'''
self.host = host
self.username = username
self.password = password
def ftp_dowload(self, directory, file):
'''下载文件主要方法'''
self.directory = directory
self.file = file
self.__ftp_connect()
self.__ftp_login()
self.__ftp_cwd()
self.__ftp_download()
self.__ftp_quit()
def __ftp_connect(self):
'''连接服务器的方法'''
try:
self.ftp = ftplib.FTP(self.host)
except (socket.error, socket.gaierror) as e:
print("目标主机不可访问:", self.host)
else:
print("主机连接成功", self.host)
def __ftp_login(self):
'''登录FTP服务器的方法'''
try:
self.ftp.login()
except ftplib.error_perm:
print("目标主机不能匿名登录,使用账号密码登录")
try:
self.ftp.login(user=self.username, passwd=self.password)
except:
print("账号或者密码有误")
else:
print("登录成功")
def __ftp_cwd(self):
'''修改工作目录的方法'''
try:
self.ftp.cwd(self.directory)
except ftplib.error_perm as e:
print("路径修改失败,没有权限", self.directory)
else:
print("路径修改完成")
def __ftp_download(self):
'''下载文件核心方法'''
try:
self.ftp.retrbinary('RETR {}'.format(self.file), open(self.file, 'wb').write)
except ftplib.error_perm as e:
print("文件下载失败...")
else:
print("文件下载完成")
def __ftp_quit(self):
'''退出FTP客户端'''
self.ftp.quit()
print('程序退出...')
if __name__ == "__main__":
# 创建FTP客户端对象
ftp = FtpClient(HOST, 'damu', '123456')
# 下载指定路径下的文件
ftp.ftp_dowload(DIRN, FILE)