jMy*_*les 24 python sockets django websocket
websockets的有趣部分是从服务器向浏览器发送基本上未经请求的内容吗?
好吧,我正在使用GregorMüllegger的django-websocket.在使用Django的websockets时,这是一个非常精彩的早期破解.
我已经完成了"你好世界".其工作方式是:当请求是websocket时,对象websocket将附加到请求对象.因此,我可以在解释websocket的视图中执行以下操作:
request.websocket.send('We are the knights who say ni!')
Run Code Online (Sandbox Code Playgroud)
这很好.我在浏览器中收到的消息就像魅力一样.
但是,如果我想在不发出浏览器请求的情况下这样做呢?
好的,首先我将websocket保存在会话字典中:
request.session['websocket'] = request.websocket
Run Code Online (Sandbox Code Playgroud)
然后,在shell中,我按会话密钥抓取会话.果然,会话字典中有一个websocket对象.快乐!
但是,当我尝试做的时候:
>>> session.get_decoded()['websocket'].send('With a herring!')
Run Code Online (Sandbox Code Playgroud)
我明白了:
Traceback (most recent call last):
File "<console>", line 1, in <module>
error: [Errno 9] Bad file descriptor
Run Code Online (Sandbox Code Playgroud)
伤心.:-(
好了,我不知道很多关于插座什么,但我知道足够嗅出在调试器周围,你瞧,我看到在我的调试器插座(这是联系在一起的真正的WebSocket从请求)已FD = 6,而我从会话保存的网页套接字抓起一个已FD = -1.
套接字导向的人可以帮我解决这个问题吗?
Gre*_*ger 64
我是django-websocket的作者.我不是webockets和网络主题的真正专家,但我认为我对正在发生的事情有一个很好的理解.很抱歉进入非常详细.即使大多数答案不是特定于您的问题,它也可能在其他方面帮助您.:-)
让我简单解释一下websocket是什么.websocket从浏览器建立的真正看起来像普通HTTP请求的东西开始.它通过HTTP标头指示它希望将协议"升级"为websocket而不是HTTP请求.如果服务器支持websockets,它同意握手,服务器和客户端都知道他们将使用以前用于HTTP请求的已建立的tcp套接字作为交换websocket消息的连接.
除了发送和等待消息之外,他们当然还可以随时关闭连接.
现在让我们深入了解django-websocket如何在django请求 - 响应循环中实现HTTP请求的"升级".
Django通常使用WSGI规范与web服务器(如apache或gunicorn等)进行通信.此规范的设计仅考虑了非常有限的HTTP通信模型.它假定它获取HTTP请求(仅传入数据)并返回响应(仅传出数据).这使得强制django成为允许双向通信的websocket概念变得棘手.
我在django-websocket中所做的就是我深入挖掘WSGI的内部和django的请求对象来检索底层套接字.然后,此tcp套接字用于直接处理对websocket实例的HTTP请求的升级.
现在问你原来的问题......
我希望上面的内容显而易见,当建立websocket时,返回HttpResponse是没有意义的.这就是为什么你通常不会在由django-websocket处理的视图中返回任何内容.
但是我想要坚持一个视图的概念,该视图保存逻辑并根据输入返回数据.这就是为什么你应该只使用视图中的代码来处理websocket.
从视图返回后,websocket将自动关闭.这样做是有原因的:我们不希望套接字在未定义的时间内保持打开状态,并依赖客户端(浏览器)关闭套接字.
这就是为什么你不能在视图外部使用django-websocket访问websocket的原因.然后,文件描述符当然设置为-1,表示它已经关闭.
我在上面解释过,我正在挖掘django的周围环境,以某种方式 - 以一种非常黑客的方式 - 访问底层套接字.这是非常脆弱的,也不应该工作,因为WSGI不是为此而设计的!我还在上面解释了websocket在视图结束后关闭 - 但是在websocket关闭之后(并关闭了tcp套接字),django的WSGI实现尝试发送HTTP响应 - 它不知道websockets并认为它在正常的HTTP请求 - 响应周期.但是套接字已经关闭,发送将失败.这通常会导致django中的异常.
这并没有影响我对开发服务器的测试.浏览器永远不会注意到(你知道..套接字已经关闭;-) - 但是在每个请求中引发一个未处理的错误并不是一个非常好的概念,可能会泄漏内存,不能正确处理数据库连接关闭和许多事情这会在某些时候打破,如果你使用的Django的WebSocket比试验更多.
这就是为什么我真的建议你不要使用带有django的websockets.它不适用于设计.Django尤其是WSGI需要彻底检查来解决这些问题(请参阅websockets和WSGI的讨论).从那时起,我建议使用像eventlet这样的东西.Eventlet有一个有效的websocket实现(我从eventlet为django-websocket的初始版本借了一些代码),因为它只是简单的python代码,你可以从django导入你的模型和其他所有东西.唯一的缺点是你需要第二个运行webserver来处理websockets.
正如GregorMüllegger所指出的那样,WSGI无法正确处理Websockets,因为该协议从未被设计用于处理这样的功能. uWSGI,自1.9.11版本,可以处理的WebSockets开箱.这里uWSGI使用原始HTTP而不是WSGI协议与应用程序服务器通信.因此,以这种方式编写的服务器可以处理协议内部并保持连接长时间打开.由Django视图处理长生存连接也不是一个好主意,因为它们会阻止工作线程,这是一种有限的资源.
Websockets的主要目的是让服务器以异步方式将消息推送到客户端.这可以是由其他浏览器触发的Django视图(例如:聊天客户端,多人游戏),或者由django-celery引发的事件(例如:体育结果).因此,这些Django服务的基础是使用消息队列将消息推送到客户端.
为了以可扩展的方式处理这个问题,我编写了django-websocket-redis,这是一个Django模块,它可以使用Redis作为后端消息队列,在一个线程/进程中保持打开所有那些长期存在的Websocket连接.
归档时间: |
|
查看次数: |
7403 次 |
最近记录: |