首先参考了这个实现
它是开多线程来调用cmd ping
LZ选择用subprocess.Popen,让子进程通过管道将输入缓存到系统buffer中。Popen会返回一个对象,可以通过它与子进程交互,获取其状态等。轮询Popen对象判断ping是否结束,进而检查echo信息判断,得到在线主机列表。。
速度比多线程快很多,扫描1-255只需要不到10s
#-*- coding: utf-8 -*-
import platform
import sys
import os
import time
import thread
from subprocess import Popen, PIPE
# 传入ip地址,调用 cmd ping, 返回 Popen 对象
# 指定ping的stdout通过管道写入设定的buffer中
def invoke_ping(addr):
# windows 的参数和linux下不同
cmd = ['ping', '-n', '1', addr]
ret = 0
try:
ret = Popen(cmd, bufsize=1024, stdout=PIPE)
except ValueError:
print 'error occur in invoke_ping: ' + addr
return ret
# 简单地通过 ping 回显信息检查是否在线
def check_online(popen_obj):
echo = popen_obj.communicate()[0].split('\n')
if len(echo) >= 3:
print echo[2]
ttl_pos = echo[2].find('TTL')
if ttl_pos != -1:
ms_pos = echo[2].find('ms')
i = ms_pos - 1
while i > 0 and echo[2][i:i+1].isdigit() == True:
i -= 1
ti = int(echo[2][i+1:ms_pos])
ttl = int(echo[2][ttl_pos + 4:])
return (ti, ttl)
return tuple()
def ping_scan(dst):
oks = []
scq = {}
net_addr = dst.split('.')
for i in range(0, 256):
net_addr[3] = str(i)
tmp = invoke_ping( '.'.join(net_addr) )
if type(tmp) != int:
scq[i] = tmp
while len(scq) != 0:
to_be_removed = []
for k, v in scq.items():
if v.poll() != None:
ret = check_online(v)
if len(ret) > 0:
net_addr[3] = str(k)
oks.append( ( k, ret) )
to_be_removed.append( k )
for i in to_be_removed:
scq.pop(i)
return oks
if __name__ == '__main__':
start_time = time.clock()
dst_net = '172.30.58.229'
online_list = ping_scan(dst_net)
online_list.sort()
prefix = '.'.join( dst_net.split('.')[0:3] )
for i in online_list:
fmt = '%s time=%dms ttl=%d'
print fmt % ( prefix+'.'+str(i[0]), i[1][0], i[1][1] )
print '%d hosts in total' % len(online_list)
print 'process time: %lfs' % (time.clock() - start_time)