Python 使用socket实现ftp 客服端

之前先了解ftp协议,然后解释代码
  1. 连接到ftp服务器,得到一个socket(这是一个连接到ftp命令端口socket)
  2. 发送必要request
  3. 第一步 Connect到服务器后,ftp_socket.recv(1024) 到服务器的欢迎消息(1 中的socket),不要问为什么,ftp协议规定的,应该是。*注意的是,后面ftp_socket每一次的请求后,都要recv一次,不管你是否全部接受到了都要recv一次,不然可能后面接受不到一些消息。个人觉着这可能是ftp协议的规定:每一次request,都会给client一个response。如果 client没有接受这个response,那么下次的request不会被服务器接受,所以client的recv就会卡住!
  4. 第二步就像代码中 直到 #LIST 都是用的命令端口。 而使用数据端口时,就是用命令端口  ftp_socket.send("PASV ")
        new_port = ftp_socket.recv(1024)     使用命令 PASV 请求一个动态的数据端口。
  5. 解释 我理解的动态数据端口: 即你每一次请求到一个数据端口后,你只能使用一次。比如:[ 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
  6. 剩下的部分就很简单了。在代码中再有点解释(后面附server端log)
  7. 最后还应该用发送一个quit命令,告诉server 我的请求完毕了。这里忘了。
  8. 一点补充:看到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 "
    password = "admin "

    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 ")

    print ftp_socket.recv(1024)

    ftp_socket.send("TYPE ASCII ")

    print ftp_socket.recv(1024)
    
   

    ftp_socket.send("SIZE my.txt ")
    temp_size = ftp_socket.recv(1024)
    file_size = int(temp_size.split(" ")[1])

    print file_size

#LIST 
    ftp_socket.send("PASV ")
    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(") ","")
    #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 ")
    
    print ftp_data_socket.recv(1024).decode("utf-8")
    
    ftp_socket.recv(1024)


#RETR
    ftp_socket.send("PASV ")
    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(") ","")
    #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 ")

    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.
原文地址:https://www.cnblogs.com/-Doraemon/p/4700068.html