일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 알고리즘 연습
- 알고리즘 문제
- django ORM
- 파이썬 알고리즘
- 파이썬
- 백준
- API
- Git
- form
- DRF
- Django
- c++
- AWS
- PYTHON
- CSS
- react
- 알고리즘 풀이
- es6
- django rest framework
- Baekjoon
- javascript
- 알고리즘
- js
- 장고
- django widget
- HTML
- MAC
- Algorithm
- web
- java
- Today
- Total
수학과의 좌충우돌 프로그래밍
[Django] Channels, 비동기적 채팅 구현하기 - WebSocket (2) 본문
저번 시간 WebSocket (1)에서는 이론적인 개념들과, 약간의 실습을 진행해보았습니다. 하지만 아직 채팅은 보내지지 않고 에러가 발생하였습니다. 지금부터 그 문제를 해결해보도록 하겠습니다.
-
소비자 만들기
django의 기본 원리를 생각해보면 HTTP 요청을 받아들이고 매핑된
URL
로 이동, 이에 따라views
에 함수를 실행합니다. 이와 유사하게Channels
역시 WebSocket 연결을 받아들이면,root routing configuration
에서 소비자를 찾은 후에, 이벤트를 처리하기 위한 함수들을 호출합니다.# chat/consumers.py from channels.generic.websocket import WebsocketConsumer import json class ChatConsumer(WebsocketConsumer): # websocket 연결 시 실행 def connect(self): self.accept() # websocket 연결 종료 시 실행 def disconnect(self, close_code): pass # 클라이언트로부터 메세지를 받을 시 실행 def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] # 클라이언트로부터 받은 메세지를 다시 클라이언트로 보내준다. self.send(text_data=json.dumps({ 'message': message }))
-
routing
소비자 라우팅을 처리하기 위해서 앱 안에
routing
을 추가해줍니다. 위에서 말했듯이 django의 url 과 유사합니다.# chat/routing.py from django.conf.urls import url from . import consumers websocket_urlpatterns = [ url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer), ]
이
routing
파일을 django가 인식할 수 있도록 추가해줘야합니다.# mysite/routing.py from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter import chat.routing # 클라이언트와 Channels 개발 서버가 연결 될 때, 어느 protocol 타입의 연결인지 application = ProtocolTypeRouter({ # (http->django views is added by default) # 만약에 websocket protocol 이라면, AuthMiddlewareStack 'websocket': AuthMiddlewareStack( # URLRouter 로 연결, 소비자의 라우트 연결 HTTP path를 조사 URLRouter( chat.routing.websocket_urlpatterns ) ), })
ERROR - server - Exception inside application: no such table: django_session
다음과 같은 에러가 발생한다면,
python manage.py migrate
migrate 함으로서 해결 할 수 있습니다.
여기 까지 진행 하였다면 사용자가 작성하는 메세지, 즉 클라이언트에서 넘어온 메세지를 다시 클라이언트 쪽으로 보내서 메세지를 보내는 듯한 효과를 줍니다. 하지만 아직 같은 채팅방에 있더라도 다른 사용자는 메세지를 볼 수 없습니다.
(1) 에서 설명했던 간단히 알아보았던 Channel layer
를 사용하면 소비자들끼리 소통을 가능하게 할 수 있습니다.
Channel layer 란?
Channel layer
는 의사소통 시스템 입니다. 즉 많은 소비자들 더 나아가서는 django의 다른 부분과 의사소통을 할 수 있게 해줍니다. Channel layer 에는 두 가지 개념이 존재합니다. channel 과 group 입니다.
-
channel
channel 은 메세지를 보낼 수 있는 우편함이라고 생각하면 됩니다. 각 채널은 고유한 이름이 있으며 누구든지 채널에 메세지를 보낼 수 있습니다.
-
group
group 은 채널과 관련된 그룹입니다. 그룹도 마찬가지로 이름을 가지며 그룹 이름을 가진 사용자는 누구나 그룹에 채널을 추가 / 삭제 가능하고 그룹의 모든 채널에게 메세지를 보낼 수 있습니다. 그러나 그룹에 속한 채널을 나열 할 수 없습니다.
소비자들을 채널 이름을 하나씩 가지고 있으며 Channel layer 를 통해 메세지를 주고 받을 수 있습니다.
-
channel layer 구현
이어서 실습을 진행해보도록 하겠습니다. channel layer 를 구현하기 위해서 백업저장소가 필요한데,
Redis
를 사용하도록 하겠습니다. 이를 사용하기 위해서는 별도의 설치가 필요합니다.macOS 용 패키지 관리자 Tool 인 brew 를 이용해서 설치해주었습니다.
$ brew install redis
다음으로 redis server 를 돌려줍니다.
$ redis-server
그리고 channels 가 redis 인터페이스를 얻을 수 있도록
channels_redis
패키지를 설치합니다.$ pip install channels_redis
다음으로는
settings
에 channel layer의 설정을 해줍니다.# Channels ASGI_APPLICATION = 'mysite.routing.application' CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [('127.0.0.1', 6379)], }, }, }
이번엔 기존에 작성했던
consumers
를 추가해줍니다.# chat/consumers.py from asgiref.sync import async_to_sync from channels.generic.websocket import WebsocketConsumer import json class ChatConsumer(WebsocketConsumer): def connect(self): # chat/routing.py 에 있는 # url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer), # 에서 room_name 을 가져옵니다. self.room_name = self.scope['url_route']['kwargs']['room_name'] self.room_group_name = 'chat_%s' % self.room_name # 그룹에 join # send 등 과 같은 동기적인 함수를 비동기적으로 사용하기 위해서는 async_to_sync 로 감싸줘야한다. async_to_sync(self.channel_layer.group_add)( self.room_group_name, self.channel_name ) # WebSocket 연결 self.accept() def disconnect(self, close_code): # 그룹에서 Leave async_to_sync(self.channel_layer.group_discard)( self.room_group_name, self.channel_name ) # WebSocket 에게 메세지 receive def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] # room group 에게 메세지 send async_to_sync(self.channel_layer.group_send)( self.room_group_name, { 'type': 'chat_message', 'message': message } ) # room group 에서 메세지 receive def chat_message(self, event): message = event['message'] # WebSocket 에게 메세지 전송 self.send(text_data=json.dumps({ 'message': message }))
macOS용 패키지 관리자 Tool
macOS용 패키지 관리자 Tool
이전 포스팅에서의 문제는 메세지 송 수신은 되지만 다른 사용자에게는 보이지 않는다는 점이었습니다. 이번에는 channels layer
를 사용하여 이러한 문제를 해결해보았습니다. 브라우저를 두 개 띄워놓고 같은 채팅방에 입장한 후, 메세지를 전송해보면 양 쪽에서 메세지가 뜨는 걸 확인할 수 있습니다. 제대로 채팅방이 구현된 것이죠.
'웹프로그래밍 > Django' 카테고리의 다른 글
[Django] visual studio code 를 이용한 debug (0) | 2019.07.14 |
---|---|
[Django] Channels, 비동기적 채팅 구현하기 - WebSocket (3) (2) | 2019.07.11 |
[Django] Channels, 비동기적 채팅 구현하기 - WebSocket (1) (4) | 2019.07.10 |
[Django] ChoiceField 사용하기 (4) | 2019.07.06 |
[Django]message framework 알아보기 (0) | 2019.07.06 |