FTP图片文件传输性能的提升与封装

一、背景

业务中对接第三方平台、或过网闸将图片向内网摆渡时,经常需要把大量图片(业务数据)上传FTP服务器,以往的FTP上传方式,是先把图片下载存储到本地,然后再把本地图片上传至FTP,图片会在本地磁盘进行中转,FTP下载文件时也是如此。因为FTP上传文件的接口都是需要以文件在本地磁盘的路径作为输入的,这样通过磁盘中转文件,会使传输速度大打折扣。此外FTP传输图片文件的性能一直不高,之前也没有人在这方面做过深入探索。

   基于以上原因,在项目实践中对FTP的性能和传输方法做了深入研究,解决掉需要磁盘中转文件的缺陷,提升传输性能,并对FTP传输性能做了统计测试,找出最佳上传方案。

二、以往FTP上传方式

 

      

   所采用的方法: CFtpConnection::PutFile/FtpPutFilewindows MFC中提供的FTP网络通讯类方法

aBOOL CFtpConnection::PutFile(LPCTSTR pstrLocalFile,LPCTSTR pstrRemoteFile,DWORD dwFlags =FTP_TRANSFER_TYPE_BINARY,DWORD_PTR dwContext = 1);

 b、BOOLAPI FtpPutFile(__in HINTERNET hConnect,__in LPCSTR lpszLocalFile,__in LPCSTR lpszNewRemoteFile,__in DWORD dwFlags,__in_opt DWORD_PTR dwContext);

   可以看到红色参数,都是需要输入一个本地的文件路径,才能上传,而无法直接将内存中的数据输入,所以以往的设计才迫不得已使用了磁盘中转。

 

三、改进后的FTP上传方式

  

 

   改进后,图片不再经过磁盘中转,而是在FTP会话上创建CinternetFile文件操作(由MFC提供,允许对使用Internet协议的远端系统文件的访问,派生于CFile类——MFC文件操作的基类),通过文件读写方法WriteClose,将内存中的图片数据写入FTP

   方法virtual void Write(const void*lpBuf,UINT nCount)的第一个参数类型为void*,能够直接输入图片在内存中的地址,从而使内存中的图片数据不需经过磁盘中转,就能写到FTP上。

   源码:

    CInternetFile*intePicFile =m_pFtpConnection->OpenFile(chPath,GENERIC_WRITE);// pFtpConnectionftp会话类

if(NULL!=intePicFile)

{

intePicFile->Write(pData,Len);

intePicFile->Close();

 

}

          

    同理,通过Read方法下载文件源码如下:(方法virtual UINT Read(void*lpBuf,UINT nCount)的第一个参数输入预分配的内存地址,使图片从ftp上读取到内存中。)

       CInternetFile*intePicFile =m_pFtpConnection->OpenFile(pFtpFilePath.c_str(),GENERIC_READ);

if(NULL!=intePicFile)

{

Len =intePicFile->Read(pData,MAXPICLEN);

intePicFile->Close();

 

}

    如此就解决了FTP下载上传图片需通过磁盘中转的问题,不仅提升了传输速度,并且精简了代码逻辑。

 

四、FTP类常用方法的封装

解决上述问题后,为了便于日后的开发,这里重新封装了FTP常用方法,提高自动化操作,包括如下内容(源码已包含在demo中,类CFtpOper):

a. 构造函数:能初始化FTP连接,并在析构中自动断开连接,传输期间若发生异常断开,会自动重连,无需额外干预。

CFtpOper::CFtpOper(string strFtpIP,int nFtpPort,string strUserName,string strPassword);

参数1:strFtpIP, FTP服务器的IP地址

参数2:nFtpPort FTP服务器的端口号

参数3:strUserName FTP服务器的用户名

参数4:strPassword FTP服务器的密码

返回值:构造函数无返回值

 

b. 文件上传函数:采用优化后的上传方法,图片无需通过磁盘中转。支持多级目录创建,通过结构体UpPath将各级目录名称、目录总数输入,该方法会自动在FTP上检索对应目录,若无此目录,或目录不完整,会自动创建,创建完成后,会将要上传的文件传输到此目录下面。最多支持10级目录(可通过修改宏定义扩展级数上限),

