公司里装了两条不同的宽带,根据使用的情况,比如拨VPN,或者使用人数过多,网速不行了就要切换下。每次手动去切换很不方便,而且网速也很难判断。这里分享下如何用Python检测网速,然后自动切换网关。
参考原文:
作者:
翻译:yushulx
使用speedtest-cli测试网速
相信很多人都用过speedtest.net来测试网络速度,是一个Python开源项目。通过链接speedtest.net来检测上传速度和下载速度。
安装
pip install speedtest-cli
或者
easy_install speedtest-cli
测试网速
安装之后就可以通过命令行来测试下网速:
speedtest-cli --bytes
根据log我们大概可以推测下这个程序的工作步骤:
从speedtest.net读取配置文件。
获得一个server列表。
找到最近的server作为最优选择用来测试速度。
这种最优方式适合检测网络的最大下载速度。而我现在需要的是根据网络访问速度切换网关,比如我需要经常访问国外某个网站,这个最大下载速度就没有意义了。要检测速度,我可以随意设置一些这个网站上的图片资源作为测试数据,而并不需要使用speedtest.net。
自定义函数用于检测网速
通过学习源码,我们可以自己重写一个网速测试函数。找到 {Python Installation Directory}\Lib\site-packages\speedtest_cli.py,根据speedtest()创建的函数很简单:
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资源。这里只需要随便设置我需要的资源:
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"]
看看源码中的下载速度是如何计算的?
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)。
安装
Win32网络适配器设置
很多人的电脑上会看到很多的网络适配器,比如无线网卡的,虚拟网卡的,以太网卡的等等。每个适配器都有很多属性,看下微软的定义::
[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和网关
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网关
configurations = wmiObj.Win32_NetworkAdapterConfiguration(Description="Realtek PCIe GBE Family Controller", IPEnabled=True)configuration = configurations[0]ret = configuration.SetGateways(DefaultIPGateway=[gateway])
请注意脚本必须用管理员权限来执行,不然设置会失败。记得查看返回值。
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:
from distutils.core import setupimport py2exesetup(console=['network.py'])
执行下面的命令:
python setup.py py2exe
目录中会生成一个dist 文件夹:
记得执行程序的时候必须要用管理员权限。