Django Channels 02. 채팅 서버 설정 (Implement Chat Server)
chat/
__init__.py
templates/
chat/
index.html
room.html
urls.py
views.py
<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<textarea id="chat-log" cols="100" rows="20"></textarea><br/>
<input id="chat-message-input" type="text" size="100"/><br/>
<input id="chat-message-submit" type="button" value="Send"/>
</body>
<script>
var roomName = {{ room_name_json }};
var chatSocket = new WebSocket(
'ws://' + window.location.host +
'/ws/chat/' + roomName + '/');
chatSocket.onmessage = function(e) {
var data = JSON.parse(e.data);
var message = data['message'];
document.querySelector('#chat-log').value += (message + '\n');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
document.querySelector('#chat-message-submit').onclick = function(e) {
var messageInputDom = document.querySelector('#chat-message-input');
var message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'message': message
}));
messageInputDom.value = '';
};
</script>
</html>
# chat/views.py
from django.shortcuts import render
from django.utils.safestring import mark_safe
import json
def index(request):
return render(request, 'chat/index.html', {})
def room(request, room_name):
return render(request, 'chat/room.html', {
'room_name_json': mark_safe(json.dumps(room_name))
})
from django.conf.urls import url
from . import views
urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^(?P<room_name>[^/]+)/$', views.room, name='room'), ]
$ python3 manage.py runserver
http://127.0.0.1:8000/chat/
경로로 이동 후 방이름 란에 lobby
입력
웹소켓에 접속을 시도하는 코드는 room.html 의 자바스크립트 코드 임.
웹소켓 URL = ws://127.0.0.1:8000/ws/chat/lobby/
채널, 웹소켓, 컨슈머의 상호작용은 django 의 http request 및 response와 비슷하다
django 의 http 통신은 다음과 같이 이루어짐
- django 에서 http url 을 통해 http request 가 발생함
- 그러면 django 의 root URL 부터 해당 URL 에 전달된 view 함수를 찾음
- 마지막으로 해당 view 함수를 실행하고 response 를 리턴
이와 유사하게 채널, 웹소켓, 컨슈머의 상호작용은 다음과 같이 이루어짐
- channel 이 websocket 의 연결을 허용 (위의 1번)
- 루트 라우팅 설정부터 컨슈머를 찾음 (위의 2번)
- 마지막으로 해당 컨슈머의 다양한 기능을 호출하여 연결된 이벤트를 처리 (위의 3번)
/ws/chat/ROOM_NAME/
경로로 WebSocket 을 연결하는 컨슈머를 만듦
chat/
__init__.py
consumers.py
templates/
chat/
index.html
room.html
urls.py
views.py
# chat/consumers.py
from channels.generic.websocket import WebsocketConsumer
import json
class ChatConsumer(WebsocketConsumer):
def connect(self):
self.accept()
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
}))
This is a synchronous WebSocket consumer that accepts all connections, receives messages from its client, and echos those messages back to the same client. For now it does not broadcast messages to other clients in the same room.
Channels also supports writing asynchronous consumers for greater performance. However any asynchronous consumer must be careful to avoid directly performing blocking operations, such as accessing a Django model. See the Consumers reference for more information about writing asynchronous consumers.
[ 현재 코드는 동기식 컨슈머인데 이렇게 되버리면 같은 채팅방에 있는 다른 사용자들한테 내가 보낸 메시지를 브로드캐스팅 하지 않음 물론 비동기식 컨슈머가 더 나은 성능을 지원하지만, 비동기식 컨슈머를 만들 때에, django의 모델에 대한 접근과 같은 blocking operation(?)을 직접 수행하지 않도록 신중하게 개발해야함]
여기까지가 공식 문서 내용이고, 사족 붙이면 위의 이유때문에 동기식으로 디폴트로 해놓은게 아닐까 싶음
chat/
__init__.py
consumers.py
routing.py
templates/
chat/
index.html
room.html
urls.py
views.py
# chat/routing.py
from django.conf.urls import url
from . import consumers
websocket_urlpatterns = [
url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer),
]
앞선 Django 의 HTTP 통신 과정에서 알아봤듯이, websocket 의 통신 과정에서도
root routing URL 로 부터 컨슈머를 찾기 시작하기 때문에
root routing URL Conf 작업을 진행함
mysite/routing.py
경로의 root routing.py 코드 작성
# mysite/routing.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing
application = ProtocolTypeRouter({
# (http->django views is added by default)
'websocket': AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver
http://127.0.0.1:8000/chat/lobby/
경로로 이동 후 메시지 입력
입력한 메시지가 그대로 echo 되어 출력 됨
하지만 새로운 창을 열어서 같은 곳에 접속 시 해당 내용은 볼 수 없음
진정한 채팅이 가능하려면 조금 전 만든 컨슈머를 채팅인원수만큼 만들어야 함
-
React
-
Server
-
Django Pakages
-
DeepLearning
-
Vue 기초
-
Vue 예제
-
NativeScript Vue
-
PWA
-
Django 프레임워크 탐구
-
Django 사용하기
-
Python
-
디자인 패턴
-
IAMPort [시작하기]
-
TDD with Python [참고]
-
블록체인
-
잡다한 개발
-
ASP.NET
-
Javascript
-
기술 블로그 & ETC
-
개발
-
Server
-
Infra
-
MSSQL
-
Django
-
Django Rest Framework
-
배포하기
-
소프트웨어 라이센스
-
React
-
Django
-
Django Channels
-
Python