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

Elasticsearch error when the field exceed limit 32kb

When we post data that the field exceed the limit, elasticsearch will reject the data which error: {"error":{"root_cause":[{"type":"remote_transport_exception","reason":"[cs19-2][10.200.20.39:9301][indices:data/write/index]"}],"type":"illegal_argument_exception","reason":"Document contains at least one immense term in field=\"field1\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped.  Please correct the analyzer to not produce such terms.  The prefix of the first immense term is You can handle this: 1. you can udpate the mapping part at any time PUT INDEXNAME/_mapping/TYPENAME { "properties" : { "logInfo" : { "type" : "string" , "analyzer" : "keyword" , "ignore_above" : 32766 } } } ignore_above means that we will only keep 32766 bytes 2...

学习服务器配置之路~~

第一个常见的小问题: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" ...

Java ClassLoader 学习反馈

Classloader是Java运行时核心机制之一,它解决了我们的.class文件如何被jvm加载的问题。也就是我们的写的源码.java文件被编译成.class字节码后,如何被jvm加载解释。 Java在广义上有三种classloader BootstrapClassLoader 是JVM级别的classloader,使用c/c++来写的。详细解释如何来加载一个bootstrap级别的class文件,哪些class文件是bootstrapclassloader来加载的。 ExtClassLoader  是ExtensionClassLoader,他是AppClassLoader的 ‘父类’,这个父类不是指AppClassLoader extends ExtClassLoader,而是指ExtClassLoader来创建了AppClassloader,后面源码部分可以解释这个关系。 AppClassLoader 这是一般我们自己写的class的classloader,他加载了我们自己写的class,而且同时如果我们有自定义的classloader,那么他也是custom class loader的parent class loader. 他们的加载顺序也是从上往下,即 1->2 ->3。   到这里可能会产生疑问,他们加载的class有何不同?  AppClassLoader是上面说的,他会加载我们自己定义的class,即我们workspace的classpath下的class ExtClassLoader则是加载我们Jdk lib/ext 下的class BootstrapClassLoader是加载 rt.jar、resources.jar、charsets.jar和class等。  那么他们是如何找到lib下这些class文件呢? 答案是通过环境变量中的一些变量,而这些变量的定义也是通过我们设置的JAVA HOME等来取得。 源码中有这么两个地方解释了这个地方。 ==》 private static String bootClassPath = System.getProperty( "sun.boot.class.path" ); ==》...