码迷,mamicode.com
首页 > 其他好文 > 详细

自己动手写一个FTP客户端

时间:2016-08-18 21:39:54      阅读:682      评论:0      收藏:0      [点我收藏+]

标签:ftp   测试   python   

自己用socket写一个FTP客户端,模拟主动被动模式。(先支持LIST命令技术分享

# -*- coding: utf-8 -*-

import socket, sys, thread, threading

def main_sock(daddr, actions, saddr=()):
    if saddr:
        try:
            sc=socket.create_connection(daddr, 3, saddr)
            #print "Now %s connecting to %s ... ..."%(saddr, daddr)
        except socket.error:
            print ‘TCP socket connect %s => %s failed‘%(saddr, daddr)
            return
    else:
        try:
            sc=socket.create_connection(daddr, 3)
        except socket.error:
            print ‘TCP socket connect %s failed‘%(daddr)
            return
    #step 1 : print welcome informations
    print "<--recive: ",sc.recv(1024)
    #step 2 login
    login(sc, actions[0])
    #step 3 use ASCII TYPE send and recv data
    sc.send(‘TYPE A\r\n‘)
    recv=sc.recv(1024)
    print "send--> TYPE A\n <---recive: ",recv
    #step 4 use mode PORT OR PASV
    if actions[1][0]==1:     # PORT mode
        if daddr[0].find(‘:‘)!=-1:    #IPV6
            sc.send(‘EPRT |2|%s|%s|\r\n‘%(actions[1][1], actions[1][2]))
        elif daddr[0].find(‘:‘)==-1:   #ipv4
            sc.send(‘PORT %s\r\n‘%handle_PORT(actions[1][1], actions[1][2]))
        print "<--recive: ",sc.recv(1024)
        #step 5 build sub connection
        th_1=threading.Thread(target=sub_bindSock, args=(actions[1][1], actions[1][2]))
        th_1.start()
        sc.send(actions[2])    #send LIST command
        print "<--recive: ",sc.recv(1024)
        th_1.join()
    elif actions[1][0]==0:   #PASV mode
        if daddr[0].find(‘:‘)!=-1:   #ipv6
            sc.send(‘EPSV\r\n‘)
            recv=sc.recv(1024)
            subDport=int(recv[recv.find(‘(|||‘)+4:recv.find(‘|)‘)])
        elif daddr[0].find(‘:‘)==-1:  #ipv4
            sc.send(‘PASV\r\n‘)
            recv=sc.resv(1024)
            subDport=handle_PASV(recvStr)
        subDaddr=(daddr[0], subDport)
        #step 5 build sub connection
        th_2=threading.Thread(target=sub_sock, args=(subDaddr, ))
        th_2.start()
        sc.send(actions[2])
        th_2.join()
    while 1:
        try:
            data=sc.recv(1024)
            if not len(data):
                break
            else:
                print "<--recived: ",data
        except:
            print "timeout!"
            break
    sc.close()
def sub_sock(daddr, saddr=()):
    try:
        subSc=socket.create_connection(daddr, 3, saddr)
        #print "Now %s connecting to %s ... ..."%(saddr, daddr)
    except socket.error:
        print ‘TCP socket connect %s => %s failed‘%(saddr, daddr)
    while 1:
        try:
            data=subSc.recv(2048)
            if not len(data):
                break
            else:
                print "<--subCon recived:",data
        except:
            print "timeout!"
            break
    subSc.close()
def sub_bindSock(saddr, sport):
    if saddr.find(‘:‘)==-1:
        sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    else:
        sc = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
    try:
        sc.bind((saddr, sport))
        sc.listen(5)
        sc.settimeout(3)
    except:
        print "bind %s:%s failed!"%(sip, sport)
        return -1
    peerSock, peerAddr=sc.accept()
    print "sub connect is builded\r\n%s<------>%s"%((saddr, sport), peerAddr)
    while 1:
        try:
            data=peerSock.recv(2048)
            if not len(data):
                break
            else:
                print "<--subCon recived:",data
        except:
            print "timeout!"
            break
    sc.close()
def login(sock, loginInfo):
    sock.send(‘USER %s\r\n‘%loginInfo[0])
    recv=sock.recv(1024)
    print "send--> username ok!\n<--recive: ",recv
    sock.send(‘PASS %s\r\n‘%loginInfo[1])
    recv=sock.recv(1024)
    print "send--> password ok!\n<--recive: ",recv
def handle_PORT(saddr, sport):
    ‘‘‘主动模式时,如果地址是IPV4,将地址和端口的格式进行转换,然后放到Port 命令中发送 ‘‘‘
    addrStr=‘,‘.join(saddr.split(‘.‘))
    temp=divmod(sport, 256)
    portStr=str(temp[0])+‘,‘+str(temp[1])
    return addrStr+‘,‘+portStr
def handle_PASV(recvStr):
    ‘‘‘针对IPV4,将受到的子连接端口字符串信息转换为真正的端口,并返回‘‘‘
    temp=recvStr[recvStr.find(‘Mode (‘)-1:recvStr.find(‘)‘)]
    a=temp.split(‘,‘)[4]
    b=temp.split(‘,‘)[5]
    subPort=int(a)*256+int(b)
    return subPort


if __name__==‘__main__‘:
    #target=‘192.168.10.112‘
    target=‘4001::112‘
    port=21
    Daddr=(target, port)
    username=‘anonymous‘
    passwd=‘IE@126.com‘
    loginInfo=(username, passwd)
    FTPmode=1 # 1 means PORT mode, 0 means PASV mode
    #saddr=‘192.168.10.102‘
    saddr=‘2000::5d80:b20f:8631:9782‘
    sport=11178
    PASV_or_PORT=(FTPmode, saddr, sport)
    LIST=‘LIST\r\n‘
    actions=(loginInfo, PASV_or_PORT, LIST)
    main_sock(Daddr, actions)


FTP协议是典型的多连接协议。通信的时候会建立两个通道:主连接和子连接。主连接传输控制信令(例如上传下载列出目录等),当需要传输数据的时候,会在主连接中使用被动模式或者主动模式协商好端口,然后打开一个子连接,传输完后,子连接就立即被拆掉了。


通过自己动手实现一个FTP客户端,可以加深对FTP协议的理解。


以上,main_sock为FTP的主连接处理,sub_sock为子连接的处理函数,sub_bindSock为主动模式时,开启一个端口监听,等待服务器主动过来连接。


好了,代码中都有注释。

本文出自 “Dalon 技术博客” 博客,转载请与作者联系!

自己动手写一个FTP客户端

标签:ftp   测试   python   

原文地址:http://ybtest.blog.51cto.com/1941531/1840025

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!