js ftpclient linux server,Node.JS用Socket实现FTP Server服务器和Client客户端

通信过程

FTP协议其实就是主机和服务通过Socket进行固定格式的通信过程,当某客户端连接到FTP 服务器后,客户端发送指令: [参数]

服务会按以下格式返回: [参数或说明]

例如以下是FileZilla FTP客户端与服务器通信的过程:

"命令"为客户端通过socket发送的消息,“响应”为服务器端的返回响应: 220-FileZilla Server version 0.9.43 beta

响应: 220-written by Tim Kosse (tim.kosse@filezilla-project.org)

响应: 220 Please visit http://sourceforge.net/projects/filezilla/

命令: AUTH TLS

响应: 502 SSL/TLS authentication not allowed

命令: AUTH SSL

响应: 502 SSL/TLS authentication not allowed

命令: USER newghost

响应: 331 Password required for newghost

命令: PASS **************

响应: 230 Logged on

命令: SYST

响应: 215 UNIX emulated by FileZilla

命令: FEAT

响应: 211-Features:

响应: MDTM

响应: REST STREAM

响应: SIZE

响应: MLST type*;size*;modify*;

响应: MLSD

响应: UTF8

响应: CLNT

响应: MFMT

响应: 211 End

命令: PWD

响应: 257 "/" is current directory.

命令: TYPE I

响应: 200 Type set to I

命令: PASV

响应: 227 Entering Passive Mode (121,42,140,131,14,77)

命令: MLSD

响应: 150 Opening data channel for directory listing of "/"

响应: 226 Successfully transferred "/"

以下是FTP中的命令列表{

"ABOR": "Abort an active file transfer.",

"ACCT": "Account information.",

"ADAT": "Authentication/Security Data",

"ALLO": "Allocate sufficient disk space to receive a file.",

"APPE": "Append.",

"AUTH": "Authentication/Security Mechanism",

"CCC": "Clear Command Channel",

"CDUP": "Change to Parent Directory.",

"CONF": "Confidentiality Protection Command",

"CWD": "Change working directory.",

"DELE": "Delete file.",

"ENC": "Privacy Protected Channel",

"EPRT": "Specifies an extended address and port to which the server should connect.",

"EPSV": "Enter extended passive mode.",

"FEAT": "Get the feature list implemented by the server.",

"HELP": "Returns usage documentation on a command if specified, else a general help document is returned.",

"HOST": "Identify desired virtual host on server, by name.",

"LANG": "Language Negotiation",

"LIST": "Returns information of a file or directory if specified, else information of the current working directory is returned.",

"LPRT": "Specifies a long address and port to which the server should connect.",

"LPSV": "Enter long passive mode.",

"MDTM": "Return the last-modified time of a specified file.",

"MFCT": "Modify the creation time of a file.",

"MFF": "Modify fact (the last modification time, creation time, UNIX group/owner/mode of a file).",

"MFMT": "Modify the last modification time of a file.",

"MIC": "Integrity Protected Command",

"MKD": "Make directory.",

"MLSD": "Lists the contents of a directory if a directory is named.",

"MLST": "Provides data about exactly the object named on its command line, and no others.",

"MODE": "Sets the transfer mode (Stream, Block, or Compressed).",

"NLST": "Returns a list of file names in a specified directory.",

"NOOP": "No operation (dummy packet; used mostly on keepalives).",

"OPTS": "Select options for a feature (for example OPTS UTF8 ON).",

"PASS": "Authentication password.",

"PASV": "Enter passive mode.",

"PBSZ": "Protection Buffer Size",

"PORT": "Specifies an address and port to which the server should connect.",

"PROT": "Data Channel Protection Level.",

"PWD": "Print working directory. Returns the current directory of the host.",

"QUIT": "Disconnect.",

"REIN": "Re initializes the connection.",

"REST": "Restart transfer from the specified point.",

"RETR": "Retrieve a copy of the file",

"RMD": "Remove a directory.",

"RNFR": "Rename from.",

"RNTO": "Rename to.",

"SITE": "Sends site specific commands to remote server (like SITE IDLE 60 or SITE UMASK 002). Inspect SITE HELP output for complete list of supported commands.",

"SIZE": "Return the size of a file.",

"SMNT": "Mount file structure.",

"SPSV": "Use single port passive mode (only one TCP port number for both control connections and passive-mode data connections)",

"STAT": "Returns the current status.",

"STOR": "Accept the data and to store the data as a file at the server site",

"STOU": "Store file uniquely.",

"STRU": "Set file transfer structure.",

"SYST": "Return system type.",

"TYPE": "Sets the transfer mode (ASCII/Binary).",

"USER": "Authentication username.",

"XCUP": "Change to the parent of the current working directory",

"XMKD": "Make a directory",

"XPWD": "Print the current working directory",

"XRCP": "",

"XRMD": "Remove the directory",

"XRSQ": "",

"XSEM": "Send, mail if cannot",

"XSEN": "Send to terminal"

}

