シェルスクリプトマガジン

Pythonあれこれ(Vol.81掲載)

筆者:飯尾 淳

本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温
かく見守ってください。皆さんと共に勉強していきましょう。第11回では、永続的な非同期通信を簡単に実現できる「WebSocket」というプロトコルを利用するシンプルなチャットアプリの作成に挑戦しま
す。

シェルスクリプトマガジン Vol.81は以下のリンク先でご購入できます。

図1 エコーサーバーを実現するコード

import asyncio
import websockets

async def echo(soc):
  async for msg in soc:
    print(f'RECV: {msg}')
    await soc.send(msg)

async def main():
  async with websockets.serve(echo, port=8765, ping_timeout=None):
    await asyncio.Future()

asyncio.run(main())

図2 エコーサーバーに接続するクライアントのコード

import asyncio
import websockets

async def client():
  uri = "ws://localhost:8765/"
  async with websockets.connect(uri, ping_timeout=None) as soc:
    while True:
      msg = input('> ')
      await soc.send(msg)
      msg = await soc.recv()
      print(f'< {msg}')

asyncio.run(client())

図4 チャットサーバーのコード

import asyncio
import websockets

clients = {}

async def echo(soc):
  async for msg in soc:
    if not (soc in clients):
      clients[soc] = msg
      print(f'{msg} is registered')
      for s in clients:
        await s.send(f'{clients[soc]} が参加しました')
    else:
      print(f'RECV: {msg}')
      for s in clients:
        await s.send(f'{clients[soc]}: {msg}')

async def main():
  async with websockets.serve(echo, port=8765, ping_timeout=None):
    await asyncio.Future()

asyncio.run(main())

図5 チャットクライアントのHTMLコード

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>A Simple BBS</title>
  <meta name="description" content="WebSockets TEST">
  <meta name="author" content="Jun IIO">
  <script src="jquery-3.6.1.min.js"></script>
  <script src="scripts.js"></script>
</head>
<body>
  <h1>シンプル・チャット・システム</h1>
  <div>
    名前:
    <input id="regname" type="text">
    <button id="register">登録</button>
  </div>
  <div>
    <textarea id="msgarea" cols=80 rows=10
              readonly disabled="disabled"></textarea>
  </div>
  <div>
    <input id="chatmsg" type="text" size=80 disabled="disabled">
    <button id="send" disabled="disabled">送信</button>
  </div>
</body>
</html>

図6 チャットクライアントのJavaScriptコード

$(function(){
  let socket = new WebSocket("ws://localhost:8765/");

  $("#register").on("click", function(event) {
    name = $("#regname").val();
    if (name != "") {
      socket.send(name);
      $("#register").prop("disabled", true);
      $("#regname").prop("disabled", true);
      $("#msgarea").prop("disabled", false);
      $("#chatmsg").prop("disabled", false);
      $("#send").prop("disabled", false);
    };
  });

  socket.onmessage = function(event) {
    text = $("#msgarea").val();
    $("#msgarea").val(text + event.data + "\n");
  };

  $("#send").on("click", function(event) {
    msg = $("#chatmsg").val();
    if (msg != "") {
      socket.send(msg);
      $("#chatmsg").val("");
    };
  });
});