python3 线程池实现批量ping某一网段,获得可用ip列表——futures模块

作者: 杰克小麻雀
原文链接: https://blog.csdn.net/yushuaigee/article/details/85244394

需求

工作中需要找出指定网段里,哪些ip是没被占用的,然后使用这些ip。

实现方法很简单,就是依次ping一下,看看哪些是不通的,就代表没被占用。ping是很耗时间的,于是想到多线程,考虑到线程数量多且每个线程的任务很简单,所以使用线程池。参考了网上博主的代码,原文链接:《Python多线程批量Ping主机IP的脚本》,主要学到了Python队列queue的概念和后台调用cmd控制台的方法。

我的代码如下:

第一个参数net_segment代表要查找的网段,

第二个参数ip_num代表所需 ip 的数量。

通过修改max_workers=100 的值可以调整程序运行的速度。

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
import time
import threading
import subprocess
from queue import Queue
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED

def get_ip_list(net_segment, ip_num):
# 创建一个队列
IP_QUEUE = Queue()
ip_list = []
list_segment = net_segment.split('.')
ip_index = 1
# 将需要 ping 的 ip 加入队列
for i in range(1, 254):
list_segment[-1] = str(ip_index + i)
addr = ('.').join(list_segment)
IP_QUEUE.put(addr)

# 定义一个执行 ping 的函数
def ping_ip(ip):
res = subprocess.call('ping -n 2 -w 5 %s' % ip, stdout=subprocess.PIPE) # linux 系统将 '-n' 替换成 '-c'
# 打印运行结果
print(ip, True if res == 0 else False)
if res != 0:
if lock.acquire():
if len(ip_list) < ip_num:
ip_list.append(ip)
lock.release()

# 创建一个最大任务为100的线程池
pool = ThreadPoolExecutor(max_workers=100)
lock = threading.Lock()
start_time = time.time()
all_task = []
while not IP_QUEUE.empty():
all_task.append(pool.submit(ping_ip, IP_QUEUE.get()))
# 等待所有任务结束
wait(all_task, return_when=ALL_COMPLETED)
print('ping耗时:%s' % (time.time() - start_time))
if len(ip_list) < ip_num:
print("Warning:当前网段可用ip不够,需要数量:%s,可用数量:%s" % (str(ip_num), str(len(ip_list))))
return ip_list


if __name__ == '__main__':
ip_list = get_ip_list("202.169.50.0", 200)
print(ip_list)
print(len(ip_list))

部分运行结果:

202.169.50.238 False
202.169.50.253 False
202.169.50.239 False
202.169.50.230 False
ping耗时:6.348670959472656
Warning:当前网段可用ip不够,需要数量:200,可用数量:168
[‘202.169.50.3’, ‘202.169.50.20’, ‘202.169.50.19’, ‘202.169.50.78’,…………………………………………………………]
168

优化

代码稍作修改,可以查看某两个ip之间哪些地址ping的通,哪些ping不通。

这里用到处理ip地址的标准库 ipaddress 模块,来处理ip地址的计算。

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
import time
import threading
import subprocess
from queue import Queue
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
from ipaddress import ip_address


def get_ip_list(ip_start, ip_end):
# 创建一个队列
IP_QUEUE = Queue()
ip_used = []
ip_not_used = []
ip_start = ip_address(ip_start)
ip_end = ip_address(ip_end)
while ip_start <= ip_end:
IP_QUEUE.put(str(ip_start))
ip_start += 1

# 定义一个执行 ping 的函数
def ping_ip(ip):
res = subprocess.call('ping -n 2 -w 5 %s' % ip, stdout=subprocess.PIPE) # linux 系统将 '-n' 替换成 '-c'
# 打印运行结果
print(ip, True if res == 0 else False)
if lock.acquire():
if res == 0:
ip_used.append(ip)
else:
ip_not_used.append(ip)
lock.release()

# 创建一个最大任务为100的线程池
pool = ThreadPoolExecutor(max_workers=120)
lock = threading.Lock()
start_time = time.time()
all_task = []
while not IP_QUEUE.empty():
all_task.append(pool.submit(ping_ip, IP_QUEUE.get()))
# 等待所有任务结束
wait(all_task, return_when=ALL_COMPLETED)
print('ping耗时:%s' % (time.time() - start_time))
return ip_used, ip_not_used


if __name__ == '__main__':
ip_used, ip_not_used = get_ip_list("202.169.50.1", "202.169.51.255")
print(str(len(ip_used))+"已用", "\n", ip_used)
print(str(len(ip_not_used))+"未用", "\n", ip_not_used)

部分运行结果:

202.169.51.222 False
202.169.51.249 False
202.169.51.200 False
202.169.51.208 False
ping耗时:10.248608827590942
86已用
 [‘202.169.50.2’, ‘202.169.50.8’, ‘202.169.50.7’,…………………………………………]
425未用
 [‘202.169.50.3’, ‘202.169.50.19’, ‘202.169.50.78’…………………………………………]

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2020-2021 杰克小麻雀
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信