2010-12-06 3 views
24

websockets의 재미있는 부분은 본질적으로 원하지 않는 콘텐츠를 서버에서 브라우저로 바로 전송하는 것입니까?websockets 및 python/django (/ twisted?)로 이동하기

음, 저는 Gregor Müllegger의 django-websocket을 사용하고 있습니다. Django에서 웹 소켓을 만들 때 정말 멋진 초기 균열입니다.

나는 "안녕하세요 세상"을 성취했습니다. 이 작동 방식은 요청이 websocket 인 경우 요청 객체에 websocket이라는 객체가 추가됩니다. 따라서 웹 소켓을 해석 할 때 다음과 같이하면됩니다.

request.websocket.send('We are the knights who say ni!') 

잘 작동합니다. 브라우저에서 메시지를 다시 매력으로 보았습니다.

하지만 브라우저에서 요청하지 않고 처리하고 싶다면 어떻게해야합니까?

OK, 그래서 먼저 내가 세션 사전에 웹 소켓을 저장합니다

request.session['websocket'] = request.websocket 

그런 다음, 쉘에, 내가 가서 세션 키에 의해 세션을 잡아. 물론 세션 사전에는 websocket 객체가 있습니다. 행복! 그러나

, 내가하려고 :

>>> session.get_decoded()['websocket'].send('With a herring!') 

내가 얻을 :

Traceback (most recent call last): 
File "<console>", line 1, in <module> 
error: [Errno 9] Bad file descriptor 

슬픈. :-(

좋아요, 그래서 소켓에 대해서는별로 몰라요.하지만 저는 디버거에서 주위를 킁킁 거리며 알기도합니다. 디버거에있는 소켓이 내가 세션에 저장 한 웹 소켓에서 잡고 하나가 전략 중 한 동안 요청에서 정품 웹 소켓은) -1 = = 6 전략 중하고있다.

소켓 지향적 인 사람이 물건을 분류 나를 도와 드릴까요?

+0

@ 엘리 콰이트 당신이 현상금을 수여하지 못했습니다. – pradyunsg

+0

@paddila : 현상금을 여는 이유는 "답장 중 하나 이상이 모범적이며 가치가 있습니다. 추가 현상금. " 시스템이 나를 허용하자마자 현상금을 수여 할 것입니다. –

답변

63

저는 django-websocket의 저자입니다. 나는 웹 소켓과 네트워킹의 주제에 대한 진정한 전문가는 아니지만, 무슨 일이 벌어지고 있는지 잘 알고 있다고 생각합니다. 훌륭한 세부 사항에 들어가서 미안해. 답변의 대부분이 귀하의 질문에 특정 적이 아니더라도 다른 시점에서 귀하를 도울 수 있습니다. :-)


WebSocket을가

작동 방법 나에게 웹 소켓이 곧 설명해 보자. websocket은 브라우저에서 설정 한 일반 HTTP 요청과 비슷한 것으로 시작합니다. HTTP 헤더를 통해 HTTP 요청 대신에 프로토콜을 "업그레이드"하여 WebSocket으로 지정하고자 함을 나타냅니다. 서버가 웹 소켓을 지원하면 핸드 셰이크 및 서버와 클라이언트 모두에서 동의합니다. 이전에는 HTTP 요청에 사용 된 기존의 tcp 소켓을 웹 소켓 메시지 교환에 사용합니다.

메시지를 보내고 기다리는 것 외에 그들은 물론 언제든지 연결을 닫을 수 있습니다.

어떻게 장고 - 웹 소켓이 남용

지금 장고 - 웹 소켓은 장고 요청 - 응답 cylce의 HTTP 요청의 "업그레이드"를 구현하는 방법의 세부 사항에 들어가 할 수있는 소켓에게 납치하는 파이썬의 WSGI 요청 환경을.

장고는 일반적으로 WSGI 사양을 사용하여 아파치 나 gunicorn 등과 같은 웹 서버와 통신합니다.이 사양은 HTTP의 통신 모델을 염두에두고 설계되었습니다. 그것은 HTTP 요청 (수신 데이터 만)을 받고 응답 (송신 데이터 만)을 리턴한다고 가정합니다. 이것은 django를 양방향 통신이 허용되는 websocket의 개념으로 강제하는 것은 까다로운 작업입니다.

내가 이것을 달성하기 위해 django-websocket에서하고있는 일은 WSGI의 내부와 django의 요청 객체를 아주 깊이 파헤쳐서 밑에있는 소켓을 검색하는 것이다. 그런 다음이 tcp 소켓을 사용하여 HTTP 요청을 websocket 인스턴스로 직접 업그레이드하는 작업을 처리합니다. 원래의 질문에 이제

