使用Python根据网速自动切换网关
公司里装了两条不同的宽带,根据使用的情况,比如拨VPN,或者使用人数过多,网速不行了就要切换下。每次手动去切换很不方便,而且网速也很难判断。这里分享下如何用Python检测网速,然后自动切换网关。参考原文:How to Change Windows Gateway by Broadband Speedin Python作者:Xiao Ling翻译:yushulx
公司里装了两条不同的宽带,根据使用的情况,比如拨VPN,或者使用人数过多,网速不行了就要切换下。每次手动去切换很不方便,而且网速也很难判断。这里分享下如何用Python检测网速,然后自动切换网关。
参考原文:How to Change Windows Gateway by Broadband Speed in Python
作者:Xiao Ling
翻译:yushulx
使用speedtest-cli测试网速
相信很多人都用过speedtest.net来测试网络速度,speedtest-cli是一个Python开源项目。通过链接speedtest.net来检测上传速度和下载速度。
安装
1
|
pip install speedtest
-
cli
|
或者
1
|
easy_install speedtest
-
cli
|
测试网速
安装之后就可以通过命令行来测试下网速:
1
|
speedtest
-
cli
-
-
bytes
|
根据log我们大概可以推测下这个程序的工作步骤:
-
从speedtest.net读取配置文件。
-
获得一个server列表。
-
找到最近的server作为最优选择用来测试速度。
这种最优方式适合检测网络的最大下载速度。而我现在需要的是根据网络访问速度切换网关,比如我需要经常访问国外某个网站,这个最大下载速度就没有意义了。要检测速度,我可以随意设置一些这个网站上的图片资源作为测试数据,而并不需要使用speedtest.net。
自定义函数用于检测网速
通过学习源码,我们可以自己重写一个网速测试函数。找到 {Python Installation Directory}\Lib\site-packages\speedtest_cli.py,根据speedtest()创建的函数很简单:
1
2
3
4
5
6
7
8
9
10
|
def
testSpeed(urls):
speedtest_cli.shutdown_event
=
threading.Event()
signal.signal(signal.SIGINT, speedtest_cli.ctrl_c)
print
"Start to test download speed: "
dlspeed
=
speedtest_cli.downloadSpeed(urls)
dlspeed
=
(dlspeed
/
1000
/
1000
)
print
(
'Download: %0.2f M%s/s'
%
(dlspeed,
'B'
))
return
dlspeed
|
原始代码是先找到最佳服务器,然后从上面获取URL资源。这里只需要随便设置我需要的资源:
1
2
3
4
5
|
urls
=
[
"http://www.dynamsoft.com/assets/images/logo-index-dwt.png"
,
"http://www.dynamsoft.com/assets/images/logo-index-dnt.png"
,
"http://www.dynamsoft.com/assets/images/logo-index-ips.png"
,
"http://www.codepool.biz/wp-content/uploads/2015/06/django_dwt.png"
,
"http://www.codepool.biz/wp-content/uploads/2015/07/drag_element.png"
]
|
看看源码中的下载速度是如何计算的?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
def
downloadSpeed(files, quiet
=
False
):
"""Function to launch FileGetter threads and calculate download speeds"""
start
=
timeit.default_timer()
def
producer(q, files):
for
file
in
files:
thread
=
FileGetter(
file
, start)
thread.start()
q.put(thread,
True
)
if
not
quiet
and
not
shutdown_event.isSet():
sys.stdout.write(
'.'
)
sys.stdout.flush()
finished
=
[]
def
consumer(q, total_files):
while
len
(finished) < total_files:
thread
=
q.get(
True
)
while
thread.isAlive():
thread.join(timeout
=
0.1
)
finished.append(
sum
(thread.result))
del
thread
q
=
Queue(
6
)
prod_thread
=
threading.Thread(target
=
producer, args
=
(q, files))
cons_thread
=
threading.Thread(target
=
consumer, args
=
(q,
len
(files)))
start
=
timeit.default_timer()
prod_thread.start()
cons_thread.start()
while
prod_thread.isAlive():
prod_thread.join(timeout
=
0.1
)
while
cons_thread.isAlive():
cons_thread.join(timeout
=
0.1
)
return
(
sum
(finished)
/
(timeit.default_timer()
-
start))
|
-
在线程中读取读取图片资源。
-
把线程放入阻塞的队列中。
-
从队列中把线程的结果一个个读取出来。
-
speed = total file sizes / total time cost
查询网络适配器设置,并设置网关
如何用Python设置网关?在StackOverflow上可以找到解答。推荐的方法是使用WMI (Windows Management Instrumentation)。
安装
WMI
Python for Windows Extensions
Win32网络适配器设置
很多人的电脑上会看到很多的网络适配器,比如无线网卡的,虚拟网卡的,以太网卡的等等。每个适配器都有很多属性,看下微软的定义Win32_NetworkAdapterConfiguration class::
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
[Provider(
"CIMWin32"
)]
class
Win32_NetworkAdapterConfiguration : CIM_Setting
{
boolean ArpAlwaysSourceRoute;
boolean ArpUseEtherSNAP;
string Caption;
string DatabasePath;
boolean DeadGWDetectEnabled;
string DefaultIPGateway[];
uint8 DefaultTOS;
uint8 DefaultTTL;
string Description;
boolean DHCPEnabled;
datetime DHCPLeaseExpires;
datetime DHCPLeaseObtained;
string DHCPServer;
string DNSDomain;
string DNSDomainSuffixSearchOrder[];
boolean DNSEnabledForWINSResolution;
string DNSHostName;
string DNSServerSearchOrder[];
boolean DomainDNSRegistrationEnabled;
uint32 ForwardBufferMemory;
boolean FullDNSRegistrationEnabled;
uint16 GatewayCostMetric[];
uint8 IGMPLevel;
uint32 Index;
uint32 InterfaceIndex;
string IPAddress[];
uint32 IPConnectionMetric;
boolean IPEnabled;
boolean IPFilterSecurityEnabled;
boolean IPPortSecurityEnabled;
string IPSecPermitIPProtocols[];
string IPSecPermitTCPPorts[];
string IPSecPermitUDPPorts[];
string IPSubnet[];
boolean IPUseZeroBroadcast;
string IPXAddress;
boolean IPXEnabled;
uint32 IPXFrameType[];
uint32 IPXMediaType;
string IPXNetworkNumber[];
string IPXVirtualNetNumber;
uint32 KeepAliveInterval;
uint32 KeepAliveTime;
string MACAddress;
uint32 MTU;
uint32 NumForwardPackets;
boolean PMTUBHDetectEnabled;
boolean PMTUDiscoveryEnabled;
string ServiceName;
string SettingID;
uint32 TcpipNetbiosOptions;
uint32 TcpMaxConnectRetransmissions;
uint32 TcpMaxDataRetransmissions;
uint32 TcpNumConnections;
boolean TcpUseRFC1122UrgentPointer;
uint16 TcpWindowSize;
boolean WINSEnableLMHostsLookup;
string WINSHostLookupFile;
string WINSPrimaryServer;
string WINSScopeID;
string WINSSecondaryServer;
};
|
找到了某个特定属性所对应的值,我们就可以很容易找到目标适配器了。我是这样查找的:
-
右键目标网络适配器。
-
选择配置。
-
点击详细。
-
看一下属性列表及对应的值。
最后选择了设备描述Realtek PCIe GBE Family Controller。
用Python查询Windows IP和网关
1
2
3
|
wmiObj
=
wmi.WMI()
sql
=
"select IPAddress,DefaultIPGateway from Win32_NetworkAdapterConfiguration where Description=\"Realtek PCIe GBE Family Controller\" and IPEnabled=TRUE"
configurations
=
wmiObj.query(sql)
|
设置Windows网关
1
2
3
|
configurations
=
wmiObj.Win32_NetworkAdapterConfiguration(Description
=
"Realtek PCIe GBE Family Controller"
, IPEnabled
=
True
)
configuration
=
configurations[
0
]
ret
=
configuration.SetGateways(DefaultIPGateway
=
[gateway])
|
请注意脚本必须用管理员权限来执行,不然设置会失败。记得查看返回值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
for
gateway
in
gateways:
settingReturn
=
setGateway(wmiObj, gateway)
if
(settingReturn[
0
] !
=
0
):
print
"Setting failed"
return
print
"Set gateway: "
+
gateway
dlspeed
=
testSpeed(urls)
option
=
(gateway, dlspeed)
print
"Network option: "
+
str
(option)
if
(option[
1
] > bestChoice[
1
]):
bestChoice
=
option
|
把Python脚本转换成可执行EXE
如何把Python程序分发给别人使用如果他们并没有安装Python程序以及依赖库?使用Py2exe 可以很容易把Python脚本转换成exe文件。
安装
转换Python脚本
新建setup.py:
1
2
3
|
from
distutils.core
import
setup
import
py2exe
setup(console
=
[
'network.py'
])
|
执行下面的命令:
1
|
python setup.py py2exe
|
目录中会生成一个dist 文件夹:
记得执行程序的时候必须要用管理员权限。
源码
更多推荐
所有评论(0)