Pingの実行に Subprocess と Ping3 を使ってみた

## subprocessモジュール と ping3モジュールを使ってみる 

### ユースケース
+ 対象のIPアドレスリストに対してpingを実行
+ forループを使って複数回pingを実行

## subprocess モジュール
+ **subprocess.run()** を使ってOS標準のpingコマンドを実行する
+ **subprocess.call()** という**returncode**の結果だけを取ってくる古いモジュールもあるが
  すべての用法を扱える**run()** メソッドが推奨されている。

### subprocessでpingを実行した際の標準出力
```　subprocess_ping.py
>>> import subprocess
>>> subprocess.call(['ping', '8.8.8.8', '-c 1', '-t 1', '-i 0.5'])
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=114 time=6.945 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 6.945/6.945/6.945/0.000 ms
0
>>> 
```


### Subprocessモジュールを使ってPingコマンドを実行

``` ping_code.py
import subprocess

file_path = '/Users/MashCannu/ipAddrList.txt'

with open(file_path) as f:
    ipAddrList = f.readlines()

    for ipAddr in ipAddrList:
        targetIp = ipAddr.rstrip('\n')
        result = subprocess.run(['ping', targetIp, '-c 1', '-t 1' '-i 0.5'],
                                stdout = subprocess.DEVNULL)
        if result.returncode == 0:
            print(f'Host : {targetIp:15} is reachable')
        else:
            print(f'Host : {targetIp:15} is NOT reachable')
```

### 実行結果
``` 
Host : 172.22.0.1      is reachable
Host : 172.22.1.25     is NOT reachable
Host : 172.22.1.30     is reachable
Host : 172.22.1.34     is reachable
Host : 172.22.1.38     is reachable
Host : 172.22.1.81     is NOT reachable
Host : 172.22.1.86     is reachable
Host : 172.22.1.93     is reachable
Host : 172.22.1.109    is reachable
Host : 172.22.1.111    is reachable
Host : 172.22.1.115    is NOT reachable
Host : 172.22.1.119    is reachable
Host : 172.22.1.122    is reachable
Host : 172.22.1.170    is NOT reachable
Host : 172.22.2.11     is reachable
```

## Ping3モジュール
+ pip install ping3 でモジュールインストール
+ **try**〜**except**〜**else**を使用した例外処理
+ ping.EXCEPTION = True をenableにすることで例外処理が可能 
+ Timeout Error、TTL Errorについては、エラー理由を明示
[詳しくはこちら](https://pypi.org/project/ping3/)

### Ping3で実行した際の標準出力

``` ping3.py
>>> from ping3 import ping
>>> ping('8.8.8.8', timeout = 0.5, unit = 'ms')
21.441221237182617
>>> 
```

### Ping3モジュールを使ってPingコマンドを実行

``` ping3_code.py
import ping3
ping3.EXCEPTIONS = True

file_path = '/Users/MashCannu/ipAddrList.txt'

with open(file_path) as f:
    ipAddrList = f.readlines()

    for ipAddr in ipAddrList:
        target_ip = ipAddr.rstrip('\n')
        try:
            result = ping3.ping(target_ip, timeout = 0.5, unit ='ms', ttl = 64)
        except ping3.errors.Timeout:
            print(f'Host : {target_ip:15} is NOT reachable (Timeout)')
        except ping3.errors.TimeToLiveExpired:
            print(f'Host : {target_ip:15} is NOT reachable (TTL)')
        except ping3.errors.PingError:
            print(f'Host : {target_ip:15} is NOT reachable (Error)')
        else:
            print(f'Host : {target_ip:15} is reachable     :{result}(ms)')
```

### 実行結果
```
Host : 172.22.0.1      is reachable     :2.5529861450195312(ms)
Host : 172.22.1.25     is NOT reachable (Timeout)
Host : 172.22.1.30     is reachable     :16.494035720825195(ms)
Host : 172.22.1.34     is reachable     :6.8149566650390625(ms)
Host : 172.22.1.38     is NOT reachable (Timeout)
Host : 172.22.1.81     is NOT reachable (Timeout)
Host : 172.22.1.86     is reachable     :9.799003601074219(ms)
Host : 172.22.1.93     is reachable     :7.737159729003906(ms)
Host : 172.22.1.109    is reachable     :8.95380973815918(ms)
Host : 172.22.1.111    is reachable     :85.27016639709473(ms)
Host : 172.22.1.115    is reachable     :104.54487800598145(ms)
Host : 172.22.1.119    is NOT reachable (Timeout)
Host : 172.22.1.122    is reachable     :4.548072814941406(ms)
Host : 172.22.1.170    is NOT reachable (Timeout)
Host : 172.22.2.11     is reachable     :2.343893051147461(ms)
```

## 考察
+ Ping3はルート権限が必要になるケースがあるが、pythonのモジュールのため例外処理など
  ”らしい”書き方ができる。
+ Linux/macOS、Windowsでpingコマンドのオプションが変わるので注意