[4]장고 채널스(django channels) json 데이타 전송

Computer 비관심/Django|2017. 2. 18. 00:01
반응형

콘슈머에 json과 parse를 임포트 한다. 지금까지 text: message.content['text'] 로 돌려보냈는데 이번에는 text: json.dumps()를 사용하여 데이타를 브라우저에 json 형태로 보낸다. 영문 튜로리얼과 다르게 우리는 한국말을 사용하기 때문에 , ensure_ascii=False를 붙여주어 한글이 아스키코드로 바뀌어서 나오는 것을 막았다.

# consumers.py

import json
from urllib import parse

from channels import Group
from channels.sessions import channel_session


@channel_session
def ws_add(message, room):
    query = parse.parse_qs(message['query_string'])
    if 'username' not in query:
        return
    Group('chat-%s' % room).add(message.reply_channel)
    message.channel_session['room'] = room
    message.channel_session['username'] = query['username'][0]


@channel_session
def ws_echo(message):
    if 'username' not in message.channel_session:
        return
    room = message.channel_session['room']
    Group('chat-%s' % room).send({
        'text': json.dumps({
            'message': message.content['text'],
            'username': message.channel_session['username']
        }, ensure_ascii=False),
    })

콘솔에 웹소켓을 ws://localhost:8000/chat/1?username=sean 이런 형식으로 보낸뒤 아래와 같은 방식으로 브라우저 마다 여러개를 만들면 서버에서 메시지와 함게 세션에 저장된 usernamed을 함께 보내는 것을 확인 할 수 있다.

ws = new WebSocket((window.location.protocol == 'http:' ? 'ws://' : 'wss://') +  window.location.host + '/chat/' + 1 + '?username=' + 'sean');
//메시지가 오면 콘솔
ws.onmessage = function(message) {
      console.log(message.data);
    }
ws.send('hi')
1번 브라우저에서는 션이라고 만들었고 2번째 브라우저에서는 jone이라고 만들어서 메시지를 보낸 것을 확인 할 수 있다.


댓글()

[3] 장고 채널스(django chennals) urls를 기반으로 한 라우팅

Computer 비관심/Django|2017. 2. 17. 15:48
반응형

우리가 이전에 만든 route에 path 를 다음과 같이 추가한합니다.

그러면 url로 consumers.ws_add를 실행 할 수 있다. 이것은 인자를 ws_add로 넘기는 방법은 urls.py 에서 한 방법과 같습니다.

# routing.py

channel_routing = [
    ...
    route('websocket.connect', 'chat.consumers.ws_add',
          path=r'^/chat/(?P<room>\w+)$'),
]

consumers.py를 수정합니다. channel_session을 불러오고 @channel_session 데코레이터를 붙이면 장고 세션처럼 사용할 수 있는 message.channel_session을 제공합니다.

아래코드에서는 소켓접속시 room이라는 인자를 전달받아 'chat-전달받은 인자' 방을 만들고 

message.channel_session['room'] = room으로 세션을 저장하고 메시지가 전달되면 저장된 세션을 가져와 chat-인자 방에 send해줍니다.


# consumers.py

from channels import Group
from channels.sessions import channel_session


@channel_session
def ws_add(message, room):
    Group('chat-%s' % room).add(message.reply_channel)
    message.channel_session['room'] = room


@channel_session
def ws_echo(message):
    room = message.channel_session['room']
    Group('chat-%s' % room).send({
        'text': message.content['text'],
    })

테스트로 브라우저를 열고 소켓 객체를 생성해봅니다.


// 소켓생성
var ws1 = new WebSocket((window.location.protocol == 'http:' ? 'ws://' : 'wss://') + window.location.host + '/chat/' + 1) // 아이디 생성 ws1.id = 1; // 메시지가 오면 콘솔에 출력하도록 함. ws1.onmessage = function(message) { console.log('W' + this.id + ': ' + message.data); }

다른 브라우저에

// 소켓생성
var ws2 = new WebSocket((window.location.protocol == 'http:' ? 'ws://' : 'wss://') + window.location.host + '/chat/' + 2) // 아이디 생성 ws2.id = 2; // 메시지가 오면 콘솔에 출력하도록 함. ws2.onmessage = function(message) { console.log('W' + this.id + ': ' + message.data); }

또 다른 브라우저에 

// 소켓생성
var ws3 = new WebSocket((window.location.protocol == 'http:' ? 'ws://' : 'wss://') + window.location.host + '/chat/' + 2) // 아이디 생성 ws3.id = 3; // 메시지가 오면 콘솔에 출력하도록 함. ws3.onmessage = function(message) { console.log('W' + this.id + ': ' + message.data); }


결과


1번 브라우저

ws1.send를 할때 자기 /chat/1 그룹으로 등록한 사람에게만 보냈다. 1번 소켓 하나만 등록음. 


2번 브라우저



3번 브라우저


2번 소켓 3번 소켓은 chat/2 그룹으로 등록하여 2번 소켓이 send를 했을때 3번 소켓도 같이 데이타를 받는 것을 볼 수 있다.



같은 소켓을 하나의 브라우저에서 두번 만드는 것도 가능하다.


댓글()

[2] 장고 채널스(django chennals) Group

Computer 비관심/Django|2017. 2. 17. 13:05
반응형

Group의 개념


urls의와 비슷한 개념의 routing.py에 이번에는 websocket.connect를 추가합니다.

websocket.receive는 소켓에 message가 전달 됬을때 발생하며

websocket.connect는 소켓에 소켓이 생성됬을 때 발생합니다. 

