gpt4 book ai didi

node.js - Node.js 的事件 FTP 客户端

转载 作者:IT老高 更新时间:2023-10-28 23:27:41 25 4
gpt4 key购买 nike

我正在尝试编写一个针对 Filezilla 的 ftp 客户端,该客户端支持使用 node.js 的事件模式。我是 ftp 和 node.js 的新手。我想通过做这个练习我可以很好地理解 tcp socket 通信和 ftp 协议(protocol)。另外,node-ftp一个 jsftp似乎不支持主动模式,所以我认为这将是对 npm 的一个很好的(虽然很少使用)补充。

我有一些概念验证代码至少有时有效,但并非一直有效。在它工作的情况下,客户端上传一个名为 file.txt 的文件,其中包含文本“hi”。当它起作用时,我得到了这个:

220-FileZilla Server version 0.9.41 beta
220-written by Tim Kosse (Tim.Kosse@gmx.de)
220 Please visit http://sourceforge.net/projects/filezilla/

331 Password required for testuser

230 Logged on

listening
200 Port command successful

150 Opening data channel for file transfer.

server close
226 Transfer OK

half closed
closed

Process finished with exit code 0

当它不起作用时,我得到这个:

220-FileZilla Server version 0.9.41 beta
220-written by Tim Kosse (Tim.Kosse@gmx.de)
220 Please visit http://sourceforge.net/projects/filezilla/

331 Password required for testuser

230 Logged on

listening
200 Port command successful

150 Opening data channel for file transfer.

server close
half closed
closed

Process finished with exit code 0

所以,我没有得到 226,我不确定为什么会得到不一致的结果。

原谅写得不好的代码。一旦我确信我理解它应该如何工作,我将重构。:

var net = require('net'),
Socket = net.Socket;

var cmdSocket = new Socket();
cmdSocket.setEncoding('binary')

var server = undefined;
var port = 21;
var host = "localhost";
var user = "testuser";
var password = "Password1*"
var active = true;
var supplyUser = true;
var supplyPassword = true;
var supplyPassive = true;
var waitingForCommand = true;
var sendFile = true;

function onConnect(){

}

var str="";
function onData(chunk) {
console.log(chunk.toString('binary'));

//if ftp server return code = 220
if(supplyUser){
supplyUser = false;
_send('USER ' + user, function(){

});
}else if(supplyPassword){
supplyPassword = false;
_send('PASS ' + password, function(){

});
}
else if(supplyPassive){
supplyPassive = false;
if(active){
server = net.createServer(function(socket){
console.log('new connection');
socket.setKeepAlive(true, 5000);

socket.write('hi', function(){
console.log('write done');
})

socket.on('connect', function(){
console.log('socket connect');
});

socket.on('data', function(d){
console.log('socket data: ' + d);
});

socket.on('error', function(err){
console.log('socket error: ' + err);
});

socket.on('end', function() {
console.log('socket end');
});

socket.on('drain', function(){
console.log('socket drain');

});

socket.on('timeout', function(){
console.log('socket timeout');

});

socket.on('close', function(){
console.log('socket close');

});
});

server.on('error', function(e){
console.log(e);
});

server.on('close', function(){
console.log('server close');
});

server.listen(function(){
console.log('listening');

var address = server.address();
var port = address.port;
var p1 = Math.floor(port/256);
var p2 = port % 256;

_sendCommand('PORT 127,0,0,1,' + p1 + ',' + p2, function(){

});
});
}else{
_send('PASV', function(){

});
}
}
else if(sendFile){
sendFile = false;

_send('STOR file.txt', function(){

});
}
else if(waitingForCommand){
waitingForCommand = false;

cmdSocket.end(null, function(){

});

if(server)server.close(function(){});
}
}

function onEnd() {
console.log('half closed');
}

function onClose(){
console.log('closed');
}

cmdSocket.once('connect', onConnect);
cmdSocket.on('data', onData);
cmdSocket.on('end', onEnd);
cmdSocket.on('close', onClose);

cmdSocket.connect(port, host);

function _send(cmd, callback){
cmdSocket.write(cmd + '\r\n', 'binary', callback);
}

另外,server 是否合适,或者我应该以其他方式吗?

