使用 FTP 命令下载带套接字的文件

Using FTP commands to download a file with sockets

我使用的是专有编程语言,它没有内置 FTP 功能。因此我使用 sockets.

sHandle := SocketOpen('ftp.Whosebug.net', 21);
SocketReadString(sHandle, answer);

retW := SocketWriteString(sHandle, 'user user1673665' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
retW := SocketWriteString(sHandle, 'pass !@#$%^&*' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);

retW := SocketWriteString(sHandle, 'cwd update' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
retW := SocketWriteString(sHandle, 'retr update.txt' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);

SocketClose(sHandle);

这些是我从 FTP 服务器收到的答案:

220-Welcome to Whosebug FTP
220 Unauthorized access is illegal!
331 Password required for user1673665
230 Logged on
250 CWD successful. "/update" is current directory.

但是为什么我在retr update.txt之后得到这个错误:

503 Bad sequence of commands.

我正在逐步调试代码。因此响应时间应该不是问题。

RETR 命令之前必须至少有 PASVPORT 才能设置数据连接。

请参阅 RFC 959,尤其是 “3.2. 建立数据连接”部分

使用 PASV 时,您必须打开服务器在 227 响应中返回的端口的连接。


另请注意,FTP 命令应以大写形式发送。

Why does retr update.txt not work?

因为您没有遵循 FTP 协议的规范。数据传输使用单独的 TCP 连接完成,需要使用 PASVEPSVPORTEPRT 命令预先设置。有关详细信息,请参阅标准(这就是它们的用途),即 RFC 959 and RFC 2428.

感谢 Martin Prikryl 和 Steffen Ullrich 的帮助。我将在此处添加带有注释的工作代码。也许它对某人有用。也许有必要添加睡眠命令,因为代码运行速度比服务器响应速度快。

# Open control channel
sHandle := SocketOpen('ftp.Whosebug.net', 21);
SocketReadString(sHandle, answer);
SocketWriteString(sHandle, 'USER user1673665' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
SocketWriteString(sHandle, 'PASS !@#$%^&*' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
SocketWriteString(sHandle, 'CWD update' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
# Enter passive mode and receive data channel adress and port
SocketWriteString(sHandle, 'PASV' & CHR(13) & CHR(10));
SocketReadString(sHandle, answer);
# Create adress for data channel
IF answer <> NOVALUE THEN
  # Split answer on character , and ( and ) and whitespace
  retPASV[] := StrSplit(answer, ',() ');
ENDIF;
CASE retPASV[1]
    # Passive mode is 227
  IS = 227 DO
    connect := retPASV[6] & '.' & retPASV[7] & '.' & retPASV[8] & '.' & retPASV[9];
  IS DO
ENDCASE;
# Create port for data channel
# Port is secondlast number * 256 + last number from PASV reply
port := String2Num(retPASV[10]) * 256 + String2Num(retPASV[11]);
# Open data channel on sHandle2
sHandle2 := SocketOpen(connect, port);
SocketReadString(sHandle2, answer2);
# Download file on control channel
SocketWriteString(sHandle, 'RETR update.txt' & CHR(13) & CHR(10));
SocketReadString(sHandle, Antwort);
# Read file on data channel - result of textfile in string answer2
SocketReadString(sHandle2, answer2);
SocketClose(sHandle);