Skip to main content

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 \r\n")
        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\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

Popular posts from this blog

学习服务器配置之路~~

第一个常见的小问题:MySQL安装 os : fedora 20 mysql: mysql-server(5.5) 所有假设你的系统是没有经过特殊配置的。 1: yum install mysql-server 2: mysql 报错:socket连接不上 3: service mysqld start   注意这步是 mysqld 不是mysql 这样就解决。网上的方法好像有点麻烦。 第二个小问题:解压一些文件(.tar.gz)时报错 http://itsfoss.com/how-solve-stdin-gzip-format/ 上面介绍的很清楚,总之要先确认你下载的文件类型。 第三个小问题。配置tomcat服务器 主要问题是比如我的域名是 cqupt.me 而你tomcat服务器的项目在/webapps/{your projectname} 这时你很蛋疼的要 cqupt.me:8080/{your projectname}/index.html。 如果要cqupt.me就可以完成。这样配置: 都是在tomcat下/conf/server.xml 第一步端口。简单 不废话 第二部。 <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> </Host> 在标签中间插入: <Context path=""  docBase="xbwl"  debug="0" reloadable="true"/> docBase="xbwl" xbwl 即为指定的项目。即({your projectname}_ 完整如下: <Host name="localhost" appBase="webapps" ...

Golang http server performance tuning practice (Golang HTTP服务器性能调优实践)

  Golang 1.8后本身自带了pprof的这个神器,可以帮助我们很方便的对服务做一个比较全面的profile。对于一个Golang的程序,可以从多个方面进行profile,比如memory和CPU两个最基本的指标,也是我们最关注的,同时对特有的goroutine也有运行状况profile。关于golang profiling本身就不做过多的说明,可以从 官方博客 中了解到详细的过程。   Profile的环境 Ubuntu 14.04.4 LTS (GNU/Linux 3.19.0-25-generic x86_64) go version go1.9.2 linux/amd64  profile的为一个elassticsearch数据导入接口,承担接受上游数据,根据元数据信息写入相应的es索引中。目前的状况是平均每秒是1.3Million的Doc数量。   在增加了profile后,从CPU层面发现几个问题。 runtime mallocgc 占用了17.96%的CPU。 SVG部分图如下 通过SVG图,可以看到调用链为: ioutil.ReadAll -> buffer.ReadFrom -> makeSlice -> malloc.go  然后进入ReadAll的源码。 readAll()方法 func readAll(r io.Reader, capacity int64) (b []byte, err error) { buf := bytes . NewBuffer ( make ([] byte , 0 , capacity )) // If the buffer overflows, we will get bytes.ErrTooLarge. // Return that as an error. Any other panic remains.   defer func() { e := recover () if e == nil { return } if panicErr , ok := e .( error ) ; ok && p...