...

나는이 위의 웹 소켓이 설정되면, HttpResponse에 반환 아무 문제가 없다는 것이 분명하게 있기를 바랍니다. 이것은 보통 django-websocket이 처리하는 뷰에서 아무 것도 반환하지 않는 이유입니다.

그러나 논리를 유지하고 입력을 기반으로 데이터를 반환하는보기의 개념에 가깝게하고 싶었습니다. 따라서 웹 소켓을 처리 할 때 코드를보기에서만 사용해야합니다.

보기에서 돌아 오면 웹 소켓이 자동으로 닫힙니다. 이유는 다음과 같습니다. 우리는 정의되지 않은 시간 동안 소켓을 열어 두지 않고 클라이언트 (브라우저)를 사용하여 소켓을 닫고 싶지 않습니다.

위와 같은 이유로 django-websocket을 외부에서 볼 수없는 웹 소켓에 액세스 할 수 없습니다. 파일 설명자는 -1로 설정되어 이미 닫혀 있음을 나타냅니다.

면책 조항

나는 그 어떻게 든 얻을 장고의 주변 환경에 파고있어 위의 설명 - 매우 hackish 방법 - 기저의 소켓에 액세스 할 수 있습니다. 이것은 WSGI가 이것을 위해 설계된 것이 아니기 때문에 매우 약해서 또한 작동하지 않을 것입니다! 위의 설명은 websocket이 뷰가 끝난 후에 닫혔다는 것입니다.하지만 WebSocket이 닫히고 (TCP 소켓을 닫은 후) django의 WSGI 구현은 HTTP 응답을 보내려고 시도합니다. 웹 소켓에 대해 알지 못하고 있다고 생각합니다. 일반적인 HTTP 요청 - 응답주기 그러나 소켓이 이미 닫혀 있으면 전송이 실패합니다. 이것은 보통 django에서 예외를 발생시킵니다.

이것은 개발 서버에 대한 내 테스트에 영향을 미치지 않았습니다. 브라우저는 알지 못합니다. (소켓이 이미 닫혀 있습니다 ;-) - 모든 요청에서 처리되지 않은 오류를 발생시키는 것은 좋은 개념이 아니며 메모리 누수가 발생할 수 있으며 데이터베이스 연결 종료를 올바르게 처리하지 못하고 많은 athor를 처리합니다 그 것입니다 당신이 실험 이상으로 django-websocket을 사용한다면 어느 시점에서 중단됩니다. 나는 정말로 당신에게 를 권합니다 아직 장고와 WebSocket을를 사용하는 이유

이다. 그것은 의도적으로 작동하지 않습니다. 장고와 특히 WSGI는 이러한 문제를 해결하기 위해 총체적인 점검이 필요합니다 (this discussion for websockets and WSGI 참조). 그 이후로 나는 eventlet과 같은 것을 사용하도록 제안 할 것입니다.Eventlet은 작동중인 websocket 구현을 가지고 있습니다. (초기 버전의 django-websocket에 대한 eventlet에서 일부 코드를 빌 렸습니다.) 그리고 그저 평범한 파이썬 코드를 사용하여 모델과 장고를 가져올 수 있습니다. 유일한 단점은 웹 소켓을 처리하기 위해 실행중인 두 번째 웹 서버가 필요하다는 것입니다.

+0

이 놀라운 대답에 감사드립니다. 나는 너에게 그 현상금을 줄 때까지 그것을 받아들이기를 기다리고있다. :-) – jMyles

+0

이것은 websocket을 서비스하기 위해 요청을 열어야 만한다는 것을 의미합니까? 들어오는 메시지를 기다리는 동안 메시지 반복자가 차단하는 경우 어떻게하면 원치 않는 메시지를 보냅니 까? – Thomas

+0

@ 토마스 그렇습니다. 요청을 열어 두어야합니다 (websocket의 소켓이 의미가 있습니다). 메시지를 기다리는 동안 차단할 필요는 없으며'read()'와'has_messages()'메쏘드로 새로운 것을 주기적으로 검사 할 수있다. 여기서 README를 읽으십시오. https://github.com/gregmuellegger/django-websocket 그런 다음 언제든지 메시지 보내기를 시작할 수 있습니다. –

0

request.websocket은 요청 처리기 (보기)에서 돌아 왔을 때 닫힌 상태 일 수 있습니다. 간단한 해결책은 처리기를 활성 상태로 유지하는 것입니다 (보기에서 돌아 가지 않음). 서버가 다중 스레드가 아닌 경우에는 처리 할 수 ​​없습니다. 다른 동시 요구를 받아 들인다. est.

