SocketIo 与 Django 集成

1 python django node.js socket.io

我一直在尝试将 socketio 与 Django 集成,但出现以下错误。

[31/Mar/2020 14:50:27] "GET /socket.io/?EIO=3&transport=polling&t=N4n4ds4&b64=1 HTTP/1.1" 200 117
[31/Mar/2020 14:50:27] "POST /socket.io/?EIO=3&transport=polling&t=N4n4dsj&b64=1&sid=9053be92266c46148304c09833b2ebe8 HTTP/1.1" 200 2
Traceback (most recent call last):
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/wsgiref/handlers.py", line 137, in run
    self.result = application(self.environ, self.start_response)
  File "/Users/murali/yourenv/lib/python3.7/site-packages/django/contrib/staticfiles/handlers.py", line 68, in __call__
    return self.application(environ, start_response)
  File "/Users/murali/yourenv/lib/python3.7/site-packages/engineio/middleware.py", line 60, in __call__
    return self.engineio_app.handle_request(environ, start_response)
  File "/Users/murali/yourenv/lib/python3.7/site-packages/socketio/server.py", line 558, in handle_request
    return self.eio.handle_request(environ, start_response)
  File "/Users/murali/yourenv/lib/python3.7/site-packages/engineio/server.py", line 377, in handle_request
    environ, start_response)
  File "/Users/murali/yourenv/lib/python3.7/site-packages/engineio/socket.py", line 108, in handle_get_request
    start_response)
  File "/Users/murali/yourenv/lib/python3.7/site-packages/engineio/socket.py", line 152, in _upgrade_websocket
    return ws(environ, start_response)
  File "/Users/murali/yourenv/lib/python3.7/site-packages/engineio/async_drivers/eventlet.py", line 16, in __call__
    raise RuntimeError('You need to use the eventlet server. '
RuntimeError: You need to use the eventlet server. See the Deployment section of the documentation for more information.
[31/Mar/2020 14:50:27] "GET /socket.io/?EIO=3&transport=websocket&sid=9053be92266c46148304c09833b2ebe8 HTTP/1.1" 500 59
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 52220)
Traceback (most recent call last):
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socketserver.py", line 650, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socketserver.py", line 720, in __init__
    self.handle()
  File "/Users/murali/yourenv/lib/python3.7/site-packages/django/core/servers/basehttp.py", line 174, in handle
    self.handle_one_request()
  File "/Users/murali/yourenv/lib/python3.7/site-packages/django/core/servers/basehttp.py", line 182, in handle_one_request
    self.raw_requestline = self.rfile.readline(65537)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socket.py", line 589, in readinto
    return self._sock.recv_into(b)
ConnectionResetError: [Errno 54] Connection reset by peer
----------------------------------------
Run Code Online (Sandbox Code Playgroud)

我指的链接https://www.botreetechnologies.com/blog/django-websocket-with-socketio

下面是我的代码:

要求.txt:

enum-compat==0.0.2
eventlet==0.25.1
python-engineio
python-socketio
pytz==2018.7
six==1.10.0
Run Code Online (Sandbox Code Playgroud)

settings.py:在INSTALLED_APPS中添加了socketio:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'socketio'
]
Run Code Online (Sandbox Code Playgroud)

wsgi.py:

import os
import eventlet
import socketio
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'integrate_socketio.settings')

application = get_wsgi_application()
sio = socketio.Server()
application = socketio.WSGIApp(sio, application)
Run Code Online (Sandbox Code Playgroud)

urls.py

from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    #path('admin/', admin.site.urls),
    path('', views.hello, name='hello')
]
Run Code Online (Sandbox Code Playgroud)

视图.py

import eventlet
async_mode = eventlet
import os
from django.http import HttpResponse
import socketio

basedir = os.path.dirname(os.path.realpath(__file__))
sio = socketio.Server(async_mode='eventlet')\

@sio.on('connection-bind')
def connection_bind(sid, data):
    print("sid:",sid,"data",data)

@sio.on('message')
def message(data):
    print(data)
    sio.emit('test',data)
@sio.on('disconnect')
def test_disconnect(sid):
    print("Disconnected")
def hello(data):
    return HttpResponse("Hello")
Run Code Online (Sandbox Code Playgroud)

下面是用nodejs编写的客户端代码,

var io = require('socket.io-client');
var socket = io.connect('http://localhost:8000', {reconnect: false});

socket.on('connect', function (socket) {
    console.log('Connected!');
});
socket.emit('message', 'messgae', 'test msg');
socket.on('test', function (data) {
    console.log(data);
})
Run Code Online (Sandbox Code Playgroud)

跑步:

python manage.py runserver
Run Code Online (Sandbox Code Playgroud)

当我在浏览器中打开http://localhost:8000/时得到响应,但当我运行 nodejs 客户端时出现上述错误。

任何帮助,将不胜感激 :)

提前致谢...!

Abc*_*Bcd 5

问题

问题是实例async_mode的参数socketio.Serversio)。该参数基本上选择运行时使用什么模型。每种模型类型都需要以某种方式运行。默认为async_mode'eventlet'这意味着 SocketIO 服务器需要使用 eventlet 来运行。就您而言,它似乎默认为'eventlet',但您没有使用 eventlet 运行 django 服务器,这会引发错误。要解决此问题,您可以更改sio参数以与您的方式兼容(解决方案 1),也可以配置 wsgi.py 以使用 eventlet 运行服务器(解决方案 2)。


解决方案1

您可以sio按如下方式更改初始化参数:

sio = socketio.Server(async_mode='mode') # Change 'mode' to your mode
Run Code Online (Sandbox Code Playgroud)

您可以'mode'根据服务器的运行方式进行更改。选项是'gevent_uwsgi''gevent'、 或'threading'(或'eventlet'None,但都不能解决您的问题)。

从你的运行语句来看,你没有使用gunicorn或uwsgi,所以在你的情况下,最好使用threadinggevent。(使用gunicorn或uwsgi的说明'gevent'分别'gevent_uwsgi'在底部引用的官方文档中)

如果您使用'threading',则不需要在 wsgi.py 中安装任何内容或更改任何内容(模式除外),但它的性能相对较慢。

如果您使用的是'gevent',则需要安装 gevent,如下所示:

$ pip install gevent
Run Code Online (Sandbox Code Playgroud)

然后,您需要更改 wsgi.py 中的一些设置。如果您安装了 gevent websocket 传输,请将以下内容添加到 wsgi.py 的底部:

from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
pywsgi.WSGIServer(('', 8000), app, 
    handler_class=WebSocketHandler).serve_forever()
Run Code Online (Sandbox Code Playgroud)

如果没有,则添加以下内容:

from gevent import pywsgi
pywsgi.WSGIServer(('', 8000), app).serve_forever()
Run Code Online (Sandbox Code Playgroud)

解决方案2

如果您决定将 wsgi.py 配置为与 eventlet 一起运行,则首先安装 eventlet...

$ pip install eventlet
Run Code Online (Sandbox Code Playgroud)

...并将以下内容添加到 wsgi.py 的底部:

import eventlet
import eventlet.wsgi
eventlet.wsgi.server(eventlet.listen(('', 8000)), application)
Run Code Online (Sandbox Code Playgroud)

引文

我从这个网站官方 socket.io 文档中获取了所有信息。官方文档还提供了使用“解决方案 1”中其他模式的说明