1. 서버에 Redis server 설치

https://blog.daonelab.com/post/33/1829/

난 로컬에 설치하지 않고 서버에 설치하여 직접연결한다.

 

2. channels_redis 설치

(.venv) C:\Work\Python project\ws.daonelab.com>pip install channels_redis

원래는 python 3.10.5 로 진행했는데 channels_redis에서 설치오류가 발생해서, python 3.7.4로 다시 Django, channels 설치 후 진행했다.

 

Django를 가동해보면 아래 메시지가 나오는데, channels_redis 버전을 downgrade하니까 되더라

Exception inside application: ERR unknown command 'BZPOPMIN'

(.venv) C:\Work\Python project\ws.daonelab.com>pip uninstall channels_redis

(.venv) C:\Work\Python project\ws.daonelab.com>pip install channels-redis==2.4.2

근데 이렇게 하면  has no attribute 'as_asgi' 에러 메시지가 또 나오는데 이건 channels 버전이 낮아서 발생하는 문제다.

channels는 channels-redis설치하면 같이 설치되는데 직접 uninstall 하고 버전을 지정하여 설치한다.

channels-redis 2.4.2 requires channels~=2.2, but you have channels 3.0.1 which is incompatible.

설치가 완료되면 위 경고가 나오는데 일단 무시했다.

(.venv) C:\Work\Python project\ws.daonelab.com>pip uninatall channels

(.venv) C:\Work\Python project\ws.daonelab.com>pip install channels==3.0.1

에러없이 작동하는 channels와 channels-rediis 버전을 찾는게 힘들었다.

(.venv) C:\Work\Python project\ws.daonelab.com>pip list
Package             Version
------------------- -------
aioredis            1.3.1
asgiref             3.5.2
async-timeout       4.0.2
attrs               21.4.0
autobahn            22.6.1
Automat             20.2.0
cffi                1.15.1
channels            3.0.1
channels-redis      2.4.2
constantly          15.1.0
cryptography        37.0.4
daphne              3.0.2
Django              3.2.14
hiredis             2.0.0
hyperlink           21.0.0
idna                3.3
incremental         21.3.0
msgpack             0.6.2
pip                 22.1.2
pyasn1              0.4.8
pyasn1-modules      0.2.8
pycparser           2.21
pyOpenSSL           22.0.0
pytz                2022.1
service-identity    21.1.0
setuptools          40.8.0
six                 1.16.0
sqlparse            0.4.2
Twisted             22.4.0
twisted-iocpsupport 1.0.2
txaio               22.2.1
typing_extensions   4.3.0
zope.interface      5.4.0

설치버전
Redis server : 3.2.12
channels : 3.0.1
channels-redis : 2.4.2

위 내용은 삽질이다.

서버에 Redis server를 설치할때 repository를 최신으로 갱신하지 않고 redis를 설치해서

redis가 최신버전으로 설치되지 않아 발생한 문제로 최신 Reids server로 설치후,

channels-redis, channels 최신버전으로 설치하면 위에서 발생한 문제 없이 잘 작동하였다.

위 삽질의 기록은 남겨둔다.

결국 최종 설치 버전은
Redis server : 7.0.4
channels : 3.0.5
channels-redis : 3.4.1

(.venv) C:\Work\Python project\ws.daonelab.com>pip uninstall channels-redis
(.venv) C:\Work\Python project\ws.daonelab.com>pip install channels-redis

(.venv) C:\Work\Python project\ws.daonelab.com>pip uninstall channels
(.venv) C:\Work\Python project\ws.daonelab.com>pip install channels

(.venv) C:\Work\Python project\ws.daonelab.com>pip list
Package             Version
------------------- -------
.
.
channels            3.0.5
channels-redis      3.4.1
.
.

 

3. ws/settings.py

# WSGI_APPLICATION = 'ws.wsgi.application'
ASGI_APPLICATION = "ws.asgi.application"    # add

CHANNEL_LAYERS = {
    "default" : {
        "BACKEND" : "channels_redis.core.RedisChannelLayer",
        "CONFIG" : {
           "hosts" : [("redis://:password@domain.com:portno/0")],
        }
    }
}

multi chat을 위한 redis server와 연결 설정, 이번 내용에는 필요없고 다음 장에 필요하다.

 

4. ws/asgi.py

import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application

import chat.routing

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

application = ProtocolTypeRouter({
    "http" : get_asgi_application(),
    "websocket" : AllowedHostsOriginValidator
    (
        AuthMiddlewareStack
        (
            URLRouter
            (
                chat.routing.websocket_urlpatterns
            )
        )
    )
})

websocket으로 접근시 routing담당할 module지정

 

5. chat/routing.py

from django.urls import path, re_path
from chat.consumers import *

websocket_urlpatterns = [
    #re_path(r"ws/chat/(?P<room_name>\w+)/$", ChatConsumer.as_asgi()),
    path("ws/chat/<str:room_name>/", ChatConsumer.as_asgi()),
]

각 접근 경로별 처리할 class method지정 (channels버전이 낮으면 as_asgi property가 없다고 에러메시지 나온다.)

 

6. chat/consumers.py

import json
from channels.generic.websocket import WebsocketConsumer

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        return super().connect()
        
    def disconnect(self, code):
        return super().disconnect(code)
    
    def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)
        message = text_data_json["message"]
        
        self.send(text_data = json.dumps({
            "message" : message
        }))
        

 

브로우저로 접속하여 chat room을 입력하고 메시지를 입력하면 echo되는 걸 확인할 수 있다.

하지만 아직은 broadcast는 되지 않는다. 즉 동일 chat room에 접속한 다른 브라우저로는 메시지가 전달되지 않는다.