python 控制有线网卡_Python 使用指定的网卡发送HTTP请求的实例

需求: 一台机器上有多个网卡, 如何访问指定的 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 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")

参考说明文档, 直接分三次绑定不通网卡的 IP 地址, 端口设置为0.

# 测试 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 "", line 1, in

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

测试通过, 说明在多网卡情况下, 创建 socket 时绑定某块网卡的 IP 就可以, 端口需要设置为0. 如果端口不设置为0, 第二次请求时, 可以看到抛异常, 端口被占用.

Traceback (most recent call last):

File "", line 1, in

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

如果是在项目中, 只需要把 socket.create_connection 这个函数的形参 source_address 设置为对应网卡的 (IP, 0) 就可以.

# 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()

通过测试, 可以发现已经可以通过制定的网卡发送数据, 并且 IP 地址对应网卡分配的 IP.

问题, 爬虫经常使用 requests, requests 是否支持呢. 通过测试, 可以发现, requests 并没有使用 python 内置的 socket 模块.

看源码, requests 是如果创建的 socket 连接呢. 方法和查看 urllib 创建socket 的方式一样. 具体就不写了.

因为我用的是 python 2.7, 所以可以定位到 requests 使用的 socket 模块是 urllib3.utils.connection 的.

修改方法和 urllib 相差不大.

import urllib3.connection

_create_socket = urllib3.connection.connection.create_connection

# pass

urllib3.connection.connection.create_connection = create_connection

# pass

运行后, 可能会抛出异常. requests.exceptions.ConnectionError: Max retries exceeded with .. Invalid argument

这个异常不是每次出现, 跟 IP 段有关系, 跳转递归层数太多导致, 只需要将 kwargs 中的 socket_options去掉即可. 127.0.0.1肯定会出异常.

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()

注意:使用 urllib3.utils.connection 好像不起作用

稍微再完善一下, 就是把根据网卡名自动获取 IP.

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 ...

只需要把 args[2] = SOURCE_ADDRESS 和 kwargs["source_address"] = SOURCE_ADDRESS改成 random_local_ip() 或者 get_local_ip("eth0")

至于有什么用途, 就全凭想象了.

以上这篇Python 使用指定的网卡发送HTTP请求的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C函数指针别再停留在语法,得上升到软件设计

点击蓝字关注我们经常有朋友问到底如何在C程序中采用面向对象编程?如何让模块之间松耦合?......其实究其原因还是没有把C语言与软件设计很好的联系起来。这里跟大家找了一些内容,相信认真看完全文多多少少会有你想要的答案:正文部分&#xf…

spring默认缓存管理器_使用Spring的缓存管理器缓存Web内容

spring默认缓存管理器在这篇文章中,我想向大家展示如何使用Spring的CacheManager, Cacheable和JMX批注来缓存和管理Web内容的缓存的基础知识。 想象一下一个网上商店,它从远程WCMS(Web内容管理系统)获取一些内容&#…

计算机软件选修课选什么好,大学值得选的“选修课”,一点不比专业课差,能选上最好认真听...

原标题:大学值得选的“选修课”,一点不比专业课差,能选上最好认真听文/小哈你是怎样对待你的选修课的?以前经常听学长学姐们说过这样一句话,“上大学之后,专业课选逃,选修课必逃”。不知道大家是…

自动化运维 python 批量监控服务器_1、python自动化运维——监测服务器状态

监测服务器状态 获取系统性能信息 1、CPU信息: Linux操作系统的CPU利用的几个部分: User Time;SystemTime;Wait IO;Idle psutil.cpu_times() psutil.cpu_times().user psutil.cpu_count() 2、内存信息 psutil.virtual_memory() #查看内存完整信息 psutil…

计算机应用基础模拟三答案,《计算机应用基础》模拟试卷三答案

计算机应用基础计算机应用基础 模拟试卷三模拟试卷三 答案答案 得分评卷人 一一 填空题填空题 1 HTTP 2 采样频率 3 机械 光电 光学 4 文件夹 5 TCP IP 6 网卡 7 网络地址 8 光纤 9 应用 10 左下角 标签颜色为白色 11 第一步 打开 页面设置 在 页边距 选项卡中选择横向 然后在 …

C/C++程序员的编程修养

点击蓝字关注我们什么是好的C/C程序员?是不是懂得很多技术细节?还是懂底层编程?还是编程速度比较快?我觉得都不是。对于一些技术细节来说和底层的技术,只要看帮助,查资料就能找到,对于速度快&am…

ginkgo spi 错误_开发SPI时不要犯这个错误