编辑:我将 server.listen 中的回调更改为使用随机端口。这已经删除了我之前得到的 425。但是,我仍然没有获得与文件传输一致的行为。

最佳答案

Active 模式 FTP 传输的流程大致如下:

  • 连接前导码(USER/PASS)
  • 为数据建立客户端本地套接字
  • 通知服务器该套接字(PORT)
  • 告诉服务器打开远程文件进行写入(STOR)
  • 从上面建立的数据套接字开始写入数据(socket.write())
  • 从客户端关闭流(socket.end())以结束文件传输
  • 告诉服务器你完成了(QUIT)
  • 清理客户端上所有打开的套接字和服务器

所以一旦你这样做了:

else if(sendFile){
sendFile = false;

_send('STOR file.txt', function(){

});
}

服务器会以 150 响应,表示它已连接到您建立的数据套接字并准备好接收数据。

在这一点上更容易推理执行的一项改进是更改您的控制流以对已解析的响应代码而不是预定义的 bool 值进行操作。

function onData(chunk) {
console.log(chunk);
var code = chunk.substring(0,3);

if(code == '220'){

代替:

function onData(chunk) {
console.log(chunk.toString('binary'));

//if ftp server return code = 220
if(supplyUser){

然后您可以添加一个用于发送数据的部分:

//ready for data
else if (code == '150') {
dataSocket.write('some wonderful file contents\r\n', function(){});
dataSocket.end(null, function(){});
}

还有一点需要清理:

//transfer finished
else if ( code == '226') {
_send('QUIT', function(){ console.log("Saying Goodbye");});
}

//session end
else if ( code == '221') {
cmdSocket.end(null, function(){});
if(!!server){ server.close(); }
}

显然,如果您发送多个文件等,事情会变得更加复杂,但这应该会让您的概念证明运行得更可靠:

var net = require('net');
Socket = net.Socket;

var cmdSocket = new Socket();
cmdSocket.setEncoding('binary')

var server = undefined;
var dataSocket = undefined;
var port = 21;
var host = "localhost";
var user = "username";
var password = "password"
var active = true;

function onConnect(){
}

var str="";
function onData(chunk) {
console.log(chunk.toString('binary'));
var code = chunk.substring(0,3);
//if ftp server return code = 220
if(code == '220'){
_send('USER ' + user, function(){
});
}else if(code == '331'){
_send('PASS ' + password, function(){
});
}
else if(code == '230'){
if(active){
server = net.createServer(function(socket){
dataSocket = socket;
console.log('new connection');
socket.setKeepAlive(true, 5000);

socket.on('connect', function(){
console.log('socket connect');
});

socket.on('data', function(d){
console.log('socket data: ' + d);
});

socket.on('error', function(err){
console.log('socket error: ' + err);
});

socket.on('end', function() {
console.log('socket end');
});

socket.on('drain', function(){
console.log('socket drain');
});

socket.on('timeout', function(){
console.log('socket timeout');
});

socket.on('close', function(){
console.log('socket close');
});
});

server.on('error', function(e){
console.log(e);
});

server.on('close', function(){
console.log('server close');
});

server.listen(function(){
console.log('listening');

var address = server.address();
var port = address.port;
var p1 = Math.floor(port/256);
var p2 = port % 256;

_send('PORT 127,0,0,1,' + p1 + ',' + p2, function(){

});
});
}else{
_send('PASV', function(){

});
}
}
else if(code == '200'){
_send('STOR file.txt', function(){

});
}
//ready for data
else if (code == '150') {
dataSocket.write('some wonderful file contents\r\n', function(){});
dataSocket.end(null, function(){});
}

//transfer finished
else if ( code == '226') {
_send('QUIT', function(){ console.log("Saying Goodbye");});
}

//session end
else if ( code == '221') {
cmdSocket.end(null, function(){});
if(!!server){ server.close(); }
}
}

function onEnd() {
console.log('half closed');
}

function onClose(){
console.log('closed');
}

cmdSocket.once('connect', onConnect);
cmdSocket.on('data', onData);
cmdSocket.on('end', onEnd);
cmdSocket.on('close', onClose);

cmdSocket.connect(port, host);

function _send(cmd, callback){
cmdSocket.write(cmd + '\r\n', 'binary', callback);
}

关于node.js - Node.js 的事件 FTP 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18603666/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com