以下是FTP中的返回状态码列表:var REPLY_CODE = {

"110": "Restart marker reply.",

"120": "Service ready in nn minutes.",

"125": "Data Connection already open; transfer starting.",

"150": "File status okay; about to open data connection.",

"200": "Command okay.",

"202": "Command not implemented, superfluous at this site.",

"211": "System status, or system help reply.",

"212": "Directory status.",

"213": "File status.",

"214": "Help message.",

"215": "NAME system type.",

"220": "Service ready for new user.",

"221": "Service closing control connection.",

"225": "Data connection open; no transfer in progress.",

"226": "Closing data connection.",

"227": "Entering Passive Mode.",

"230": "User logged in, proceed. This status code appears after the client sends the correct password. It indicates that the user has successfully logged on.",

"250": "Requested file action okay, completed.",

"257": "'\"'PATHNAME'\"' created.",

"331": "User name okay, need password.",

"332": "Need account for login.",

"350": "Requested file action pending further information.",

"421": "Error 421 Service not available, closing control connection.\n Error 421 User limit reached\n Error 421 You are not authorized to make the connection\n Error 421 Max connections reached\n Error 421 Max connections exceeded",

"425": "Cannot open data connection.",

"426": "Connection closed; transfer aborted.",

"450": "Requested file action not taken.",

"451": "Requested action aborted: local error in processing.",

"452": "Requested action not taken. Insufficient storage space in system.",

"500": "Syntax error, command unrecognized, command line too long.",

"501": "Syntax error in parameters or arguments.",

"502": "Command not implemented.",

"503": "Bad sequence of commands.",

"504": "Command not implemented for that parameter.",

"530": "User not logged in.",

"532": "Need account for storing files.",

"550": "Requested action not taken. File unavailable, not found, not accessible",

"552": "Requested file action aborted. Exceeded storage allocation.",

"553": "Requested action not taken. File name not allowed.",

"10054": "Connection reset by peer. The connection was forcibly closed by the remote host.",

"10060": "Cannot connect to remote server.",

"10061": "Cannot connect to remote server. The connection is actively refused by the server.",

"10066": "Directory not empty.",

"10068": "Too many users, server is full."

}

一个简易的FTP服务器

通过以上协议,我们可以编写一个简易的实现了登陆过程的FTP服务器,var net = require('net')

var COMMANDS = {

AUTH: function() {

this.send('502 SSL/TLS authentication not allowed.')

},

USER: function(username) {

this.session.username = username

this.send('331 User name okay, need password.')

},

PASS: function(password) {

var socket = this

var username = socket.username

if (username == 'newghost' && password == 'dachun') {

socket.send(230, 'Logged on')

} else {

socket.send(450, 'Ensure that you typed the correct user name and password combination.')

}

},

PWD: function(args) {

this.send('257 "/" is current directory')

},

TYPE: function(args) {

this.send('200 Type set to I')

},

EPSV: function(args) {

this.send('229 Entering Extended Passive Mode (|||30324|).')

},

PASV: function(args) {

this.send('227 Entering Passive Mode (112,124,126,185,165,12).')

},

MLSD: function(args) {

this.send('226 Successfully transferred "/"')

},

LIST: function(args) {

this.send('502 Command not implemented.')

this.send('502')

}

}

