船井総研デジタルのよもぎたです。
PythonのPing3パッケージのソースコードを調べたので、わかったこと、主に関数の使い方についてまとめておきます。
Ping3パッケージはVer.4.0.4を確認しています。Ping3パッケージのPyPIのページはこちら、ソースコードはGitHub上のこちらのリポジトリになります。
概要
- GitHubのREADMEのGet Startedにある
ping
とverbose_ping
を押さえておけばよい。 -
ping
が1回Pingを実行する(ICMP Echo Requestを送信してICMP Echo Replyを受信する)。 -
verbose_ping
はping
をラッピングしている。結果は標準出力に出力される。 - IPv6には対応していない。
ping
引数
必須のもの
-
dest_addr
: Pingの宛先をIPアドレスまたはFQDNで指定します。
任意のもの
-
timeout
:Pingのタイムアウト値を整数で指定します。単位は秒で、デフォルトは4秒です。 -
unit
:戻り値の単位を文字列で指定します。指定できる値はs
の秒と、ms
のミリ秒です。デフォルトはs
です。 -
src_addr
:Pingの送信元となるIPアドレスを文字列で指定します。デフォルトはNone
です。 -
interface
:Pingの送信元となるインターフェース(NIC)を文字列で指定します。デフォルトはNone
です。この引数は、OSがLinuxの場合にだけ指定できます。 -
ttl
: 送信するICMP Echo RequestのTTL(Time to Live)の値を整数で指定します。デフォルトはNone
で、その場合はOSのデフォルト値が使われます。Windowsの場合は128、Linuxの場合は64になります。 -
seq
:送信するICMP Echo Requestのシーケンス番号を整数で指定します。デフォルトは0になります。 -
size
:送信するICMP Echo Requestのペイロードの大きさを整数で指定します。単位はバイトで、デフォルトは56です。
戻り値
あて先からの応答時間がfloat
で返されます。デフォルトはの単位は秒で、unit
引数でms
を指定した場合はミリ秒になります。
タイムアウトになった場合はNone
が返されます。それ以外の何らかのエラーの場合には、False
が返されます。
例外
Ping3モジュールはsocket
モジュールを使用しています。SocketのタイプとしてまずSOCK_RAW
でインスタンスの作成を試みて、失敗した場合はSOCK_DGRAM
でインスタンスの作成を試みます。どちらも失敗した場合、PermissionError
例外が投げられます。
verbose_ping
引数
必須のもの
-
dest_addr
:Pingの宛先をIPアドレスまたはFQDNで指定します。
任意のもの
-
count
:Pingを実行する回数を整数で指定します。デフォルト値は4です。0を指定すると無限に実行します。 -
interval
:Pingを実行する間隔を整数で指定します。単位は秒で、デフォルト値は0です。0が指定されるとPingに応答があり次第即次のPingが実行されます。
その他、ping
と同じ引数が指定できます。
戻り値
メソッドとしての戻り値は無くて、代わりにPingの実行結果(応答時間 or タイムアウト or エラー)が標準出力に出力されます。
余談
このパッケージを調べたキッカケはPythonでPing監視を実行したかったからです。監視要件に沿って複数回Pingを実行できるようにするつもりだったのですが、結果が標準出力に出力されてしまうとちょっと扱いにくいですね。
デバッグモード
ping3.DEBUG = True
とすると、デバッグモードが有効になります。細かくデバッグメッセージの出力が埋め込まれていて、True
にするとメッセージが標準出力に出力されます。
テストスクリプト
import ping3
ping3.DEBUG = True
ping3.ping('www.example.com')
実行例
$ python test_ping.py
[DEBUG] Ping3 Version: 4.0.4
[DEBUG] LOGGER: <Logger ping3 (DEBUG)>
[DEBUG] Function called: ping(www.example.com)
[DEBUG] `[Errno 1] Operation not permitted` when create socket.SOCK_RAW, using socket.SOCK_DGRAM instead.
[DEBUG] Function called: send_one_ping({'sock': <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=1, laddr=('0.0.0.0', 0)>, 'dest_addr': 'www.example.com', 'icmp_id': 51073, 'seq': 0, 'size': 56})
[DEBUG] Destination address: 'www.example.com'
[DEBUG] Destination IP address: 93.184.216.34
[DEBUG] Sent ICMP header: {'type': 8, 'code': 0, 'checksum': 8998, 'id': 51073, 'seq': 0}
[DEBUG] Sent ICMP payload: b'A\xd9C\xb3\xe7\xc9\x00bQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ'
[DEBUG] Function returned: send_one_ping -> None
[DEBUG] Function called: receive_one_ping({'sock': <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=1, laddr=('0.0.0.0', 37)>, 'icmp_id': 51073, 'seq': 0, 'timeout': 4})
[DEBUG] Unprivileged on Linux
[DEBUG] Timeout time: Sat Sep 23 20:44:35 2023 (1695469475.141067)
[DEBUG] Timeout left: 4.00s
[DEBUG] Received time: Sat Sep 23 20:44:31 2023 (1695469471.3031929))
[DEBUG] Received ICMP header: {'type': 0, 'code': 0, 'checksum': 62082, 'id': 37, 'seq': 0}
[DEBUG] Received ICMP payload: b'A\xd9C\xb3\xe7\xc9\x00bQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ'
[DEBUG] Received sent time: Sat Sep 23 20:44:31 2023 (1695469471.1406484)
[DEBUG] Function returned: receive_one_ping -> 0.16254448890686035
[DEBUG] Function returned: ping -> 0.16254448890686035
ちなみに上の例は一般ユーザーで実行していて、socket.SOCK_RAW
が使えずにsocket.DGRAM
で実行していることが分かります。同じスクリプトをrootで実行すると、次のようにsocket.RAW
で実行していることが分かります。
# python test_ping.py
[DEBUG] Ping3 Version: 4.0.4
[DEBUG] LOGGER: <Logger ping3 (DEBUG)>
[DEBUG] Function called: ping(www.example.com)
[DEBUG] Function called: send_one_ping({'sock': <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_RAW, proto=1, laddr=('0.0.0.0', 1)>, 'dest_addr': 'www.example.com', 'icmp_id': 57200, 'seq': 0, 'size': 56})
[DEBUG] Destination address: 'www.example.com'
[DEBUG] Destination IP address: 93.184.216.34
[DEBUG] Sent ICMP header: {'type': 8, 'code': 0, 'checksum': 59052, 'id': 57200, 'seq': 0}
[DEBUG] Sent ICMP payload: b'A\xd9C\xb3\xf6W\x16^QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ'
[DEBUG] Function returned: send_one_ping -> None
[DEBUG] Function called: receive_one_ping({'sock': <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_RAW, proto=1, laddr=('0.0.0.0', 1)>, 'icmp_id': 57200, 'seq': 0, 'timeout': 4})
[DEBUG] Timeout time: Sat Sep 23 20:45:33 2023 (1695469533.3609657)
[DEBUG] Timeout left: 4.00s
[DEBUG] Received time: Sat Sep 23 20:45:29 2023 (1695469529.504645))
[DEBUG] Received IP header: {'version': 69, 'tos': 0, 'len': 84, 'id': 0, 'flags': 16384, 'ttl': 44, 'protocol': 1, 'checksum': 46826, 'src_addr': '93.184.216.34', 'dest_addr': '172.17.181.210'}
[DEBUG] Received ICMP header: {'type': 0, 'code': 0, 'checksum': 61100, 'id': 57200, 'seq': 0}
[DEBUG] Received ICMP payload: b'A\xd9C\xb3\xf6W\x16^QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ'
[DEBUG] Received sent time: Sat Sep 23 20:45:29 2023 (1695469529.3607402)
[DEBUG] Function returned: receive_one_ping -> 0.1439049243927002
[DEBUG] Function returned: ping -> 0.1439049243927002
EXCEPTIONSモード
Pingに応答がなかった時にping
メソッドがFalese
やNone
を返さずに例外を投げるようにするEXCEPTIONS
モードがあります。
たとえば、存在しないFQDNに向かってPingを実行すると次のようになります。
テストスクリプト
import ping3
ping3.EXCEPTIONS = True
try:
ping3.ping('no.such.domain')
except Exception as e:
print(e)
実行例
$ python test2_ping.py
Cannot resolve: Unknown host. (Host='no.such.domain')
以上です、最後までお読みいただきありがとうございました。