LoginSignup
0
0

PythonのPing3パッケージのソースコードを読んで分かったことのメモ

Posted at

船井総研デジタルのよもぎたです。

PythonのPing3パッケージのソースコードを調べたので、わかったこと、主に関数の使い方についてまとめておきます。

Ping3パッケージはVer.4.0.4を確認しています。Ping3パッケージのPyPIのページはこちら、ソースコードはGitHub上のこちらのリポジトリになります。

概要

  • GitHubのREADMEのGet Startedにある pingverbose_ping を押さえておけばよい。
  • ping が1回Pingを実行する(ICMP Echo Requestを送信してICMP Echo Replyを受信する)。
  • verbose_pingping をラッピングしている。結果は標準出力に出力される。
  • 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にするとメッセージが標準出力に出力されます。

テストスクリプト

test_ping.py
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メソッドがFaleseNoneを返さずに例外を投げるようにするEXCEPTIONSモードがあります。

たとえば、存在しないFQDNに向かってPingを実行すると次のようになります。

テストスクリプト

test2_ping.py
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')

以上です、最後までお読みいただきありがとうございました。

0
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
0
0