之前先了解ftp协议,然后解释代码
- 连接到ftp服务器,得到一个socket(这是一个连接到ftp命令端口socket)
- 发送必要request
- 第一步 Connect到服务器后,ftp_socket.recv(1024) 到服务器的欢迎消息(1 中的socket),不要问为什么,ftp协议规定的,应该是。*注意的是,后面ftp_socket每一次的请求后,都要recv一次,不管你是否全部接受到了都要recv一次,不然可能后面接受不到一些消息。个人觉着这可能是ftp协议的规定:每一次request,都会给client一个response。如果 client没有接受这个response,那么下次的request不会被服务器接受,所以client的recv就会卡住!
- 第二步就像代码中 直到 #LIST 都是用的命令端口。 而使用数据端口时,就是用命令端口 ftp_socket.send("PASV \r\n")new_port = ftp_socket.recv(1024) 使用命令 PASV 请求一个动态的数据端口。
- 解释 我理解的动态数据端口: 即你每一次请求到一个数据端口后,你只能使用一次。比如:[ INFO] 2014-11-29 22:25:44,682 [admin] [127.0.0.1] SENT: 227 Entering Passive Mode (127,0,0,1,204,82) 这是ftp服务器端发送的请求(apache ftpserver),明显括号中是你的ip(我的是本机),然后两个数字。通过查询,你要请求的数据端口:(a,b,c,d,x,y) new_port = x*250+y
- 剩下的部分就很简单了。在代码中再有点解释(后面附server端log)
- 最后还应该用发送一个quit命令,告诉server 我的请求完毕了。这里忘了。
- 一点补充:看到server端log可以发现,服务器每一次的SEND 我们都应该recv一次
#download a folder's files
import socket
class ParseUrl():
"""docstring for ParseUrl"""
def __init__(self, url):
self.url = url
self.method = ""
self.host = ""
self.port =""
def get_method(self):
method_url = self.url
self.method = method_url.split(":")[0]
print "Request Method:",self.method
return self.method
def get_host(self):
temp_pos = self.url.find("://")
temp_url = self.url[temp_pos+3:]
self.host = temp_url[:temp_url.find(":")]
print "Request Host:",self.host
return self.host
def get_port(self):
tem_url = self.url.split(":")[2]
if tem_url.find("/"):
tem_url = tem_url[:tem_url.find("/")]
print "Request Port:",tem_url
self.port = tem_url
return self.port
def parse(self):
temp_methd = self.get_method()
temp_host = self.get_host()
temp_port = self.get_port()
return temp_methd,temp_host,temp_port
def main():
#ftp url
request_url = "ftp://localhost:2121/"
parse_url = ParseUrl(request_url)
method,host,port = parse_url.parse()
print "method,host,port",method,host,port
#get connection to ftp server
ftp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ftp_socket.connect((host,int(port)))
user = "admin\r\n"
password = "admin\r\n"
print ftp_socket.recv(1024) #这个地方是用来接收欢迎消息
ftp_socket.send("USER "+user)
print ftp_socket.recv(1024)
ftp_socket.send("PASS "+password)
print ftp_socket.recv(1024)
ftp_socket.send("CWD \r\n")
print ftp_socket.recv(1024)
ftp_socket.send("TYPE ASCII \r\n")
print ftp_socket.recv(1024)
ftp_socket.send("SIZE my.txt\r\n")
temp_size = ftp_socket.recv(1024)
file_size = int(temp_size.split(" ")[1])
print file_size
#LIST
ftp_socket.send("PASV \r\n")
new_port = ftp_socket.recv(1024)
print new_port
before_port = ""
temp_port =""
if new_port.startswith("227"):
temp_port = new_port.split(",")[5]
before_port = new_port.split(",")[4]
temp_port = temp_port.replace(")\r\n","")
#get the server's new port
new_request_port = int(before_port)*256+int(temp_port)
# connect to the server's new port
ftp_data_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ftp_data_socket.connect((host,new_request_port))
ftp_socket.send("LIST \r\n")
print ftp_data_socket.recv(1024).decode("utf-8")
ftp_socket.recv(1024)
#RETR
ftp_socket.send("PASV \r\n")
new_port = ftp_socket.recv(1024)
print new_port
before_port = ""
temp_port =""
if new_port.startswith("227"):
temp_port = new_port.split(",")[5]
before_port = new_port.split(",")[4]
temp_port = temp_port.replace(")\r\n","")
#get the server's new port
new_request_port = int(before_port)*256+int(temp_port)
# connect to the server's new port
ftp_data_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ftp_data_socket.connect((host,new_request_port))
ftp_socket.send("RETR my.txt\r\n")
file_content = ftp_data_socket.recv(file_size)
print file_content
download_file = open("my.txt","wb")
download_file.write(file_content)
download_file.close()
#print create_data_connection(ftp_socket,"LIST","",host)
if __name__ == '__main__':
main()
SERVEER LOG:
[ INFO] 2014-11-29 22:47:55,513 [] [127.0.0.1] CREATED
[ INFO] 2014-11-29 22:47:55,514 [] [127.0.0.1] OPENED
[ INFO] 2014-11-29 22:47:55,515 [] [127.0.0.1] SENT: 220 Service ready for new user.
[ INFO] 2014-11-29 22:47:55,516 [] [127.0.0.1] RECEIVED: USER admin
[ INFO] 2014-11-29 22:47:55,517 [admin] [127.0.0.1] SENT: 331 User name okay, need password for admin.
[ INFO] 2014-11-29 22:47:55,519 [admin] [127.0.0.1] RECEIVED: PASS *****
[ INFO] 2014-11-29 22:47:55,569 [admin] [127.0.0.1] Login success - admin
[ INFO] 2014-11-29 22:47:55,569 [admin] [127.0.0.1] SENT: 230 User logged in, proceed.
[ INFO] 2014-11-29 22:47:55,571 [admin] [127.0.0.1] RECEIVED: CWD
[ INFO] 2014-11-29 22:47:55,571 [admin] [127.0.0.1] SENT: 250 Directory changed to /
[ INFO] 2014-11-29 22:47:55,572 [admin] [127.0.0.1] RECEIVED: TYPE ASCII
[ INFO] 2014-11-29 22:47:55,573 [admin] [127.0.0.1] SENT: 200 Command TYPE okay.
[ INFO] 2014-11-29 22:47:55,574 [admin] [127.0.0.1] RECEIVED: SIZE my.txt
[ INFO] 2014-11-29 22:47:55,574 [admin] [127.0.0.1] SENT: 213 4813
[ INFO] 2014-11-29 22:47:55,575 [admin] [127.0.0.1] RECEIVED: PASV
[ INFO] 2014-11-29 22:47:55,576 [admin] [127.0.0.1] SENT: 227 Entering Passive Mode (127,0,0,1,213,199)
[ INFO] 2014-11-29 22:47:55,579 [admin] [127.0.0.1] RECEIVED: LIST
[ WARN] 2014-11-29 22:47:55,610 [admin] [127.0.0.1] Releasing unreserved passive port: 54727
[ INFO] 2014-11-29 22:47:55,610 [admin] [127.0.0.1] SENT: 150 File status okay; about to open data connection.
[ INFO] 2014-11-29 22:47:55,610 [admin] [127.0.0.1] SENT: 226 Closing data connection.
[ INFO] 2014-11-29 22:47:55,614 [admin] [127.0.0.1] RECEIVED: PASV
[ INFO] 2014-11-29 22:47:55,616 [admin] [127.0.0.1] SENT: 227 Entering Passive Mode (127,0,0,1,213,201)
[ INFO] 2014-11-29 22:47:55,619 [admin] [127.0.0.1] RECEIVED: RETR my.txt
[ INFO] 2014-11-29 22:47:55,621 [admin] [127.0.0.1] File downloaded /my.txt
[ WARN] 2014-11-29 22:47:55,622 [admin] [127.0.0.1] Releasing unreserved passive port: 54729
[ INFO] 2014-11-29 22:47:55,622 [admin] [127.0.0.1] SENT: 150 File status okay; about to open data connection.
[ INFO] 2014-11-29 22:47:55,622 [admin] [127.0.0.1] SENT: 226 Transfer complete.
Comments
Post a Comment