2013-09-04 17 views
8

के लिए सक्रिय एफ़टीपी क्लाइंट मैं फाइलजीला के खिलाफ एक FTP क्लाइंट लिखने पर अपना हाथ कोशिश कर रहा हूं जो node.js. का उपयोग कर सक्रिय मोड का समर्थन करता है। मैं ftp और node.js. के लिए नया हूँ मैंने सोचा कि मैं इस अभ्यास करके टीसीपी सॉकेट संचार और एफटीपी प्रोटोकॉल की अच्छी समझ प्राप्त कर सकता हूं। इसके अलावा, node-ftp एक jsftp सक्रिय मोड का समर्थन नहीं करता है, इसलिए मुझे लगता है कि यह एक अच्छा (हालांकि शायद ही कभी इस्तेमाल किया जाएगा) एनपीएम के अलावा होगा।Node.js

मुझे अवधारणा कोड का कुछ सबूत मिला है जो कम से कम कभी-कभी काम करता है, लेकिन हर समय नहीं। जिस मामले में यह काम करता है, क्लाइंट 'हाय' टेक्स्ट के साथ file.txt नामक फ़ाइल अपलोड करता है। जब यह काम करता है, मैं इस मिल:

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 नहीं मिल रहा है, और मुझे यकीन है कि नहीं कर रहा हूँ मुझे असंगत परिणाम क्यों मिल रहे हैं।

खराब लिखित कोड को क्षमा करें। मैं refactor जाएगा एक बार मुझे विश्वास है मैं समझता हूँ कि यह कैसे .:

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 को पहले हटा दिया था। हालांकि, मुझे अभी भी फ़ाइल स्थानांतरण के साथ लगातार व्यवहार नहीं मिल रहा है।

+0

क्या आपने इसे देखा था? https://github.com/sergi/jsftp। – yeya

उत्तर

1

सक्रिय मोड एफ़टीपी हस्तांतरण के लिए प्रवाह इस तरह मोटे तौर पर चला जाता है:

  • कनेक्शन प्रस्तावना (USER/PASS)
  • डेटा
  • कि सॉकेट के सर्वर को सूचित करने के लिए एक ग्राहक स्थानीय सॉकेट की स्थापना (PORT)
  • सर्वर को लिखने के लिए दूरस्थ फ़ाइल खोलने के लिए कहें (STOR)
  • लिखना प्रारंभ करना डेटा सॉकेट ऊपर (socket.write())
  • स्थापित से डेटा फ़ाइल स्थानांतरण
  • समाप्त करने के लिए ग्राहक के पक्ष (socket.end()) से धारा बंद सर्वर आप (QUIT)
  • स्वच्छ ऊपर किसी भी खुले सॉकेट और सर्वर से किया जाता है को बताएँ ग्राहक

तो पर एक बार आपके द्वारा किए गए इस:

else if(sendFile){ 
    sendFile = false; 

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

    }); 
} 

सर्वर एकसाथ जवाब देंगेकह रहा है कि यह आपके द्वारा स्थापित डेटा सॉकेट से जुड़ा हुआ है और डेटा प्राप्त करने के लिए तैयार है।

इस बिंदु पर निष्पादन के बारे में कारण बनाना आसान बनाने के लिए एक सुधार आपके नियंत्रण प्रवाह को पूर्व परिभाषित बूल के बजाय एक पार्स किए गए प्रतिक्रिया कोड पर संचालित करने के लिए बदलना होगा।

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