サーバ上のpythonとブラウザ上のjavascriptとデータ通信を行う

# やりたいこと
- pythonで簡単なゲームのプログラムを書いた。
- HTMLを駆使しながら、ブラウザ上の「GUI」でこのゲームができるようにしたい。
→　javascriptとpythonでデータのやり取りができれば大体OK

# この記事で説明すること
ここでは **WebSocket** の基本的な使い方をまとめておきます。
- javascript ↔ pythonのデータ通信が簡単に実装できる。
- ゲームユーザ（クライアント）がゲームから途中離脱した場合などの接続管理が簡単になるっぽい。複数人が個別でバラバラに接続してもOK。

# さっそくサンプル
### 使い方
1. webscoketsをpython環境にインストール
    ``conda install -c conda-forge websockets``を実行すればOK。簡単。

1. 下の``server.py``を保存して実行。
```python:server.py
'''Echoサーバの実装'''
import asyncio
import websockets

# この関数に通信しているときに行う処理を書く。
# クライアントが接続している間は下の関数が常に回っている
async def handler(websocket):
    # クライアントからのメッセージを取り出してそのまま送り返す（Echo）
    async for message in websocket:
        await websocket.send(message)

async def main():
    async with websockets.serve(handler, "localhost", 8001):
        await asyncio.Future()  # run forever

asyncio.run(main()
```


1. 下の``index.html``を保存してブラウザ上で起動。

```html:index.html
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Websocket Demo</title>
</head>
<body>
  <!-- ==========ここからHTML本体========== -->
  <!-- テキストフォームとボタン -->
  <form>
    <input id="textMessage" type="text">
    <input onclick="connect()" value="Connect" type="button">
    <input onclick="sendMessage()" value="Send" type="button">
    <input onclick="disconnect()" value="Disconnect" type="button">
  </form>
  <br />
  <!-- テキスト出力エリア -->
  <textarea id="messageTextArea" rows="10" cols="50"></textarea>


  <!-- ==========ここからjavascript========== -->
  <script type="text/javascript">

    var webSocket; //ウェブソケット
    var messageTextArea = document.getElementById("messageTextArea"); // HTML内のテキスト出力エリア

    // サーバとの通信を接続する関数
    function connect(){
      webSocket = new WebSocket("ws://localhost:8001"); // インスタンスを作り、サーバと接続

      // ソケット接続すれば呼び出す関数を設定
      webSocket.onopen = function(message){
        messageTextArea.value += "Server connect... OK\n";
      };

      // ソケット接続が切ると呼び出す関数を設定
      webSocket.onclose = function(message){
        messageTextArea.value += "Server Disconnect... OK\n";
      };

      // ソケット通信中でエラーが発生すれば呼び出す関数を設定
      webSocket.onerror = function(message){
        messageTextArea.value += "error...\n";
      };

      // ソケットサーバからメッセージが受信すれば呼び出す関数を設定
      webSocket.onmessage = function(message){
        messageTextArea.value += "Receive => "+message.data+"\n";
      };
    }

    // サーバにメッセージを送信する関数
    function sendMessage(){
      var message = document.getElementById("textMessage");
      messageTextArea.value += "Send => "+message.value+"\n";
      webSocket.send(message.value);
      message.value = "";
    }

    // サーバとの通信を切断する関数
    function disconnect(){
      webSocket.close();
    }
  </script>

</body>
</html>
```

### 実際に使っているところ
Connectボタンを押して接続し、適当な文字列を入力してSendボタンを押した結果。
そのまま文字列がサーバから返却されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510180/507e4e21-7ad2-1620-ce46-4c0a25db77ec.png)



# 参考
次のページを参考に勉強させていただきました。感謝。（ほとんど写経）
https://www.nowonbun.com/247.html


# おわりに
- 一応RESTでも作れるが、ゲームとの接続管理をもっと簡単に作れたのでwebsocketはわりと良かった。
- このソースコードを魔改造するとゲーム用GUIがブラウザ上でつくれる。








# （おまけ）ブラウザとの通信方法
- **REST API**
    - ざっくり説明
        - 最も基本的なサーバとの通信方式
        - GETなどを使ってサーバにアクセスし、データをサーバからもらう
    - メリット
        - つくるのが簡単で、大体のことはRESTで事足りる
    - デメリット
        - **クライアントがゲームから途中離脱した場合などの接続管理が面倒**
        - サーバから自主的にデータを送ることはできない
    
- **WebSocket**
    - ざっくり説明
        - 双方向通信用の通信方式
        - 接続が解除されるまではサーバとクライアントが常に通信を保ち、データのやり取りをする
    - メリット
        - **クライアントがゲームから途中離脱した場合などの接続管理が簡単**
        - サーバから自主的にデータを送ることができる
    - デメリット
        - 通信負荷とか、セキュリティとか考えるべき要素が増える