Django Channel로 WebSocket 구현
Posted on 2021-08-30 by GKSRUDTN99
Django Rest Framework
DRF
Django Channel
WebSocket
1. 설치 및 SetUp
- Django 프로젝트 생성
- pip로
channels
와channels_redis
를 설치한다- Django 프로젝트에서
chat
이라는 이름의 App을 생성한다.INSTALLED_APPS
에channels
와chat
을 추가한다.- myapp/asgi.py파일에 다음과 같이 작성한다.
# mysite/asgi.py
import os
import django
from channels.http import AsgiHandler
from channels.routing import ProtocolTypeRouter
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
django.setup()
application = ProtocolTypeRouter({
"http": AsgiHandler(),
# Just HTTP for now. (We can add other protocols later.)
})
- settings.py에
ASGI_APPLICATION = 'myapp.asgi.application'
을 추가한다.- redis를 설치한다.
brew install redis
brew services start redis
2. consumer 생성하기
- consumer는 WebSocket을 사용하는 객체로, WebSocket의 connect, disconnet와 기타 action들을 정의한다.
- chat/consumers.py 파일을 생성하고, 다음 내용을 작성한다.
# chat/consumers.py
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
async_to_sync(self.channel_layer.group_add)(
self.room_group_name,
self.channel_name
)
self.accept()
def disconnect(self, close_code):
# Leave room group
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
def chat_message(self, event):
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({
'message': message
}))
- channel layer를 통해 consumer들의 그룹을 생성할 수 있다.
- group_send를 통해 data와 type을 보내면, type을 보고 Group에 속한 모든 consumer들은 type의 이릉믈 가진 함수를 실행한다.
- chat/routings.py 파일을 생성하고, 다음 내용을 작성한다.
# chat/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
]
- roomname을 parameter로 받는 path를 정의했다.
- roomname은 ChatConsumer에서 접근이 가능해, group의 이름을 정하는데 쓰인다.
- myapp/asgi.py 파일을 열고, 다음 내용을 수정한다.
# mysite/asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
http://
로 시작하는 요청은 원래 존재하던 django project로 넘기고,ws://
로 시작하는 websocket 요청은 chat 폴더 내 routing 파일로 넘긴다는 의미이다.
- Channel_layers 활성화를 위해 settings.py 파일 수정하기
- settings.py 파일에 다음 내용을 추가한다.
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
3. 프론트에서 웹소켓 생성하기
- 웹소켓 생성
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/chat/'
+ roomName
+ '/'
);
- 웹소켓에 메시지가 들어왔을 때, 콜백 함수 정의
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').value += (data.message + '\n');
};
redis를 도커로 설치하기
docker-compose를 통해 redis를 설치한다면, docker-compose 파일에 다음과 같이 작성하여 redis container를 실행한다.
redis:
image: redis:alpine
command: redis-server --port 6379
ports:
- 6379:6379
이와 같은 방식으로 실행되는 redis container의 host는 localhost(127.0.0.1)이 아니므로,
channel_layers config 설정에서 '127.0.0.1' 대신 'redis'를 사용해야한다.