Flaskを使ってみる

WebSocketで他のサーバーと連携する

こち らにブラウザーで使えるWebSocketオブジェクトの仕様が公開されています。
ほとんどのブラウザーがWebSocketオブジェクトをサポートしています。
WebSocket オブジェクトは、WebSocketのクライアントとして動作し、
サーバーへの WebSocket 接続の作成と管理、および接続上のデータの送受信に使用する API を提供します。

Flaskで構築したアプリケーションはブラウザーでのイベントが無いと、pythonコードを実行することができませんが、
このAPIを使うと、WebSocketサーバーと非同期に通信することができます。
つまり、外部のサーバーが非同期に送り付けてきたデータを、ブラウザー内で処理することが出来るようになります。

FlaskのテンプレートでもWebSocketオブジェクトを使うことができます。
事前にpsutilライブラリをインストールしておきます。
$ python -m pip install psutil

pytonコードは以下の通りです。
get_ip_address()はサーバー側のIPアドレスを求める関数で、こちらからお借りしま した。
127.0.0.1以外のIPアドレスを探してテンプレート側に渡しています。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask, render_template, redirect
import datetime
import socket
import psutil
app = Flask(__name__)

import socket
import psutil

# https://lightgauge.net/language/python/8786/
def get_ip_addresses( family ):
    for interface, snics in psutil.net_if_addrs().items() :
        for snic in snics :
            if snic.family == family :
                yield( interface, snic.address )


@app.route("/")
def index():
        print("Start index")
        ipv4s = list(get_ip_addresses(socket.AF_INET))
        ipv6s = list(get_ip_addresses(socket.AF_INET6))
        print("ipv4s={}".format(ipv4s))
        print("ipv6s={}".format(ipv4s))
        for ipv4 in ipv4s:
                print("ipv4={} {} {} {}".format(type(ipv4), ipv4[0], ipv4[1], ipv4))
                if (ipv4[1] != "127.0.0.1"):
                        server_ip = ipv4[1]

        print("server_ip={}".format(server_ip))

        return render_template('web-socket.html', server_ip=server_ip, server_port="5001")

if __name__ == "__main__":
        print("Reloding...")
        print("app.url_map={}".format(app.url_map))
        app.run(host='0.0.0.0', port=8080, debug=True)

template(web-socket.html)は以下の通りです。
スクリプト内でWebSocketオブジェクトを作成していますが、localhostや127.0.0.1では動かなかったので、
python側から渡ってきたIPアドレスを使っています。
WebSocketオブジェクトの使い方に関しては、こ ちらのページを大いに参考にさせて頂きました。ありがとうございます。
<!DOCTYPE html>
  <head>
        <meta charset="UTF-8">
        <title>JavaScriptでWebSocket</title>
  </head>
  <body>
        <h1>JavaScriptでWebSocket</h1>
        server_ip : {{ server_ip }}<br>
        <br>
        <textarea id="RcvMsg" cols="40" rows="4" maxlength="20" placeholder="受信メッセージ表示します"></textarea><br>
        <br>
        <textarea id="Status" cols="40" rows="4" maxlength="20" placeholder="サーバステータスを表示します"></textarea><br>
        <br>
        <button id="btn">Hello</button>
        <br>


        <script type="text/javascript">
                var server_ip = "{{server_ip}}";
                console.log("server_ip", server_ip);
                var server_port = "{{server_port}}";
                console.log("server_port", server_port);
                document.getElementById("Status").value = "CONNECTING";

                //https://qiita.com/okumurakengo/items/c497fba7f16b41146d77
                //const sock = new WebSocket("ws://127.0.0.1:5001");
                //const sock = new WebSocket("ws://localhost:5001");
                var server_url = "ws://" + server_ip + ":" + server_port;
                console.log("server_url", server_url);
                //const sock = new WebSocket("ws://192.168.10.43:5001");
                const sock = new WebSocket(server_url);

                sock.addEventListener("open", e => {
                        console.log("接続が開かれたときに呼び出されるイベント");
                        document.getElementById("Status").value = "OPEN";
                });

                sock.addEventListener("message", e => {
                        console.log("サーバーからメッセージを受信したときに呼び出されるイベント");
                        console.log(e.data);
                        document.getElementById("RcvMsg").value = e.data;
                });

                sock.addEventListener("close", e => {
                        console.log("接続が閉じられたときに呼び出されるイベント");
                        document.getElementById("Status").value = "CLOSING";
                });

                sock.addEventListener("error", e => {
                        console.log("エラーが発生したときに呼び出されるイベント");
                        document.getElementById("Status").value = "FAIL";
                });

                btn.addEventListener("click", e => {
                        console.log(`readyState:${sock.readyState}`);
                        console.log(sock.readyState);
                        if (sock.readyState == 0) {
                                document.getElementById("Status").value = "CONNECTING";
                        } else if (sock.readyState == 1) {
                                document.getElementById("Status").value = "OPEN";
                                sock.send("hello from browser");
                        } else if (sock.readyState == 2) {
                                document.getElementById("Status").value = "CLOSING";
                        } else if (sock.readyState == 3) {
                                document.getElementById("Status").value = "CLOSED";
                        }
                });

        </script>

  </body>
</html>



サーバー側はnode+WebSocketライブラリで作りました。
WebSocketライブラリは、上で紹介してるWebSocketオブジェクトと紛らわしいですが、nodeのライブラリで使い方が全く違いま す。
WebSocketでググるとWebSocketライブラリとWebSocketオブジェクトがヒットするので注意が必要です。
nodeのコードは、こ ちらのページのサンプルを借用しました。ありがとうございます。
WebSocketのサーバー処理は、pythonでもC言語でも簡単に作ることができます。
const server = require("ws").Server;
const s = new server({ port: 5001 });

s.on("connection", ws => {
    console.log("Connected");
    ws.send("hello from server");
    ws.on("message", message => {
        console.log("Received: " + message);
        ws.send("you are welcome");
    });
    ws.on('close',function(){
        console.log('I lost a client');
    });
});

サーバー側を起動したらFlaskを起動します。
この様にサーバー側からのメッセージ(hello from server)が表示されます。


Helloボタンを押すとブラウザーからサーバーにメッセージを送り、サーバーからの応答(you are welcome)を表示します。


サーバーを止めると、サーバーの状態はCLOSEDになります。


サーバー起動前にFlaskを起動すると、サーバーの状態はCONNECTINGになります


このようにブラウザー側でサーバーの接続状態が分かるので、サーバー側に異常が有ったことがすぐに分かります。

続く...