简体   繁体   中英

Picking which ip address to use for ftp connection

I got a question. My NIC has several secondary ip addresses. I was not able to find a library for ftp in python which allows to pick which ip address to use to connect to a ftp server. Does anyone know how it can be implemented, i looked into raw sockets and didn't find it too. I know it's implemented for http/https in jmeter for example, but not for ftp for some reason.

Any help is appreciated.

As noted by spectras , the FTP client in the Python 3 standard library allows specifying a source address as a tuple. Unless you have a known or static port for the source, setting the port number to zero should pick the next available port. Using the docs as an example:

from ftplib import FTP

source = ('192.168.1.100', 0)
destination = '172.16.1.1'
with FTP(destination, source_address=source) as ftp:
    ftp.login()
    print(ftp.dir())

As I mentionned, standard python ftp lib has a source_address parameter. However it's not available for python 2, which you apparently need.

So I suggest the following kludge for python2.7. That's copy-pasting python3 implementation of source_address argument and tweaking it to make it work. Ugly but…

import ftplib
import socket

class FTP(ftplib.FTP):
    # KLUDGE, MANUAL BACKPORT OF source_address
    #     => REMOVE WHEN MOVING TO PYTHON3

    def __init__(self, *args, **kwargs):
        self.source_address = kwargs.pop("source_address", None)
        super(FTP, self).__init__(*args, **kwargs)

    def connect(self, host='', port=0, timeout=-999, source_address=None):
        if host != '':
            self.host = host
        if port > 0:
            self.port = port
        if timeout != -999:
            self.timeout = timeout
        if source_address is not None:
            self.source_address = source_address
        self.sock = socket.create_connection((self.host, self.port), self.timeout,
                                             self.source_address)
        self.af = self.sock.family
        self.file = self.sock.makefile('rb')
        self.welcome = self.getresp()
        return self.welcome

    def ntransfercmd(self, cmd, rest=None):
        size = None
        if self.passiveserver:
            host, port = self.makepasv()
            conn = socket.create_connection((host, port), self.timeout,
                                            self.source_address)
            try:
                if rest is not None:
                    self.sendcmd("REST %s" % rest)
                resp = self.sendcmd(cmd)
                if resp[0] == '2':
                    resp = self.getresp()
                if resp[0] != '1':
                    raise ftplib.error_reply, resp
            except:
                conn.close()
                raise
        else:
            sock = self.makeport()
            try:
                if rest is not None:
                    self.sendcmd("REST %s" % rest)
                resp = self.sendcmd(cmd)
                if resp[0] == '2':
                    resp = self.getresp()
                if resp[0] != '1':
                    raise ftplib.error_reply, resp
                conn, sockaddr = sock.accept()
                if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
                    conn.settimeout(self.timeout)
            finally:
                sock.close()
        if resp[:3] == '150':
            size = ftplib.parse150(resp)
        return conn, size

It's as ugly as monkey patching. It should do the trick. If you use it, please document this horror so it is removed when you move to python3.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM