추가 의존 없이 Django 응용 프로그램에 WebSocket을 추가하는 방법

주: 이 글은 최초로 my blog에 발표되었다.
현재 Django 3.0에는 ASGI의 기존 지원이 포함되어 있으며 Django 응용 프로그램에 WebSocket을 추가할 때 추가 의존 항목이 필요하지 않습니다.본 논문에서는 기본 ASGI 프로그램을 확장해서Django를 사용하여WebSocket을 처리하는 방법을 배울 것입니다.Websocket 연결, 전송, 수신 데이터를 어떻게 처리하고, 예시적인 ASGI 응용 프로그램에서 업무 논리를 실현하는지 토론할 것입니다.

개시하다
우선, 컴퓨터에 Python>=3.6을 설치해야 합니다.Django 3.0은 asyncawait 키워드를 사용했기 때문에 Python 3.6 및 더 높은 버전과 호환됩니다.파이썬 버전 설정이 완료되면 프로젝트 디렉터리를 만들고 cd을 넣습니다.그런 다음 virtualenv에 Django를 설치하고 프로젝트 디렉토리에 새 Django 응용 프로그램을 만듭니다.
$ mkdir django_websockets && cd django_websockets
$ python -m venv venv
$ source venv/bin/activate
$ pip install django
$ django-admin startproject websocket_app .
Django 애플리케이션의 websocket_app 디렉토리를 살펴보십시오.asgi.py이라는 파일을 보실 수 있습니다.내용은 다음과 같습니다.
import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'websocket_app.settings')

application = get_asgi_application()
이 파일은 기본 Django ASGI 설정을 제공하고 application이라는 이름의 ASGI 애플리케이션을 공개하며 uvicorn 또는 daphne 같은 ASGI 서버를 사용하여 실행할 수 있습니다.추가 논의에 앞서 ASGI 애플리케이션이 어떻게 구성되는지 살펴보겠습니다.

ASGI 응용 프로그램 구조
ASGI, 즉 비동기 서버 인터페이스 인터페이스는 파이톤을 사용하여 비동기 웹 서비스를 구축하는 규범이다.WSGI의 정신적 계승자로서 Django와 Flask 등 프레임워크가 WSGI를 오랫동안 사용해왔다.ASGI는 파이톤의 로컬 async/await 기능을 사용하여 장기적인 연결을 지원하는 웹 서비스를 구축할 수 있습니다. 예를 들어 웹소켓과 서버에서 보내는 이벤트입니다.
ASGI 응용 프로그램은 async 함수로 3개의 매개 변수를 받아들인다. scope(현재 요청한 상하문), receive(들어오는 이벤트를 감청할 수 있는 async 함수)와 send(클라이언트에 이벤트를 보낼 수 있는 async 함수)이다.
ASGI 응용 프로그램 내부에서는 scope 사전의 값 라우팅을 기반으로 요청할 수 있습니다.예를 들어 scope['type']의 값을 검사해서 요청이 HTTP 요청인지 Websocket 요청인지 확인할 수 있습니다.클라이언트의 데이터를 감청하려면 await 함수 receive을 사용할 수 있습니다.클라이언트에 데이터를 보낼 준비가 되었을 때 await 함수 send을 사용하여 클라이언트에 보내고 싶은 모든 데이터를 전송할 수 있습니다.이것은 예시 프로그램에서 어떻게 작동하는지 보여 줍니다.

ASGI 응용 프로그램 만들기
Google asgi.py 파일에서, Google은 Google ASGI 프로그램으로 Django의 기본 ASGI 프로그램 함수를 포장하여 Websocket 연결을 처리할 것입니다.이를 위해 우리는 async이라는 application 함수를 정의해야 한다. 이것은 3개의 ASGI 매개 변수를 받아들인다. 그것이 바로 scope, receivesend이다.HTTP 요청을 처리해야 하기 때문에 get_asgi_application 호출 결과를 django_application으로 변경합니다.application 함수에서 우리는 scope['type']의 값을 검사하여 요청 유형을 확정할 것이다.요청 형식이 'http'이면 요청은 일반적인 HTTP 요청입니다. Django가 처리해야 합니다.요청 유형이 'websocket'이라면 논리를 스스로 처리해야 합니다.생성된 asgi.py 파일은 다음과 같습니다.
import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'websocket_app.settings')

django_application = get_asgi_application()

async def application(scope, receive, send):
    if scope['type'] == 'http':
        # Let Django handle HTTP requests
        await django_application(scope, receive, send)
    elif scope['type'] == 'websocket':
        # We'll handle Websocket connections here
        pass
    else:
        raise NotImplementedError(f"Unknown scope type {scope['type']}")
웹 소켓 연결을 처리하기 위해 함수를 만들어야 합니다.websocket.py 파일이 있는 폴더에 asgi.py이라는 파일을 만들고 3개의 ASGI 매개 변수를 수용하는 websocket_application이라는 ASGI 응용 프로그램 함수를 정의합니다.다음에 우리는 websocket_application 파일에서 asgi.py을 가져오고 application 함수에서 이를 호출하여Websocket 요청을 처리하고 scope, receivesend 파라미터를 전달할 것이다.이렇게 해야 합니다.
# asgi.py
import os

