问题描述
|
我有一个ColdFusion应用程序,用于在开发服务器和生产服务器之间传输文件。实际发送文件的代码如下:
ftp = new Ftp();
ftp.setUsername(username);
ftp.setPassword(password);
ftp.setServer(server);
ftp.setTimeout(1800);
ftp.setConnection(\'dev\');
ftp.open();
ftp.putFile(transferMode=\"binary\",localFile=localpath,remoteFile=remotepath);
ftp.close(connection=\'dev\');
使用上述代码发送文件时,我的输出速度接近100KB / s(通过接收服务器上的FileZilla监视)。如果使用Windows命令行FTP工具发送完全相同的文件,则速度将超过1000KB / s。
我创建了一个全新的文件,只带了上面的代码,并且对传输速度没有任何影响,因此我知道它与原始应用程序中的周围代码无关。
那么,是什么原因导致这些低速行驶呢?
编辑:所有测试都已完成,将文件从生产服务器传输到开发服务器。我也尝试使用<cfftp>
标记而不是cfscript,结果也相同。
编辑#2:我最终使用cfexecute
,代码如下:
从我的FTP脚本中:
public function sendFiles(required string localpath,required string remotepath) {
this.writeFtpInstructions(localpath);
exe = \"C:\\Windows\\system32\\ftp.exe\";
params = \"-s:\" & request.localapproot & \"/\" & \"upload.txt\";
outputfile = request.localapproot & \'/ftp.log\';
timeout = 120;
Request.cliExec(exe,params,outputfile,timeout);
}
public function writeFtpInstructions(required string localpath) {
instructions = request.localapproot & \"/\" & \"upload.txt\";
crlf = chr(13) & chr(10);
data = \"\";
data &= \"open \" & this.server & crlf;
data &= this.username & crlf;
data &= this.password & crlf;
data &= \"cd \" & request.remoteapproot & crlf;
data &= \"put \" & localpath & crlf;
data &= \"quit\";
FileWrite(instructions,data);
}
cliExec()
函数(由于在cfscript中没有cfexecute
等效项,因此必须创建包装器):
<cffunction name=\"cliExec\">
<cfargument name=\"name\">
<cfargument name=\"arguments\">
<cfargument name=\"outputfile\">
<cfargument name=\"timeout\">
<cfexecute
name=\"#name#\"
arguments=\"#arguments#\"
outputFile=\"#outputfile#\"
timeout=\"#timeout#\" />
</cffunction>
解决方法
我一直在寻找,但对于为什么它变慢没有答案。但是,从理论上讲,您应该能够通过Windows命令行使用cfexecute来执行此操作。您甚至可以创建一个批处理文件,然后在一个调用中进行处理。
,以我在CF9上使用cfftp的经验,不可能传输更大的文件。如果在FTP服务器端查看活动的传输,您会注意到传输以最快的速度开始,但是随着越来越多的数据传输,速度不断下降。传输了100 MB之后,还原开始变得非常剧烈,直到最终达到单位数爬取。最终,传输超时并失败。我试图使用330 MB的文件,但发现无法使用cfftp进行传输。我无法使用标准Windows ftp.exe来选择cfexecute,因为它似乎不支持SFTP。
我最终找到了一个通过Coldfusion使用的外部Java类,并决定使用JSch(http://www.jcraft.com/jsch/)。具有讽刺意味的是,CF9似乎将此类用于CFFTP(jsch-0.1.41m.jar),但使用此最新下载版本(jsch-0.1.45.jar)的结果却大不相同。
这是我为概念证明而编写的代码:
<cfscript>
stAppPrefs = {
stISOFtp = {
server = \'sftp.server.com\',port = \'22\',username = \'youser\',password = \'pa$$w0rd\'
}
};
/* Side-Load JSch Java Class (http://www.jcraft.com/jsch/) */
try {
// Load Class Using Mark Mandel\'s JavaLoader (http://www.compoundtheory.com/?action=javaloader.index)
/*
Add Mark\'s LoaderClass To The ColdFusion Class Path Under CF Admin:
Java and JVM : ColdFusion Class Path : C:\\inetpub\\wwwroot\\javaloader\\lib\\classloader-20100119110136.jar
Then Restart The Coldfusion Application Service
*/
loader = CreateObject(\"component\",\"javaloader.JavaLoader\").init([expandPath(\"jsch-0.1.45.jar\")]);
// Initiate Instance
jsch = loader.create(\"com.jcraft.jsch.JSch\").init();
}
catch(any excpt) {
WriteOutput(\"Error loading \"\"jsch-0.1.45.jar\"\" java class: \" & excpt.Message & \"<br>\");
abort;
}
/* SFTP Session & Channel */
try {
// Create SFTP Session
session = jsch.getSession(stAppPrefs.stISOFtp.username,stAppPrefs.stISOFtp.server,stAppPrefs.stISOFtp.port);
// Turn Off & Use Username/Password
session.setConfig(\"StrictHostKeyChecking\",\"no\");
session.setPassword(stAppPrefs.stISOFtp.password);
session.connect();
// Create Channel To Transfer File(s) On
channel = session.openChannel(\"sftp\");
channel.connect();
}
catch(any excpt) {
WriteOutput(\"Error connecting to FTP server: \" & excpt.Message & \"<br>\");
abort;
}
// Returns Array Of Java Objects,One For Each Zip Compressed File Listed In Root DIR
// WriteDump(channel.ls(\'*.zip\'));
// Get First Zip File Listed For Transfer From SFTP To CF Server
serverFile = channel.ls(\'*.zip\')[1].getFilename();
/* Debug */
startTime = Now();
WriteOutput(\"Transfer Started: \" & TimeFormat(startTime,\'hh:mm:ss\') & \"<br>\");
/* // Debug */
/* Transfer File From SFTP Server To CF Server */
try {
// Create File On Server To Write Byte Stream To
transferFile = CreateObject(\"java\",\"java.io.File\").init(expandPath(serverFile));
channel.get(serverFile,CreateObject(\"java\",\"java.io.FileOutputStream\").init(transferFile));
// Close The File Output Stream
transferFile = \'\';
}
catch(any excpt) {
WriteOutput(\"Error transfering file \"\"\" & expandPath(serverFile) & \"\"\": \" & excpt.Message & \"<br>\");
abort;
}
/* Debug */
finishTime = Now();
WriteOutput(\"Transfer Finished: \" & TimeFormat(finishTime,\'hh:mm:ss\') & \"<br>\");
expiredTime = (finishTime - startTime);
WriteOutput(\"Duration: \" & TimeFormat(expiredTime,\'HH:MM:SS\') & \"<br>\");
WriteOutput(\"File Size: \" & NumberFormat(Evaluate(GetFileInfo(ExpandPath(serverFile)).size / 1024),\'_,___._\') & \" KB<br>\");
WriteOutput(\"Transfer Rate: \" & NumberFormat(Evaluate(Evaluate(GetFileInfo(ExpandPath(serverFile)).size / 1024) / Evaluate(((TimeFormat(expiredTime,\'H\') * 60 * 60) + (TimeFormat(expiredTime,\'M\') * 60) + TimeFormat(expiredTime,\'S\')))),___._\') & \" KB/Sec <br>\");
/* // Debug */
channel.disconnect();
session.disconnect();
</cfscript>
结果:
Transfer Started: 09:37:57
Transfer Finished: 09:42:01
Duration: 00:04:04
File Size: 331,770.8 KB
Transfer Rate: 1,359.7 KB/Sec
实现的传输速度与使用FileZilla FTP Client和手动下载获得的速度相当。我发现此方法对于cfftp的不足是一种可行的解决方案。