今さらPython3 (77) - インターネットサービス

第11章継続中。

入門 Python 3

入門 Python 3

インターネットサービスの自動化手法についてのドキュメントがここにある。

21. Internet Protocols and Support — Python 3.5.1 documentation

この先は、手を動かせるモノを順にやっていくつもり。

DNS

>>> import socket
>>> socket.gethostbyname('www.crappytaxidermy.com')
'66.6.44.4'
>>> socket.gethostbyname_ex('www.crappytaxidermy.com')
('crappytaxidermy.com', ['www.crappytaxidermy.com'], ['66.6.44.4'])
>>> socket.gethostbyname('www.google.co.jp')
'216.58.196.227'

ちなみに、taxidermyとは剥製のことらしいっす。(この情報、今必要か?)
socket.gethostbyname()でIPアドレスが返ってきて、socket.gethostbyname_ex()だとさらに詳細みたいな。

>>> socket.getaddrinfo('www.crappytaxidermy.com', 80)
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_DGRAM: 2>, 17, '', ('66.6.44.4', 80)), (<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('66.6.44.4', 80))]

socket.getaddrinfo()では、ソケットを作るのに必要な情報が取得できる。2つのタプルが返ってきて、1つ目がUDP、2つ目がTCP/IP用とのこと。本に書いてあるよりも詳細な情報が出ている。

>>> socket.getaddrinfo('www.crappytaxidermy.com', 80, socket.AF_INET, socket.SOCK_STREAM)
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('66.6.44.4', 80))]

これは、さっきの2つ目の情報だけが戻って来ているので、TCP/IP用の情報を取得したと理解できる。

>>> socket.getservbyname('http')
80
>>> socket.getservbyport(80)
'http'
>>> socket.getservbyname('gopher')
70

一番下のが分かる人は、ネット20年ぐらいうろついている人だねw。

電子メール

あんまりメール使わなくなったんじゃない?とは言え、ドキュメントのありかぐらいは押さえておかねば。

19.1.14. email: Examples — Python 3.5.1 documentation

  • smtplib : メール送信用
  • email : メール作成、構文解析
  • poplib : POP3で電子メールメッセージを読み出す
  • imaplib : IMAPで電子メールメッセージを読み出す

リモート処理

リモートファンクションコール(RFC)というのは聞いたことあるけど、Remote Procedure Callというのは初めて聞いたかも。xmlrpcという標準ライブラリを使った実験を試してみる。

サーバーを先に起動した状態からクライアントを実行。

$ python3 xmlrpc_client.py
Double 7 is 14

7の2倍を計算するのに行って帰ってきたわけですね。

$ python3 xmlrpc_server.py
127.0.0.1 - - [28/Dec/2015 15:11:43] "POST / HTTP/1.1" 200 -

これはサーバー側に出てきた情報。

今度は、msgpack-rpc-pythonを使った例。

サーバーを起動して、

$ python3 msppack_server.py

クライアントを起動。

$ python3 msppack_client.py
Double 8 is 16

はい、よく出来ましたw。ちなみに、サーバを落としたまま、クライアントを実行すると、こうなる。

$ python3 msppack_client.py
WARNING:tornado.general:Connect error on fd 9: ECONNREFUSED
WARNING:tornado.general:Connect error on fd 9: ECONNREFUSED
WARNING:tornado.general:Connect error on fd 9: ECONNREFUSED
WARNING:tornado.general:Connect error on fd 9: ECONNREFUSED
WARNING:tornado.general:Connect error on fd 9: ECONNREFUSED
Traceback (most recent call last):
  File "msppack_client.py", line 5, in <module>
    result = client.call("double", num)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/msgpackrpc/session.py", line 41, in call
    return self.send_request(method, args).get()
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/msgpackrpc/future.py", line 43, in get
    raise self._error
msgpackrpc.error.TransportError: Retry connection over the limit

fabric

本の情報によれば、fabricのPython3対応はもうすぐ終わるというような話だったが、果たしてどうだろう?

$ pip3 install fabric
...(長いので省略)...
Installing collected packages: pycrypto, ecdsa, paramiko, fabric
Successfully installed ecdsa-0.13 fabric-1.10.2 paramiko-1.16.0 pycrypto-2.6.1

問題なくインストールできたので、動かしてみたが、サンプルがまるで動かず。そこでpypiを確認したところ、Python3に対応しているという内容は確認できず。

