pingを並行処理しようと思った経緯
とある炎上プロジェクトで先輩が私に
「cmdを複数立ち上げてもいいから、全拠点同時にpingを打って疎通確認してほしい。モニターが足りなければ増やしてもいいから実施してね。」
話を聞いた当初は「Expingで良くね?」と思いましたが、Expingは並列でping送信できないんですよね。。。
結局、モニターを追加する余裕もなく宛先が120個ほどありましたので、以下の方法で実施しました。
・Expingの疎通間隔を短くして1拠点2秒~3秒間隔でpingできるように調節
けど正直複数宛先に同時pingは割りと簡単に実装できるのではないのか?と思い、pythonでコードを書いてみました。
multi_subprocess.py
import subprocess
from multiprocessing import Process, Manager
import time
def ping_host(ip, queue):
result = subprocess.run(['ping', ip, '-n', '1', '-w', '1'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
output = result.stdout.strip()
if "TTL=" in output:
queue.put((ip, "○"))
else:
queue.put((ip, "☓"))
def run_parallel_pings(ips):
start_time = time.time()
with Manager() as manager:
queue = manager.Queue()
processes = [Process(target=ping_host, args=(ip, queue)) for ip in ips]
for process in processes:
process.start()
for process in processes:
process.join()
while not queue.empty():
print(queue.get())
end_time = time.time()
print(f"Time taken: {end_time - start_time:.2f} seconds")
if __name__ == '__main__':
with open('ips.txt') as f:
ips = f.read().splitlines()
run_parallel_pings(ips)
ips.txt
192.168.11.1
192.168.11.5
8.8.8.8
1.1.1.1
2.2.2.2
3.3.3.3
4.4.4.4
5.5.5.5
6.6.6.6
7.7.7.7
8.8.8.8
9.9.9.9
0.0.0.0
コード解説
def ping_host(ip, queue):
pingを実施する関数です。
result = subprocess.run(['ping', ip, '-n', '3', '-w', '1'], stdout=subprocess.DEVNULL)
subprocessはコマンドを実行するためのモジュールで、subprocessモジュールを使いpingを実行します。
オプションについて以下に説明を記載します。
-n:パケット送信回数
-w:タイムアウト時間
"stdout=subprocess.DEVNULL"は標準出力を無視することを意味します。なのでcmdにping実施中の表示がされません。
if result.returncode == 0:
result.returncodeに終了結果が格納されており
成功:0
失敗:0以外
となります。
成功すればIPアドレスと”○”が変数queusに格納され、
失敗すればIPアドレスと”☓”が変数queusに格納されます。
def run_parallel_pings(ips):
pingを並列処理する関数です。
processes = [Process(target=ping_host, args=(ip, queue)) for ip in ips]
先程のpingを実行する関数をIPアドレス毎にサブプロセスを作成しています。
for process in processes:
process.start()
先程作成したサブプロセスを実行します。
for process in processes:
process.join()
実行処理が終了したサブプロセスをメインプロセスへ戻します。
while not queue.empty():
print(queue.get())
サブプロセスが全て終了していることを確認して、
終了している場合は、サブプロセス毎の結果を表示する。
with open('ips.txt') as f:
ips = f.read().splitlines()
ips.txtに記載しているIPアドレスをリスト化します。
表示結果
('192.168.11.1', '○')
('192.168.11.5', '○')
('8.8.8.8', '○')
('8.8.8.8', '○')
('0.0.0.0', '☓')
('1.1.1.1', '○')
('9.9.9.9', '○')
('3.3.3.3', '☓')
('2.2.2.2', '☓')
('7.7.7.7', '☓')
('4.4.4.4', '☓')
('6.6.6.6', '☓')
('5.5.5.5', '☓')
Time taken: 4.33 seconds
pingは1回1秒間隔で3回実施なので理論値3秒で表示されるはずですが、結果は4秒で表示されました。
まとめ
並列処理はできましたがping処理が1回きりなのでこれでは先輩は満足しないでしょう。
なので次は以下を実装します。
・ExpingのようなGUIで表示