#routing.py

channel_routing = [
    route('websocket.receive','chat.consumers.ws_echo'),
    route('websocket.connect', 'chat.consumers.ws_add'),
]

그러면 consumers.py에서 ws_add를 만들고 그룹에 있는 사람들이 메시지를 모두 받을 수 있도록 ws_echo를 수정해 보겠습니다. 

이전 글에서도 말했듣이 consumers.py는 장고의 views.py와 비슷하다고 볼 수 있습니다.  


ws_add에서는 routing.py에 websocket.connect가 실행되면 Group('chat')이라는 객체를 만든뒤 웹소켓 연결을 통해 만들어진 인스턴스들을 추가합니다.


ws_echo도 Goup('chat').send({text:브라우저로 보낼내용})

# consumers.py

from channels import Group


def ws_add(message):
    Group('chat').add(message.reply_channel)


def ws_echo(message):
    Group('chat').send({
        'text': message.content['text'],
    })


소캣객체 생성부터 메시지보내기 까지 3번 반복~

for (var i = 0; i < 3; ++i) {
  // Create a new WebSocket
  var ws = new WebSocket((window.location.protocol == 'http:' ? 'ws://' : 'wss://') +  window.location.host + '/')
  // Assign it an id
  ws.id = i;
  // Make it show a console message when a message is received
  ws.onmessage = function(message) {
    console.log('W' + this.id + ': ' + message.data);
  }
  // Send a new message when the WebSocket opens
  ws.onopen = function() {
    this.send('Hello, world');
  }
}

소켓을 만들고 ws.onmessage 즉 메시지가 왔으면 console.log를 사용해 message.data의 내용을 console에 뿌려준다.

ws.send는 서버에 내용을 hellow,world를 전달해준다.

댓글()

[1] 장고 채널스(django channels) 웹소켓 에코

Computer 비관심/Django|2017. 2. 17. 10:28
반응형


장고 채널은 장고 1.10 이상에서 지원


1.설치

# requirements.txt

asgi-redis==1.0.0
channels==0.17.3
daphne==0.15.0
Django==1.10.4

requirements.txt 파일을 만든 뒤 pip install -r requirements.txt를 입력하여 requirements.txt에 있는 모듈을 모두 설치 한다.




2. 앱 세팅


- 프로젝트를 만들고 앱을 만든다. 


- settings.py의 INSTALLED_APPS에 channels와 새로 생성한 앱 추가한다. (여기선 앱의 이름을 chat 이라고 만듬)

# settings.py

INSTALLED_APPS = (
    ...
    'channels',
    'chat',
)

...

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'asgiref.inmemory.ChannelLayer',
        'ROUTING': 'django_channels.routing.channel_routing',
    },
}

3.routing


- 라우팅 처리를 위하여 위에 설정한 바와 같이 django_channels라는 폴더에 routing.py 파일을 만든다.  


# routing.py
from channels.routing import route

channel_routing = [
    route('websocket.receive', 'chat.consumers.ws_echo'),
]

4. consumers.py


# consumers.py

def ws_echo(message):
    message.reply_channel.send({
        'text': message.content['text'],
    })


소켓이 접속이 되는지 확인하기 위해 로컬호스트에 접속하여 소켓을 만들어 아래를 입력합니다.


// http인지 https인지 확인 하여 그것에 맞는 소켓을 웹소켓 프로토콜을 선택
var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
ws = new WebSocket(ws_scheme +'://' +  window.location.host + '/');


이렇게 소켓에 접속 된 것을 볼수 있습니다.


// Create a new WebSocket
ws = new WebSocket((window.location.protocol == 'http:' ? 'ws://' : 'wss://') +  window.location.host + '/')

// ws.onmessage를 통해 메시지를 받으면 알림
ws.onmessage = function(message) {
  alert(message.data); 
}
// ws.onpen을 통해 소켓이 열리면 메시지를 보냄
ws.onopen = function() {
  ws.send('Hello, world');
}

send의 키를 text라고 하고 키 값으로 브라우저에 보낼 내용을 적습니다. 아래의 예는 브라우저에서 보낸 내용을 매개변수 message로 받아 오브젝트를 생성하여 .content['text']로 브라우저에서 보낸 내용을 다시 브라우저에 전달 하였습니다.


content 딕셔너리의 text라는 키가 있음. 그 키에는 브라우저에서 보내온 값이 있다.


message오브젝트에 data속성에 채널에서 보낸 내용이 들어 있다.


ws.readyState 를 통해 소켓의 상태를 확인 할 수 있음.  

WebSocket.OPEN  ->1 반환 소켓이 열려있음 

WebSocket.CLOSED ->3 반환 소켓이 닫힘


※ 이대로 하면 websocket.receive이 작동안됨을 알 수 있다. 이유는 다음과 같다.

위의 모듈대로 설치하게 되면  Twisted 가 최신버전으로 깔리게 되는데 Twisted 16.2.0만 제대로 작동한다는 이야기가 있다.

즉, 제대로 작동하기 위해서는 Twisted를 지운뒤 16.2.0버전으로 다시 설치하여야 한다.





참고


글이 적어서 좋았던 튜토리얼

https://www.sourcelair.com/blog/articles/115/django-channels-chat

소켓연결에서 http와 https에 따른 ws와 wss 선택  

https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django

채널 공식 문서

https://media.readthedocs.org/pdf/channels/latest/channels.pdf

twisted 문제 

http://stackoverflow.com/questions/38322197/django-channels-websocket-receive-is-not-handled



댓글()