需求: 一台机器上有多个网卡, 如何访问指定的 URL 时使用指定的网卡发送数据呢?
$ curl --interface eth0 www.baidu.com # curl interface 可以指定网卡
阅读 urllib.py 的源码, 追述到 open_http –> httplib.HTTP –> httplib.HTTP._connection_class = HTTPConnection
HTTPConnection 在创建的时候会指定一个 source_address.
HTTPConnection.connect 时调用 HTTPConnection._create_connection = socket.create_connection
# 先看一下本地网卡信息
$ ifconfig
lo0: flags=8049 mtu 16384
options=3
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=1
en0: flags=8863 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
media: autoselect
status: active
en1: flags=8863 mtu 1500
options=4
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
media: autoselect (100baseTX )
status: active
可以看到en0和en1, 这两块网卡都可以访问公网. lo0是本地回环.
直接修改 socket.py 做测试.
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