Reputation: 23
I am trying to create a simple FTP client but somehow the FTP connection can not be established.
I used the following code:
import socket
sock = socket.socket()
sock.connect(('localhost', 21))
data = 'USER adm\r\n'.encode()
sock.send(data)
print('Close')
sock.close()
The logs of the FTP server I try to connect to look like this:
(048507)01.05.2018 06:00:03 - (not logged in) (127.0.0.1)> Connected on port 21, sending welcome message...
(048507)01.05.2018 06:00:03 - (not logged in) (127.0.0.1)> 220-FileZilla Server 0.9.60 beta
(048507)01.05.2018 06:00:03 - (not logged in) (127.0.0.1)> 220-written by Tim Kosse ([email protected])
(048507)01.05.2018 06:00:03 - (not logged in) (127.0.0.1)> 220 Please visit https://filezilla-project.org/
(048507)01.05.2018 06:00:03 - (not logged in) (127.0.0.1)> disconnected.
I tried to send the USER adm
command but can not find it in the logs. How can I establish a successful connection to a FTP server with sockets?
Upvotes: 2
Views: 6158
Reputation: 1
Do a "first response" read from server to verify if it "hears" you or not and as the server hears you and it "talked back" once, make a loop to read all of the responses from the server until the server go quiet with no response, just like waiting for it to finish "talking". Then you may continue your "talk" with the server by sending new data to it.
Based from other answers and your comment replies, it seems that you went from ignoring when will the server itself finish "talking" to expecting it to finish "talking" after your 5 second sleep timer, which is not good. The most efficient way is to "listen" to all of the server's "talk" response before "talking" to the server again as client.
That way you can immediately "talk" to server after it finishes "talking" with you, the client.
Upvotes: 0
Reputation:
There are a couple of possible timing issues.
FTP is a "server speaks first" protocol. The 220 banner that you see in your log is sent by the server immediately after the connection is accepted. The client is supposed to read that banner before sending any commands. (If you get any numeric code other than 220, the server is unwilling to talk.)
For testing purposes, I recommend that you read from the server and print whatever you read to stdout. Your server's 220 banner is an example of a multi-line FTP response, in which the numeric code is followed by a hyphen on the first line, and followed by a space on the last line. You should keep reading until you get a line with a space after the numeric code.
If you don't do that, and just send USER
immediately after the connection completes, you are speaking out of turn. Depending on how fast your client code is running, the server may get the command before it is expecting one, and that could explain why it doesn't respond.
The other possible problem is that you are closing the connection immediately after sending USER
, without waiting for the response. The server might notice that too. Even if it's not trying to detect odd client behavior, it might be getting a write error when it tries to send its response, and that could explain why it's not logging normally.
The overall structure of an FTP client in pseudocode is
connect
read response (banner)
while not done:
send command
read response
send QUIT
read response
close
(That omits the really interesting part, which is managing the data connection, but you haven't got that far yet).
For your test where you just want to get as far as USER
, you at least need to:
connect
read banner
send USER
read response
close
(Skipping QUIT
probably won't do any harm)
Note that the server is allowed to return a multi-line response to any command, including USER
, so you should always check for the space after the numeric code. It's a good idea to write a subroutine to read a single FTP response, and call that after every command.
Upvotes: 2