5. ネットワーク - TCPソケット

ほとんどのインターネットの構成要素は TCP ソケットです。これらのソケットは、接続されたネットワークデバイス間で信頼できるバイトストリームを提供します。チュートリアルのこの部分では、いくつかの異なるケースで TCP ソケットを使用する方法を示します。

5.1. スターウォーズのテキストアニメーション

最も簡単なことは、インターネットからデータをダウンロードすることです。ここでは、blinkenlights.nl のウェブサイトで提供されているスターウォーズのアシメーションサービスを使用します。これは、ポート 23 上の Telnet プロトコルを使用して、接続するすべての人にデータをストリーミングします。認証する必要がない(ユーザー名またはパスワードを入力する必要がない)ので、データのダウンロードをすぐに開始できで、使い方が簡単です。

最初に行うことは、使用可能なソケットモジュールがあることを確認することです。

>>> import socket

次に、サーバーのIPアドレスを取得します。

>>> addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23)

getaddrinfo 関数は、実際のアドレスのリストを返します。この関数が返す、各アドレスは、必要以上の情報を持っています。最初の有効なアドレスだけを取得し、次にサーバーのIPアドレスとポートだけを取得する必要があります。これを行うには次のようにします:

>>> addr = addr_info[0][-1]

プロンプトで addr_infoaddr だけを入力してみると、これらが保持している情報を確認できます。

IP アドレスを使用してソケットを作成して、サーバに接続します:

>>> s = socket.socket()
>>> s.connect(addr)

これで接続されたので、データをダウンロードして表示できます:

>>> while True:
...     data = s.recv(500)
...     print(str(data, 'utf8'), end='')
...

このループが実行されると、アニメーションの表示が開始されます(中断するには ctrl-C を使います)。

また、普通の Python を使って、このコードを試してみることもできます。

5.2. HTTP GETリクエスト

次の例は、Web ページをダウンロードする方法を示しています。HTTP はポート 80 を使用し、何かをダウンロードする前にまず "GET" リクエストを送信する必要があります。リクエストの一部として、取得するページを指定する必要があります。

URL からダウンロードして表示する関数を定義しましょう:

def http_get(url):
    import socket
    _, _, host, path = url.split('/', 3)
    addr = socket.getaddrinfo(host, 80)[0][-1]
    s = socket.socket()
    s.connect(addr)
    s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
    while True:
        data = s.recv(100)
        if data:
            print(str(data, 'utf8'), end='')
        else:
            break
    s.close()

次を試してください:

>>> http_get('http://micropython.org/ks/test.html')

これにより、Webページが取得され、HTMLがコンソールに出力されます。

5.3. シンプルなHTTPサーバー

次のコードは、すべての GPIO ピンの状態を示す表を含む単一の Web ページを提供する単純な HTTP サーバーを作成します。

import machine
pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)]

html = """<!DOCTYPE html>
<html>
    <head> <title>ESP8266 Pins</title> </head>
    <body> <h1>ESP8266 Pins</h1>
        <table border="1"> <tr><th>Pin</th><th>Value</th></tr> %s </table>
    </body>
</html>
"""

import socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('listening on', addr)

while True:
    cl, addr = s.accept()
    print('client connected from', addr)
    cl_file = cl.makefile('rwb', 0)
    while True:
        line = cl_file.readline()
        if not line or line == b'\r\n':
            break
    rows = ['<tr><td>%s</td><td>%d</td></tr>' % (str(p), p.value()) for p in pins]
    response = html % '\n'.join(rows)
    cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
    cl.send(response)
    cl.close()