需求: 一台机器上有多个网卡, 如何访问指定的 URL 时使用指定的网卡发送数据呢?
$ curl --interface eth0 www.baidu.com # curl interface 可以指定网卡 |
# 先看一下本地网卡信息 $ ifconfig lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=3<RXCSUM,TXCSUM> inet6 ::1 prefixlen 128 inet 127.0.0.1 netmask 0xff000000 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 nd6 options=1<PERFORMNUD> en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ether c8:e0:eb:17:3a:73 inet6 fe80::cae0:ebff:fe17:3a73%en0 prefixlen 64 scopeid 0x4 inet 192.168.20.2 netmask 0xffffff00 broadcast 192.168.20.255 nd6 options=1<PERFORMNUD> media: autoselect status: active en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=4<VLAN_MTU> ether 0c:5b:8f:27:9a:64 inet6 fe80::e5b:8fff:fe27:9a64%en8 prefixlen 64 scopeid 0xa inet 192.168.8.100 netmask 0xffffff00 broadcast 192.168.8.255 nd6 options=1<PERFORMNUD> media: autoselect (100baseTX <full-duplex>) status: active |
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
source_address=None):
"""If *source_address* is set it must be a tuple of (host, port)
for the socket to bind as a source address before making the connection.
An host of '' or port 0 tells the OS to use the default.
source_address 如果设置, 必须是传递元组 (host, port), 默认是 ("", 0)
"""
host, port = address
err = None
for res in getaddrinfo(host, port, 0, SOCK_STREAM):
af, socktype, proto, canonname, sa = res
sock = None
try:
sock = socket(af, socktype, proto)
# sock.bind(("192.168.20.2", 0)) # en0
# sock.bind(("192.168.8.100", 0)) # en1
# sock.bind(("127.0.0.1", 0)) # lo0
if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
sock.settimeout(timeout)
if source_address:
print "socket bind source_address: %s" % source_address
sock.bind(source_address)
sock.connect(sa)
return sock
except error as _:
err = _
if sock is not None:
sock.close()
if err is not None:
raise err
else:
raise error("getaddrinfo returns an empty list")
|
# 测试 en0
$ python -c 'import urllib as u;print u.urlopen("http://ip.haschek.at").read()'
.148.245.16
# 测试 en1
$ python -c 'import urllib as u;print u.urlopen("http://ip.haschek.at").read()'
.94.115.227
# 测试 lo0
$ python -c 'import urllib as u;print u.urlopen("http://ip.haschek.at").read()'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 87, in urlopen
return opener.open(url)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 213, in open
return getattr(self, name)(url)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 350, in open_http
h.endheaders(data)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1049, in endheaders
self._send_output(message_body)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 893, in _send_output
self.send(msg)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 855, in send
self.connect()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 832, in connect
self.timeout, self.source_address)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 578, in create_connection
raise err
IOError: [Errno socket error] [Errno 49] Can't assign requested address
|
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 87, in urlopen return opener.open(url) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 213, in open return getattr(self, name)(url) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 350, in open_http h.endheaders(data) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1049, in endheaders self._send_output(message_body) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 893, in _send_output self.send(msg) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 855, in send self.connect() File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 832, in connect self.timeout, self.source_address) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 577, in create_connection raise err IOError: [Errno socket error] [Errno 48] Address already in use |
# test-interface_urllib.py
import socket
import urllib, urllib2
_create_socket = socket.create_connection
SOURCE_ADDRESS = ("127.0.0.1", 0)
#SOURCE_ADDRESS = ("172.28.153.121", 0)
#SOURCE_ADDRESS = ("172.16.30.41", 0)
def create_connection(*args, **kwargs):
in_args = False
if len(args) >=3:
args = list(args)
args[2] = SOURCE_ADDRESS
args = tuple(args)
in_args = True
if not in_args:
kwargs["source_address"] = SOURCE_ADDRESS
print "args", args
print "kwargs", str(kwargs)
return _create_socket(*args, **kwargs)
socket.create_connection = create_connection
print urllib.urlopen("http://ip.haschek.at").read()
|
import urllib3.connection _create_socket = urllib3.connection.connection.create_connection # pass urllib3.connection.connection.create_connection = create_connection # pass |
import socket
import urllib
import urllib2
import urllib3.connection
import requests as req
_default_create_socket = socket.create_connection
_urllib3_create_socket = urllib3.connection.connection.create_connection
SOURCE_ADDRESS = ("127.0.0.1", 0)
#SOURCE_ADDRESS = ("172.28.153.121", 0)
#SOURCE_ADDRESS = ("172.16.30.41", 0)
def default_create_connection(*args, **kwargs):
try:
del kwargs["socket_options"]
except:
pass
in_args = False
if len(args) >=3:
args = list(args)
args[2] = SOURCE_ADDRESS
args = tuple(args)
in_args = True
if not in_args:
kwargs["source_address"] = SOURCE_ADDRESS
print "args", args
print "kwargs", str(kwargs)
return _default_create_socket(*args, **kwargs)
def urllib3_create_connection(*args, **kwargs):
in_args = False
if len(args) >=3:
args = list(args)
args[2] = SOURCE_ADDRESS
in_args = True
args = tuple(args)
if not in_args:
kwargs["source_address"] = SOURCE_ADDRESS
print "args", args
print "kwargs", str(kwargs)
return _urllib3_create_socket(*args, **kwargs)
socket.create_connection = default_create_connection
# 因为偶尔会出问题, 所以使用默认的 socket.create_connection
# urllib3.connection.connection.create_connection = urllib3_create_connection
urllib3.connection.connection.create_connection = default_create_connection
print " *** test requests: " + req.get("http://ip.haschek.at").content
print " *** test urllib: " + urllib.urlopen("http://ip.haschek.at").read()
print " *** test urllib2: " + urllib2.urlopen("http://ip.haschek.at").read()
|
import subprocess
def get_all_net_devices():
sub = subprocess.Popen("ls /sys/class/net", shell=True, stdout=subprocess.PIPE)
sub.wait()
net_devices = sub.stdout.read().strip().splitlines()
# ['eth0', 'eth1', 'lo']
# 这里简单过滤一下网卡名字, 根据需求改动
net_devices = [i for i in net_devices if "ppp" in i]
return net_devices
ALL_DEVICES = get_all_net_devices()
def get_local_ip(device_name):
sub = subprocess.Popen("/sbin/ifconfig en0 | grep '%s ' | awk '{print $2}'" % device_name, shell=True, stdout=subprocess.PIPE)
sub.wait()
ip = sub.stdout.read().strip()
return ip
def random_local_ip():
return get_local_ip(random.choice(ALL_DEVICES))
# code ...
|