from django.core.asgi import get_asgi_application
from websocket_app.websocket import websocket_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'websocket_app.settings')

django_application = get_asgi_application()

async def application(scope, receive, send):
    if scope['type'] == 'http':
        await django_application(scope, receive, send)
    elif scope['type'] == 'websocket':
        await websocket_application(scope, receive, send)
    else:
        raise NotImplementedError(f"Unknown scope type {scope['type']}")

# websocket.py
async def websocket_applciation(scope, receive, send):
    pass
다음은 웹 소켓 응용 프로그램의 논리를 실현합니다.클라이언트가 문자열 "ping"을 보낼 때, 우리는 문자열 "pong!"으로 응답할 것입니다.websocket_application 함수에서 연결이 닫힐 때까지 무한 순환을 정의합니다.이 순환에서, 우리는 서버가 클라이언트로부터 새로운 이벤트를 받기를 기다릴 것입니다.그리고 이벤트의 내용에 대해 행동을 취하고 응답을 클라이언트에게 보낼 것입니다.
우선 연결을 처리합시다.새로운 Websocket 클라이언트가 서버에 연결되면 'websocket.connect' 이벤트를 받을 것입니다.이러한 연결을 허용하기 위해서, 우리는 'websocket.accept' 이벤트를 응답으로 보낼 것입니다.이렇게 하면 Websocket 핸드셰이크가 완료되고 클라이언트와 지속적인 연결이 이루어집니다.
클라이언트가 서버와의 연결을 종료할 때, 우리는 인터럽트 이벤트를 처리해야 한다.이를 위해 'websocket.disconnect' 행사를 듣겠습니다.클라이언트가 연결을 끊을 때, 우리는 우리의 무한 순환을 깨뜨릴 것이다.
마지막으로, 우리는 클라이언트로부터 요청을 처리해야 한다.이를 위해 'websocket.receive' 행사를 듣겠습니다.클라이언트로부터 'websocket.receive' 이벤트를 받으면 event['text']의 값이 'ping'인지 확인합니다.만약 그렇다면 'websocket.send' 이벤트를 보내겠습니다. text 값은 'pong!'입니다.
Websocket 로직을 설정한 후 websocket.py 파일은 다음과 같습니다.
# websocket.py
async def websocket_applciation(scope, receive, send):
    while True:
        event = await receive()

        if event['type'] == 'websocket.connect':
            await send({
                'type': 'websocket.accept'
            })

        if event['type'] == 'websocket.disconnect':
            break

        if event['type'] == 'websocket.receive':
            if event['text'] == 'ping':
                await send({
                    'type': 'websocket.send',
                    'text': 'pong!'
                })

테스트
현재, 우리의ASGI 응용 프로그램은 Websocket 연결을 처리하는 것으로 설정되어 있으며, 우리는 이미 Websocket 서버 논리를 실현하였으니, 한번 테스트해 봅시다.현재 Django 개발 서버는 asgi.py 파일을 사용하지 않으므로 ./manage.py runserver 테스트 연결을 사용할 수 없습니다.대신 ASGI 서버(예: uvicorn)를 사용하여 어플리케이션을 실행해야 합니다.설치를 시작하겠습니다.
$ pip install uvicorn
uvicorn을 설치한 후에는 다음 명령을 사용하여 ASGI 애플리케이션을 실행할 수 있습니다.
$ uvicorn websocket_app.asgi:application
INFO:     Started server process [25557]
INFO:     Waiting for application startup.
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Websocket 연결을 테스트하려면 새 탭에서 브라우저의 개발 도구를 엽니다.콘솔에서 Websocket이라는 새로운 ws 실례를 만들어 ws://localhost:8000/을 가리킨다.그리고 onmessage 프로세서를 ws에 연결하고 이 프로세서는 event.data을 컨트롤러에 기록한다.마지막으로 서버로 메시지를 보내려면 ws.send('ping')으로 전화하십시오.콘솔에 기록된 값 "pong!"을 보실 수 있습니다.
> ws = new WebSocket('ws://localhost:8000/')
  WebSocket {url: "ws://localhost:8000/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}
> ws.onmessage = event => console.log(event.data)
  event => console.log(event.data)
> ws.send("ping")
  undefined
  pong!
축하합니다!이제 ASGI를 사용하여 Django 응용 프로그램에 Websocket 지원을 추가하는 방법을 알게 되었습니다.얘로 좋은 거 만들어.😎
👋 여보세요, 제인입니다.나는 응용 프로그램을 구축하는 것을 좋아하고, 다른 사람에게 어떻게 응용 프로그램을 구축하는지 가르치는 것을 좋아한다.Django,React,GraphQL을 이용한 응용 프로그램 구축에 대한 더 많은 게시물은 Twitter으로 연락하거나 jaydenwindle.com으로 저의 시사통신을 구독하세요.

좋은 웹페이지 즐겨찾기