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.