使用Python根据网速自动切换网关

公司里装了两条不同的宽带,根据使用的情况,比如拨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我们大概可以推测下这个程序的工作步骤:

  1.  从speedtest.net读取配置文件。

  2. 获得一个server列表。

  3. 找到最近的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
  
     =  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))
 
  1. 在线程中读取读取图片资源。

  2. 把线程放入阻塞的队列中。

  3. 从队列中把线程的结果一个个读取出来。

  4. 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;
};
 

找到了某个特定属性所对应的值,我们就可以很容易找到目标适配器了。我是这样查找的:

  1. 右键目标网络适配器。

  2. 选择配置。

  3. 点击详细。

  4. 看一下属性列表及对应的值。

最后选择了设备描述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文件。

安装

Py2exe

转换Python脚本

新建setup.py:

?
1
2
3
from  distutils.core  import  setup
import  py2exe
setup(console = [ 'network.py' ])
 

执行下面的命令:

?
1
python setup.py py2exe

目录中会生成一个dist 文件夹:

记得执行程序的时候必须要用管理员权限。

源码

https://github.com/yushulx/switch-windows-gateway

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值