Responder + WebSocket으로 간단한 채팅 앱

TL;DR



WebSocket을 거의 사용한 적이 없었기 때문에 사용해 보았다.
사용자 인증이 없는 간이적인 채팅 앱이라면 바로 만들 수 있을 것 같았기 때문에 2018년에 방금 출시된 파이썬 웹 프레임워크 Responder을 사용해 구현해 보았다. (원래 Responder의 정보가 너무 적은데 WebSocket을 사용하고 있는 기사 등이 전무했기 때문에 소스 코드를 읽거나 Responder의 베이스가 되고 있는 Starlette도 조사하거나 해 꽤 힘들었다…)

Responder 은 Python 세계에서 유명한 Kenneth Reitz 씨작( requests 이나 pipenv 만든 사람)

완제품 : htps : // 기주 b. 이 m / ksk001100 / re s pon r-b b c t

프로젝트 구성


$ tree
.
├── Pipfile
├── Pipfile.lock
├── app.py
└── static
    └── index.html

프로젝트 만들기



이번에도 pipenv 에서 프로젝트를 작성하겠습니다.
$ mkdir responder-websocket-chat
$ cd responder-websocket-chat
$ pipenv --python 3.6.5
$ pipenv install responder --pre

서버 구현


app.py 에 서버 프로그램을 작성합니다.

app.py
import responder

api = responder.API()
clients = {} # 1

@api.route('/ws', websocket=True)
async def websocket(ws):
    await ws.accept()
    key = ws.headers.get('sec-websocket-key') # 2
    clients[key] = ws # 3
    try:
        while True:
            msg = await ws.receive_text()
            for client in clients.values(): # 4
                await client.send_text(msg)
    except:
        await ws.close()
        del clients[key] # 5

api.add_route('/', static=True)
api.run()

  • 1의 변수 clients 는 접속중의 클라이언트를 포함하는 사전. 메시지를 받으면 모든 클라이언트에게 메시지를 브로드 캐스트하기 위해 저장됩니다.
  • 2에서 요청 헤더에서 키를 검색하고 3에서 1로 선언한 사전에 클라이언트를 저장합니다.

  • 4 단계에서 모든 연결 클라이언트에 메시지를 브로드 캐스트

  • 5의 예외 처리 부분은 연결이 끊어지거나 다시로드 될 때 사전에 연결되지 않은 클라이언트가 저장되어 메모리를 압축하기 때문에 클라이언트를 삭제합니다.

    전면 구현



    JS의 처리 부분만 씁니다. 귀찮아서 실제로는 static/index.html 에 script 태그를 직접 묻고 있습니다.
    const ws = new WebSocket('ws://localhost:5042/ws');
    
    // メッセージを入力するinput要素
    const textbox = document.getElementById('textbox');
    
    // チャットのメッセージを表示するのul要素
    const chat = document.getElementById('chat');
    
    // 1
    ws.onmessage = function (e) {
    
      // メッセージのli要素作成
      const li = document.createElement('li');
    
      li.textContent = e.data;
      chat.appendChild(li);
    };
    
    // 2
    window.onload = function () {
      textbox.addEventListener('keypress', function (e) {
    
        // エンターキーが押された場合メッセージを送信
        if (e.keyCode == 13) {
          ws.send(textbox.value);
          textbox.value = "";
        }
      });
    }
    

  • 1은 서버에서 브로드 캐스트 될 때 처리

  • 2는 메시지를 입력하고 Enter 키를 눌렀을 때 처리합니다

  • 실제 동작



    좋은 웹페이지 즐겨찾기