2013-09-04 3 views
8

node.js를 사용하여 활성 모드를 지원하는 Filezilla에 대한 FTP 클라이언트를 작성하고 있습니다. 나는 ftp와 node.js에 익숙하지 않다. 나는이 훈련을 통해 tcp 소켓 통신과 ftp 프로토콜을 잘 이해할 수 있다고 생각했다. 또한 node-ftpjsftp은 활성 모드를 지원하지 않는 것 같아서 npm에 추가하는 것이 좋을 것 같습니다.Node.js 용 활성 FTP 클라이언트

적어도 가끔은 작동하지만 일부 시간은 작동하지 않는다는 개념 증명 코드가 있습니다. 클라이언트가 작동하는 경우 클라이언트는 file.txt이라는 텍스트를 'hi'라는 파일로 업로드합니다. 작동 할 때 ,이 얻을 :

작동하지 않는 경우
220-FileZilla Server version 0.9.41 beta 
220-written by Tim Kosse ([email protected]) 
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 ([email protected]) 
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입니다 리팩토링거야, 아니면 그것을 다른 방법으로해야합니까?

EDIT : 임의의 포트를 사용하도록 server.listen에서 콜백을 변경했습니다. 이것은 내가 이전에 얻었던 425 개를 제거했다. 그러나 여전히 파일 전송과 일관된 동작을 얻지 못하고 있습니다.

+0

이 파일을 확인하셨습니까? https://github.com/sergi/jsftp. – yeya

답변

1

활성 모드 FTP 전송을위한 흐름은 다음과 같이 대략 간다 :

  • 연결 프리앰블 (USER/PASS)는
  • 은 (PORT를 데이터
  • 그 소켓의 서버를 알려위한 클라이언트 로컬 소켓을 수립)
  • 서버에 쓰기 위해 원격 파일을 열어 보냅니다 (STOR)
  • (socket.write())
  • 위의 설정 데이터 소켓에서 데이터는 (QUIT)
  • 정리 열려있는 소켓과 서버를 수행하는 서버에게 파일 전송
  • 을 종료 클라이언트 측 (socket.end())에서 스트림을 닫습니다

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

    서버가로 응답합니다 : 클라이언트 그래서

당신이 수행 한 후은 사용자가 설정 한 데이터 소켓에 연결되어 있으며 데이터를 수신 할 준비가되었음을 나타냅니다.

이 시점에서 실행을 쉽게 판단하기위한 한 가지 개선 사항은 사전 정의 된 bool이 아닌 구문 분석 된 응답 코드에서 작동하도록 제어 흐름을 변경하는 것입니다.

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

    if(code == '220'){ 

대신 : 정리

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

그리고 조금 더 :

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

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

는 그런 다음 데이터를 전송하기위한 섹션을 추가 할 수 있습니다

//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); 
}