+0

하지만 그 때의 요점은 무엇입니까? 보기에 요청을 유지해야한다면 바로 혜성입니다. 웹 소켓의 요점은 요청을 계속 유지하지 않고도 브라우저에 컨텐츠를 푸시 할 수 있다는 것입니다. – jMyles

+1

@Justin Myles Holms : http : //pypi.python에서 면책 조항을 읽으십시오.org/pypi/django-websocket – jfs

+0

그래, 나는 그것을 보았다. 두 가지 이유가 있습니다. 1) django-websocket과 함께 제공되는 다중 스레드 runserver를 사용하고 있습니다. 2) websocket-ready 서버 솔루션을 사용할 준비가되어 있습니다. pywebsocket (blegh) 또는 Twisted (yay)가있는 Apache/mod_python 중 하나입니다. 그러나 지금은 테스트 할 수도 없습니다. 이 소켓을 쉘에서 사용할 수없는 이유에 대해 더 이해해야합니다. – jMyles

2

stargate에게 bash : http://boothead.github.com/stargate/http://pypi.python.org/pypi/stargate/을 줄 수 있습니다.

필자는 피라미드 및 이벤트 릿 (eventlet에 대한 웹 소켓 지원 및 테스트의 상당 부분을 제공함) 위에 구축되었습니다. 이런 종류의 피라미드의 가장 큰 장점은 호출 가능 객체의 결과가 아니라 URL이 매핑되는 자원의 개념입니다. 따라서 URL 구조에 매핑되는 영구 리소스의 그래프로 끝나고 websocket 연결은 단순히 라우트되고 해당 리소스에 연결됩니다. 자기가로 (

class YourView(WebSocketView): 

    def handler(self, websocket): 
     self.request.context.add_listener(websocket) 
     while True: 
      msg = websocket.wait() 
      # Do something with message 

메시지 를 수신하고

다음
resource.send(some_other_message) 

자원이 stargate.resource.WebSocketAwareContext의 인스턴스 : 그래서

만이 일을 할 필요가 결국 .request.context)를 호출하고 send 메소드는 add_listener 메소드로 연결된 모든 클라이언트에 메시지를 보냅니다.

방금 ​​내가 희망이 조금 더 잘 보여주기 위해 다음 두 주에 약간의 예제 응용 프로그램을 작성하는거야 node.send(message)

전화 연결된 모든 클라이언트에 메시지를 게시하려면.

도움이 필요하시면 github에서 나를 핑 (ping)하십시오.

+0

Ben - 낙관적 인 것처럼 보입니다. 너는 나의 주의력을 가지고있다! :-) – jMyles

5

그레고리 뮬 레거 (Gregor Müllegger)는 WSGI는 웹 소켓을 제대로 처리 할 수 ​​없다고 지적합니다. 그 프로토콜은 결코 그런 기능을 처리 할 수 ​​없기 때문입니다. uWSGI은 버전 1.9.11부터 웹 스택을 즉시 처리 할 수 ​​있습니다. 여기서 uWSGI는 WSGI 프로토콜이 아닌 원시 HTTP를 사용하여 응용 프로그램 서버와 통신합니다. 그렇게 작성된 서버는 프로토콜 내부를 처리하고 오랜 기간 동안 연결을 열어 둘 수 있습니다. Django 뷰로 오래 살아있는 연결을 처리하는 것은 제한된 리소스 인 작업자 스레드를 차단하므로 좋은 아이디어가 아닙니다.

웹 소켓의 주요 목적은 서버가 비동기 방식으로 클라이언트에 메시지를 푸시하도록하는 것입니다. 이것은 다른 브라우저 (예 : 채팅 클라이언트, 멀티 플레이어 게임) 또는 장고 - 셀러리 (예 : 스포츠 결과)에 의해 트리거되는 이벤트에 의해 트리거되는 장고보기 일 수 있습니다. 따라서이 장고 서비스가 클라이언트에게 메시지를 푸시하기 위해 메시지 큐를 사용하는 것이 중요합니다.

확장 성있는 방식으로이 문제를 해결하기 위해 백엔드 메시지 대기열로 Redis를 사용하여 하나의 단일 스레드/프로세스에서 긴 수명 웹 소켓 연결을 모두 열 수있는 장고 모듈 인 django-websocket-redis을 작성했습니다.

+0

고령화 문제에 대한 통찰력을 주셔서 감사합니다! – jMyles

+0

+1'django-websocket-redis'는 제안 된'nginx'와'uWSGI' 콤보에 익숙하다면 설치와 사용이 매우 간단합니다. –

관련 문제