int  UpLoadImage(const char*pData,int Len,const char*pFtpPicName,UpPath uPath);

参数1:pData待上传的图片数据指针

参数2:Len待上传的图片数据长度

参数3:pFtpPicName图片数据在到FTP上的文件名,含后缀,如xx.jpg。

参数4:uPath,存储目录信息的结构体,uPath. m_nLev 为目录级数(总共几级目录),uPath. m_strPath[i] 为第i级目录的名称,i从0开始,支持10级目录。

返回值: 1 成功;0 连接不可用; 2 失败

c. 文件下载函数:采用优化后的上传方法,图片无需通过磁盘中转。

下载前需修改代码中MAXPICLEN的值为预分配内存块pData的长度,该长度要大于需读取的文件大小。

int  DownLoadImage(char*pData,int&Len,const string pFtpFilePath);

参数1:pData 预分配的内存块,下载的图片将存储到此内存块中

参数2:Len 将返回下载图片的实际长度。

参数3:文件在FTP上的完整路径,如/05/photo/[20160422]/1143/aaa.jpg

返回值:1 成功;0 连接不可用; 2 失败

 

d. 多级目录创建函数:通过结构体UpPath将各级目录名称、目录总数输入,该方法会自动在FTP上检索改目录,目录若不存在或不完整,将创建对应目录,最多支持10级目录(可通过修改宏定义扩展级数上限)

bool CreateDir(UpPath UploadPath);

参数: UploadPath, 同 UpLoadImage方法中的参数4。

返回值:true 成功;false 失败

 

c.  文件的查找、删除:可通过已有的CFtpConnection::Remove方法和CFtpFileFind类实现,此处不再扩展,demo中也做了示例程序以供参考。

 

五、FTP上传性能测试统计

实践中发现,FTP单会话上传数据速度很慢(已确定FTP上没有对传输速率做限制),270KB的图片文件,一秒钟只能上传1.5-2张,且无法通过在一个会话中启用多线程来加快传输,反而会因此产生异常崩溃,这种方法是不可行的。只能通过开启多个FTP会话来提升传输速度,每个会话使用一个线程来实现,即一个线程对应一个会话。

但是开多少个线程(会话)能使传输速度达到最优呢,理论上线程并非越多越好,随着线程数的上涨,线程调度上耗费的时间也会上涨,以及其他软件和硬件因素限制,反而会使性能下降,或者速率随着线程数的增长而提高甚微。

这个数值对实际应用有很大参考价值的,所以此处做了测试统计。

a. 测试程序:基于优化封装后的代码实现。

关键代码如下(详见demo程序):

       

b.测试过程:反复上传一张270KB大小的图片到FTP上,当然名称保证各不相同,测试不同线程数量下图片的传输速度。

c.硬件环境:

客户端主机:台式机,cpu E3-1230 v3  3.3GHZ八核,硬盘7200

FTP服务器主机:笔记本,cpu i5  2.7GHZ  四核,硬盘7200

 

e. 测试统计结果基于以下事实:测试中网络带宽,磁盘写入速度远未达到瓶颈值,硬件环境在测试过程中始终保持一致。

程序运行截图:

 

      结果统计:

线程数(每个线程开启一个单独的ftp会话)

1

5

10

15

20

25

30

35

40

50

20秒传输数量

48

231

411

488

507

535

542

544

547

559

平均每秒传输数量

2.4

11.55

20.55

24.4

25.35

26.75

27.1

27.2

27.35

27.95

 

生成图表如下:

 

          

 

 

比对图表曲线可以得出结论:(因硬件资源条件有限,测试结果仅供参考)

随着线程数量(此处等同FTP会话数量)的增加,图片传输数量呈对数曲线增长。建议选择15个左右会话线程数,以获得最佳传输速度——270k大小图片,25/每秒。30个会话线程基本已达到最高传输速度。

   其中限制传输性能的因素包括:

1CPU:限制多会话的处理速度。

2、硬盘:限制文件的写入速度。

3、网络带宽:限制文件网络传输速度。


Demo 附件:http://pan.baidu.com/s/1jImVyaa

含测试数据记录

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值