var sendHandler = function(type, message) {

var socket = this

var command

if (arguments.length < 2) {

if (REPLY_CODE[type]) {

command = REPLY_CODE[type]

} else {

command = type.toString()

}

} else {

command = type + ' ' + message

}

console.log('S:', command)

socket.write(command + '\r\n')

}

var ftpServer = net.createServer(function(socket) {

socket.session = {}

socket.send = sendHandler

socket.send(220, 'Welcome to OnceDoc FTP Server')

var onCommand = function(buffer) {

//receives.push(data)

//var buffer = Buffer.concat(receives).toString()

//receives = []

var buffers = buffer.toString()

var lines = buffers.split('\r\n')

for (var i = 0, l = lines.length; i < l; i++) {

var line = lines[i]

if (line) {

console.log('C:', line)

//lines.push(raw[i])

var cmds = line.split(' ')

var cmd = cmds[0].toUpperCase()

var arg = cmds.slice(1)

var func = COMMANDS[cmd]

func

? func.apply(socket, arg)

: socket.send(502)

}

}

}

socket

.on('data', onCommand)

.on('end', function() {

console.log('end', arguments)

})

.on('close', function () {

console.log('close', arguments)

})

.on('timeout', function () {

console.log('timeout', arguments)

})

.on('error', function (err) {

console.log('error', arguments)

})

}).on('error', function(err) {

// handle errors here

console.error(err)

})

//

ftpServer.listen({ port: 21 }, function() {

console.log('opened server on', ftpServer.address())

})

FTP 服务器端模块

目前用Node.JS实现的服务端模块还不多,大多不是很成熟,如

ftp-srvconst FtpSvr = require('ftp-srv')

const ftpServer = new FtpSvr('ftp://127.0.0.1:21')

ftpServer.on('login', function (data, resolve, reject) {

var connection = data.connection

var username = data.username

var password = data.password

if (data.username == 'anonymous') {

resolve({ root: 'D:\\github\\oncedoc\\onceoa' })

} else {

reject()

}

})

ftpServer

.listen()

.then(() => {

console.log('ready')

})

ftpServervar FTPServer = require('ftpserver').FTPServer

var ftpServer = new FTPServer({

host: '127.0.0.1',

port: 21,

pasvStart: null,

pasvEnd: null,

timeout: 30000,

disabledCommands: [],

anonymous: false,

logLevel: 10,

greeting: null,

override: {

fs: null,

authentication: null

}

})

ftpServer.listen().then(() => {

})

nodeftpd

FTP 客户端模块

目前基于node.js的FTP客户端非常成熟,开源项目也比较多

JSFTPvar JSFtp = require("jsftp");

var Ftp = new JSFtp({

host: "myserver.com",

port: 3331, // defaults to 21

user: "user", // defaults to "anonymous"

pass: "1234" // defaults to "@anonymous"

});

Ftp.raw("mkd", "/new_dir", function(err, data) {

if (err) return console.error(err);

console.log(data.text); // Show the FTP response text to the user

console.log(data.code); // Show the FTP response code to the user

});

node-ftpvar c = new Client();

c.on('ready', function() {

c.list(function(err, list) {

if (err) throw err;

console.dir(list);

c.end();

});

});

// connect to localhost:21 as anonymous

c.connect();

node-ftps

这个项目是对lftp的node.js封装var FTPS = require('ftps');

var ftps = new FTPS({

host: 'domain.com', // required

username: 'Test', // Optional. Use empty username for anonymous access.

password: 'Test', // Required if username is not empty, except when requiresPassword: false

protocol: 'sftp', // Optional, values : 'ftp', 'sftp', 'ftps', ... default: 'ftp'

// protocol is added on beginning of host, ex : sftp://domain.com in this case

port: 22, // Optional

// port is added to the end of the host, ex: sftp://domain.com:22 in this case

escape: true, // optional, used for escaping shell characters (space, $, etc.), default: true

retries: 2, // Optional, defaults to 1 (1 = no retries, 0 = unlimited retries)

timeout: 10, // Optional, Time before failing a connection attempt. Defaults to 10

retryInterval: 5, // Optional, Time in seconds between attempts. Defaults to 5

retryMultiplier: 1, // Optional, Multiplier by which retryInterval is multiplied each time new attempt fails. Defaults to 1

requiresPassword: true, // Optional, defaults to true

autoConfirm: true, // Optional, is used to auto confirm ssl questions on sftp or fish protocols, defaults to false

cwd: '', // Optional, defaults to the directory from where the script is executed

additionalLftpCommands: '', // Additional commands to pass to lftp, splitted by ';'

requireSSHKey: true, // Optional, defaults to false, This option for SFTP Protocol with ssh key authentication

sshKeyPath: '/home1/phrasee/id_dsa' // Required if requireSSHKey: true , defaults to empty string, This option for SFTP Protocol with ssh key authentication

});

