小编典典
我是django-websocket的作者。我不是Websocket和网络领域的真正专家,但是我认为我对所发生的事情有很好的了解。很抱歉,进入细节。即使大多数答案不是特定于你的问题,也可能会在其他时候为你提供帮助。:-)
网络套接字如何工作
让我简短地解释一下什么是网络套接字。Websocket的开始看起来像是从浏览器建立的普通HTTP请求。它通过HTTP标头指示它希望将协议“升级”为Web套接字而不是HTTP请求。如果服务器支持websocket,则表示同意握手,并且服务器和客户端现在都知道它们将使用以前用于HTTP请求的已建立tcp套接字作为连接来交换websocket消息。
除了发送和等待消息外,他们当然还具有随时关闭连接的能力。
django-websocket如何滥用python的wsgi请求环境来劫持套接字
现在,让我们详细了解django-websocket如何在django请求-响应网络中实现HTTP请求的“升级”。
Django通常使用WSGI规范来与Web服务器通信,例如apache或gunicorn等。该规范的设计仅考虑到HTTP的通信模型非常有限。它假定它获取一个HTTP请求(仅传入数据)并返回响应(仅传出数据)。这使得将django强制引入允许双向通信的websocket的概念非常棘手。
我在django-websocket中为实现此目的而做的是,我非常深入地研究了WSGI和django的请求对象以检索底层套接字的内部。然后,此tcp套接字用于直接处理将HTTP请求升级到websocket实例。
现在到你的原始问题…
我希望以上内容可以使我们很明显,当建立一个websocket时,没有必要返回HttpResponse。这就是为什么通常在django-websocket处理的视图中不返回任何内容的原因。
但是,我想坚持一个视图的概念,该视图包含逻辑并根据输入返回数据。这就是为什么你只应在视图中使用代码来处理websocket的原因。
从视图返回后,websocket将自动关闭。这样做是有原因的:我们不想在不确定的时间内保持打开套接字的状态,而不必依靠客户端(浏览器)将其关闭。
这就是为什么你无法在视图外部使用django-websocket访问websocket的原因。然后,当然将文件描述符设置为-1,表明其已关闭。
免责声明
上面我曾解释说,我正在django的周围环境中进行挖掘,以便以一种非常骇人听闻的方式来访问底层套接字。这非常脆弱,而且由于WSGI并非为此而设计,因此也不应该起作用!上面我还解释了视图结束后websocket是关闭的-但是,在websocket关闭(并关闭了tcp套接字)之后,django的WSGI实现尝试发送HTTP响应-它不知道websockets并认为它在正常的HTTP请求-响应周期。但是套接字已经关闭,发送将失败。这通常会在Django中引起异常。
这并没有影响我对开发服务器的测试。浏览器永远不会注意到(你知道..套接字已经关闭;-)-但是在每个请求中引发未处理的错误不是一个很好的概念,并且可能会泄漏内存,无法正确处理数据库连接关闭以及许多麻烦的事情如果你使用django-websocket进行更多的实验,那将在某些时候中断。
这就是为什么我真的建议你不要将Websocket与django一起使用的原因。它不是设计使然。Django(尤其是WSGI)将需要彻底检查以解决这些问题(有关Websockets和WSGI的信息,请参阅此讨论)。从那时起,我建议使用诸如eventlet之类的东西。Eventlet具有有效的websocket实现(我从eventlet借用了django-websocket初始版本的一些代码),由于它只是纯Python代码,因此你可以从django中导入模型和其他所有内容。唯一的缺点是你需要运行另一个仅用于处理WebSocket的Web服务器。
2020-03-30