今さらPython3 (76) - ネットワーク

引き続き11章。

入門 Python 3

入門 Python 3

ネットワークの基本的なところを追いかけるのは、ここの主旨と違うのでPythonで手を動かせるところをカバーしていく。

UDP

まずは、udp_server.pyから。socket.socket()でソケットを作る、つまり口を開けるてな感じで、bind()のところでバインドすると言われてもそのままなので、ソケットに届いたデータを聞いてやるという意味と理解。recvfromでスタンバイOKってとこか。実際にデータを受け取ると、「呼んだ?」と送り返したらサーバーはクローズ。

udp_client.pyもだいたい同じだけど、ソケットを作って、サーバーに挨拶したら、こっちもお返事待ちの状態に入り、返事を受け取ったら終了しますってな具合だね。

サーバー側。

$ python3 udp_server.py
Starting the server at 2015-12-28 11:38:53.558049
Waiting for a client to call.
At 2015-12-28 11:39:41.591555 ('127.0.0.1', 49889) said b'Hey!'
$

49889はクライアントのポート番号で、挨拶されたよという内容が出力されている。

クライアント側。

$ python3 udp_client.py
Starting the client at 2015-12-28 11:39:41.588752
At 2015-12-28 11:39:41.591683 ('127.0.0.1', 6789) said b'Are you talking to me?'
$

サーバーは自分で6789というポート番号を指定していたので、この番号でもってお返事したということ。

TCP/IP

UDPは高速だけど到達を保証しないという問題があるので、接続を確立してやりとりするTCP/IPを使いましょうということだね。

変わったところは、socketの引数の1つがSOCK_STREAMになっているのは、TCP/IPになったからだよね。

例によって、server側から起動して、

$ python3 tcp_server.py
Starting the server at 2015-12-28 12:15:25.317374
Waiting for a client to call.
At 2015-12-28 12:15:36.944858 <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6789), raddr=('127.0.0.1', 53646)> said b'Hey!'

client側を後から起動する。

$ python3 tcp_client.py
Starting the client at 2015-12-28 12:15:36.941942
At 2015-12-28 12:15:36.944994 someone replied b'Are you talking to me?'
$

実際に、このレベルのプログラミングが必要になるかどうかは微妙だけど、その時は、この文書を読むようにするつもり。
Socket Programming HOWTO — Python 3.5.1 documentation

ZeroMQ再び

前回触ったZeroMQはパブサブ(この略語はあまり好きじゃない)だけでなく、強化版ソケットとしても使えるということで再登場なんですね。ここには、Pythonのサンプルもいっぱい載っているそうなので、必要になったときのためにリンクを張っておく。

bit.ly

インストール済なので、さっそく試してみる。

Gistの関係で、クライアント側が上に出ているけど、サーバー側のソース(zqm_server.py)から見る。socketを作るときの引数にzmq.REPという同期応答が指定されている事以外は、これまで見てきたものと大差なく見える。一方のクライアント側(zmq_client.py)を見ると、ソケットの引数がzmq.REQ(同期要求)になっているところが目立つかな。メッセージを送って、戻りを受け取ってと言うあたりは、これまでも一緒。

サーバー、クライアントの順に起動するとこうなる。

$ python3 zmq_server.py &
[1] 13729
python3 zmq_client.py
That voice in my head says: message #1
Sent message #1, received Stop saying: message #1
That voice in my head says: message #2
Sent message #2, received Stop saying: message #2
That voice in my head says: message #3
Sent message #3, received Stop saying: message #3
That voice in my head says: message #4
Sent message #4, received Stop saying: message #4
That voice in my head says: message #5
Sent message #5, received Stop saying: message #5

&を使ってバックグラウンド処理にしているので、同じウィンドウからクライアントも起動できる。

$ python3 zmq_server.py
Traceback (most recent call last):
  File "zmq_server.py", line 7, in <module>
    server.bind("tcp://%s:%s" % (host, port))
  File "zmq/backend/cython/socket.pyx", line 487, in zmq.backend.cython.socket.Socket.bind (zmq/backend/cython/socket.c:5156)
  File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:7535)
zmq.error.ZMQError: Address already in use

いちおう、別ウィンドウでサーバーをもう1つ起動したときの怒られ方も確認。

あとは、本を読んでいて気がついたところを拾い読み。

このやりとりでは、文字列だけを使っていたので、encode/decodeで対応すれば良かったけど、他のデータ型を含む場合は、MessagePackなるものがあるらしい。

MessagePack: It's like JSON. but fast and small.

ZeroMQにブローカーを持たせるイメージ図だけど、あれはサービスA, B, C側にあるのはREQではなくてREPのような気がする。

scapyは、python3で一応使えるようになったみたい。みたいというのは、インストールだけしてまだ動かしてないから。

phaethon.github.io

サイトには、一応こう説明してある。
This is a fork of scapy (packet dissection and manipulation tool) with added functionality, some bug fixes, and python3 compatibility.

$ pip3 install scapy-python3
Collecting scapy-python3
  Downloading scapy-python3-0.18.tar.gz (2.1MB)
    100% |████████████████████████████████| 2.1MB 261kB/s 
Building wheels for collected packages: scapy-python3
  Running setup.py bdist_wheel for scapy-python3
  Stored in directory: /Users/ken/Library/Caches/pip/wheels/a4/a1/ec/6ca7f94c3f4618af253473dfb86e588e1904f8898d2e805b98
Successfully built scapy-python3
Installing collected packages: scapy-python3
Successfully installed scapy-python3-0.18

とりあえずインストールが煩わしいということもなさそう。

(つづく)