// Do some amazing things

ftps.cd('some_directory').addFile(__dirname + '/test.txt').exec(console.log);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是 Python 实现 FTP 服务器客户端的代码示例: FTP 服务器端代码: ```python import socket import threading import os SERVER_HOST = '127.0.0.1' SERVER_PORT = 8000 BUFFER_SIZE = 1024 class FTPServer: def __init__(self): self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.bind((SERVER_HOST, SERVER_PORT)) self.server_socket.listen(5) print(f'Server listening on port {SERVER_PORT}') def start(self): while True: client_socket, client_address = self.server_socket.accept() print(f'Accepted connection from {client_address}') t = threading.Thread(target=self.handle_client, args=(client_socket,)) t.start() def handle_client(self, client_socket): while True: # receive command from client command = client_socket.recv(BUFFER_SIZE).decode() if not command: break # process command if command.startswith('upload'): self.handle_upload(client_socket, command.split(' ')[1]) elif command.startswith('download'): self.handle_download(client_socket, command.split(' ')[1]) else: client_socket.send(b'Invalid command\n') client_socket.close() def handle_upload(self, client_socket, filename): # receive file from client client_socket.send(b'Ready to receive file\n') with open(filename, 'wb') as f: while True: data = client_socket.recv(BUFFER_SIZE) if not data: break f.write(data) client_socket.send(b'File uploaded successfully\n') def handle_download(self, client_socket, filename): # check if file exists if not os.path.isfile(filename): client_socket.send(b'File not found\n') return # send file to client client_socket.send(b'Ready to send file\n') with open(filename, 'rb') as f: while True: data = f.read(BUFFER_SIZE) if not data: break client_socket.send(data) client_socket.send(b'File downloaded successfully\n') if __name__ == '__main__': server = FTPServer() server.start() ``` FTP 客户端代码: ```python import socket import os import sys SERVER_HOST = '127.0.0.1' SERVER_PORT = 8000 BUFFER_SIZE = 1024 class FTPClient: def __init__(self): self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.client_socket.connect((SERVER_HOST, SERVER_PORT)) def start(self): while True: # get user input command = input('Enter command: ') # send command to server self.client_socket.send(command.encode()) # process command if command.startswith('upload'): self.handle_upload(command.split(' ')[1]) elif command.startswith('download'): self.handle_download(command.split(' ')[1]) elif command == 'quit': break else: response = self.client_socket.recv(BUFFER_SIZE) print(response.decode()) self.client_socket.close() def handle_upload(self, filename): # check if file exists if not os.path.isfile(filename): print('File not found') return # send file to server self.client_socket.recv(BUFFER_SIZE) with open(filename, 'rb') as f: while True: data = f.read(BUFFER_SIZE) if not data: break self.client_socket.send(data) response = self.client_socket.recv(BUFFER_SIZE) print(response.decode()) def handle_download(self, filename): # receive file from server self.client_socket.recv(BUFFER_SIZE) with open(filename, 'wb') as f: while True: data = self.client_socket.recv(BUFFER_SIZE) if not data: break f.write(data) response = self.client_socket.recv(BUFFER_SIZE) print(response.decode()) if __name__ == '__main__': client = FTPClient() client.start() ``` 这里使用了多线程循环处理的模式,每个客户端连接都会启动一个新的线程来处理。FTP 服务器支持上传和下载文件,FTP 客户端可以通过输入命令来上传和下载文件。注意,此示例程序只是一个简单的实现,没有考虑安全性和错误处理等方面的问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值