ginkgo spi 错误您的大多数代码都是私有的,内部的,专有的,并且永远不会公开。 在这种情况下,您可以放轻松–您可以重构所有错误,包括那些可能导致API更改中断的错误。 但是,如果要维护公共API,…

python账号密码一一对应_python模拟用户登录系统,如何两个用户输入各自的密码才能登入?...

展开全部 #我可以把我自己2113的成果送你,你来研究5261研究 import json #用来存储数据4102的模块 import os #用来进行文件操作1653 import sys #获取脚本所在目录用 import re #用来进行字符串操作 script_path os.path.realpath(__file__) PATH os.path.dirnam…

计算机课实验三,成都信息工程学院计算机网络课程实验三

成都信息工程学院计算机网络课程实验三 本文关键词:成都,计算机网络,信息工程学院,课程,实验成都信息工程学院计算机网络课程实验三 本文简介:计算机网络实验报告实验三:编写客户服务器程序班级…

C语言#define与typedef的区别

点击蓝字关注我们在C语言编程中,typedef 和 #define是最常用语句,可能很多工作过几年的工程师都没有去深究过它们的一些用法和区别。typedef的用法在C/C语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部…

netflix_Netflix Archaius用于物业管理–基础知识

netflixNetflix Archaius提供了一组精巧的功能,可将动态属性加载到应用程序中。 这篇博客文章只是我所了解的Archaius范围的文档,比我在这里所记录的内容要多得多,但这应该提供一个很好的开始: 默认行为 考虑一个简单的属性文件…

python安装pygame模块_windows下 python 如何安装pygame模块

本机系统:win7,Pyhon版本: 3.6.0 1. 安装下载python 官网 https://www.python.org/ 下载地址 https://www.python.org/downloads/windows/ 下载后运行并安装。注意: 官网明确表示,3.5及以上版本不支持xp操作系统。要兼…

html文字添加波浪线,利用css渐变给文字下方加波浪线

具体代码如下.wavy-line-decoration {position: relative;line-height: 1.5em;}.wavy-line-decoration::before {content: ;position: absolute;bottom: -3px;width: 100%;height: 0.25em;background: // 可以给同一个元素同时添加多个背景渐变图层,用逗号隔开&…

新旧C++生成随机浮点数方法,你喜欢哪个?

点击蓝字关注我们一、在C11之前,我们通常采用rand函数来生成随机数。有时我们想用rand生成一组随机数,即使我们调用了srand,但生成的还是相同值。为什么会产生这种情况?又该如何解决?下面将用第一视角一起探究这其中的…

arm926ej_EJB超时策略:它们如何提供帮助?

arm926ejEJB 3.1在其API中引入了与超时相关的注释。 AccessTimeout StatefulTimeout 让我们快速看一下它们是什么以及它们为什么重要 AccessTimeout 指定一个排队请求(等待另一个线程完成)超时的时间段。 当您的会话bean实例被并发请求轰炸时&#…

html页面加载完成后会触发的事件_前端隐秘角落 - 页面渲染

前言如图所示,webkit内核浏览器的渲染过程(解析HTML,构建DOM树,解析CSS,构建CSSOM树 ,构建render树,布局layout,绘制painting),这些过程理解起来可能有些抽象,今天我们一…

计算机进管理提示找不到入口,win10系统开机提示xxxdll模块已加载但找不到入口点的教程...

有关win10系统开机提示xxxdll模块已加载但找不到入口点的操作方法想必大家有所耳闻。但是能够对win10系统开机提示xxxdll模块已加载但找不到入口点进行实际操作的人却不多。其实解决win10系统开机提示xxxdll模块已加载但找不到入口点的问题也不是难事,小编这里提示两…

十大经典排序,你真的都会了吗?(源码详解)

点击蓝字关注我们一、前言:排序的概念排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性:假定在待排序的记录序列中,存在多个具有相同的关键…

jvm 架构_不可变的基础架构,热部署和JVM

jvm 架构您是否在生产中部署和取消部署基于JVM的应用程序(无论JVM容器/无容器)? 也就是说,当您拥有某个应用程序或服务的新版本时,是否通过“取消部署”和“热部署”该应用程序的新更新版本来更改正在运行的JVM&#x…

c语言默认参数_5.1 C++有默认参数的函数

点击上方“C语言入门到精通”,选择置顶第一时间关注程序猿身边的故事作者闫小林白天搬砖,晚上做梦。我有故事,你有酒么?C有默认参数的函数在函数调用时形参从实参获取值,因为实参的个数要和形参相同,但有时…