1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Python】複数宛先に対して同時にping送信してみた

Last updated at Posted at 2023-02-12

 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で表示

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?