Fabric 1.10.2 : Python Package Index

さらに別の資料を読み進めると、SSH的な部分はInvokeとして分割して、すでにPython3 compatibleになっているとのこと。

Frequently asked questions — Invoke documentation

Invoke自体はpip3でインストールできたものの、本のサンプルの通りに進めてみても、こんな感じで怒られてしまう。

$ invoke -f fab1.py -H localhost iso
Can't find any collection named 'tasks'!

残念ながら、この部分はskipして先に進めることにしようと思う。

(つづく)


ちなみに、同じようなことを繰り返している間に、ポート6789が捕まれたままになってしまったので、使われているポートとそれを開放する時の手順を備忘として残しておく。

$ sudo lsof -i -P | grep "LISTEN"
Password:
launchd       1           root    9u  IPv6 0x693ad74c8fbd54cb      0t0    TCP *:548 (LISTEN)
launchd       1           root   10u  IPv6 0x693ad74c8fbd54cb      0t0    TCP *:548 (LISTEN)
launchd       1           root   11u  IPv4 0x693ad74c8fbdb41b      0t0    TCP *:548 (LISTEN)
launchd       1           root   12u  IPv4 0x693ad74c8fbdb41b      0t0    TCP *:548 (LISTEN)
launchd       1           root   29u  IPv6 0x693ad74c8fbd4fcb      0t0    TCP *:5900 (LISTEN)
launchd       1           root   31u  IPv4 0x693ad74c8fbdab4b      0t0    TCP *:5900 (LISTEN)
launchd       1           root   32u  IPv6 0x693ad74c8fbd4fcb      0t0    TCP *:5900 (LISTEN)
launchd       1           root   33u  IPv4 0x693ad74c8fbdab4b      0t0    TCP *:5900 (LISTEN)
launchd       1           root   37u  IPv6 0x693ad74c8fbd4acb      0t0    TCP localhost:631 (LISTEN)
launchd       1           root   42u  IPv4 0x693ad74c8fbda27b      0t0    TCP localhost:631 (LISTEN)
launchd       1           root   55u  IPv4 0x693ad74c8fbda27b      0t0    TCP localhost:631 (LISTEN)
launchd       1           root   56u  IPv6 0x693ad74c8fbd4acb      0t0    TCP localhost:631 (LISTEN)
mtmfs        67           root    4u  IPv4 0x693ad74c8fbd880b      0t0    TCP localhost:49152 (LISTEN)
mtmfs        67           root    6u  IPv4 0x693ad74c8fbd90db      0t0    TCP localhost:49153 (LISTEN)
httpd        73           root    4u  IPv6 0x693ad74c8fbd3bcb      0t0    TCP *:80 (LISTEN)
kdc          85           root    6u  IPv6 0x693ad74c8fbd45cb      0t0    TCP *:88 (LISTEN)
kdc          85           root    8u  IPv4 0x693ad74c8fbd99ab      0t0    TCP *:88 (LISTEN)
awacsd      151           root    9u  IPv6 0x693ad74c8fbd31cb      0t0    TCP [fdf3:9d69:adbd:6df1:4122:b5eb:ced6:d08d]:4488 (LISTEN)
httpd       191           _www    4u  IPv6 0x693ad74c8fbd3bcb      0t0    TCP *:80 (LISTEN)
kill -9 6789
Eye-Fi      371            ken   20u  IPv4 0x693ad74c97f16d9b      0t0    TCP *:59278 (LISTEN)
httpd       454           _www    4u  IPv6 0x693ad74c8fbd3bcb      0t0    TCP *:80 (LISTEN)
pycharm    1580            ken   88u  IPv4 0x693ad74c9032a80b      0t0    TCP localhost:6942 (LISTEN)
pycharm    1580            ken  189u  IPv4 0x693ad74c930be80b      0t0    TCP localhost:63342 (LISTEN)
Python    13729            ken   14u  IPv4 0x693ad74c930bf9ab      0t0    TCP localhost:6789 (LISTEN)

一番下にポート6789を掴んでいる(この例だとPID 13729)がいたので、お引き取り願う。

$ kill -9 13729

するとこんな結果がひょこっと現れる。この人がずっと掴んでいた訳ですね。

[1]+  Killed: 9               python3 zmq_server.py


(つづく)