Python-socketio Server.call() 方法似乎不适用于 JavaScript 客户端

Python-socketio Server.call() method does not seem to work with JavaScript client

总结问题

我正在使用 python-socketio 包作为我正在创建的基于网络的游戏的服务器。我最初在 Python(使用 python-socketio[client])中实现客户端用于调试目的,并在开发时广泛使用 Server.call() 方法。这与 Python 中的所有 运行ning 完美配合,并且在将客户端函数的 return 值发送回服务器之前等待用户输入。

但是,当尝试将事情切换到 JavaScript 时,无论我做什么,Server.call() 都会超时。我真的不知道我可以切换到任何替代方案而不必完全撕开我已经实施的程序,但我愿意接受建议。

描述您尝试过的内容

我已经尝试在 JavaScript 中重新实现我的 Python 客户端代码,或多或少与最初编写的完全一样。这是一个失败,因为正如我上面提到的,任何时候我使用 Server.call() 它都会超时(或者如果我设置 timeout=None 则无限期挂起)。

我还尝试从 Server.call() 切换到使用 Server.emit() 和回调来设置全局变量,然后阻塞直到使用 Server.sleep() 设置它,但是这好像也没用。

显示一些代码

这是一个演示该问题的最小示例。服务器在这两个用例中是相同的,Python 客户端和 JavaScript 客户端实际上是相同的,但只有在使用 Python 客户端时才有效。

这是服务器,用 Python 编写并使用 python-socketio 模块:

# server.py


from socketio import Server, WSGIApp

socketio = Server(async_mode='eventlet', async_handlers=True, cors_allowed_origins='*')

@socketio.on('start')
def start(sid):
    name = socketio.call('get name', to=sid)
    print(name)

if __name__ == '__main__':
    app = WSGIApp(socketio)
    import eventlet
    eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 5000)), app)

这是正在工作的 Python 客户端:

# client.py


import socketio

sio = socketio.Client()

@sio.event
def connect():
    sio.emit('start')

@sio.on('get name')
def get_name():
    print('Sending name')
    return 'Hermione Granger'

if __name__ == '__main__':
    sio.connect('http://localhost:5000', transports=['websocket'])

这是无法工作的 JavaScript 客户端和一些相应的 HTML,所以阅读本文的任何人都拥有重现我的问题所需的一切:

// client.js


var socket = io.connect('http://localhost:5000');

socket.on('connect', function () {
    socket.emit('start');
});

socket.on('get name', function () {
    console.log('Sending name');
    return 'Hermione Granger';
});
<!-- index.html -->


<!doctype html>

<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>

<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
    <script src="client.js"></script>
</body>
</html>

如果有人能帮我弄清楚为什么这不起作用(或推荐一个简单的替代方案),我将感激不尽! :)

记录服务器的输出

这是我尝试 运行 JavaScript 客户端时的服务器日志:

Server initialized for eventlet.
(16261) wsgi starting up on http://0.0.0.0:5000
(16261) accepted ('127.0.0.1', 63733)
2bff7607e60548e5ba70b2dcabb6131d: Sending packet OPEN data {'sid': '2bff7607e60548e5ba70b2dcabb6131d', 'upgrades': [], 'pingTimeout': 60000, 'pingInterval': 25000}
2bff7607e60548e5ba70b2dcabb6131d: Sending packet MESSAGE data 0
2bff7607e60548e5ba70b2dcabb6131d: Received request to upgrade to websocket
2bff7607e60548e5ba70b2dcabb6131d: Upgrade to websocket successful
2bff7607e60548e5ba70b2dcabb6131d: Received packet MESSAGE data 2["start"]
received event "start" from 2bff7607e60548e5ba70b2dcabb6131d [/]
emitting event "get name" to 2bff7607e60548e5ba70b2dcabb6131d [/]
2bff7607e60548e5ba70b2dcabb6131d: Sending packet MESSAGE data 21["get name"]
2bff7607e60548e5ba70b2dcabb6131d: Received packet PING data None
2bff7607e60548e5ba70b2dcabb6131d: Sending packet PONG data None
2bff7607e60548e5ba70b2dcabb6131d: Received packet PING data None
2bff7607e60548e5ba70b2dcabb6131d: Sending packet PONG data None
Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/mnt/c/Users/eshap/Documents/GitHub/dominion-game/venv/lib/python3.8/site-packages/socketio/server.py", line 685, in _handle_event_internal
    r = server._trigger_event(data[0], namespace, sid, *data[1:])
  File "/mnt/c/Users/eshap/Documents/GitHub/dominion-game/venv/lib/python3.8/site-packages/socketio/server.py", line 714, in _trigger_event
    return self.handlers[namespace][event](*args)
  File "server.py", line 7, in start
    name = socketio.call('get name', to=sid)
  File "/mnt/c/Users/eshap/Documents/GitHub/dominion-game/venv/lib/python3.8/site-packages/socketio/server.py", line 386, in call
    raise exceptions.TimeoutError()
socketio.exceptions.TimeoutError

为了比较,这是我成功 运行 Python 客户端时的服务器日志:

Server initialized for eventlet.
(14184) wsgi starting up on http://0.0.0.0:5000
(14184) accepted ('127.0.0.1', 54749)
a5f56db4733b4b1b924b0cb2a599e7c6: Sending packet OPEN data {'sid': 'a5f56db4733b4b1b924b0cb2a599e7c6', 'upgrades': [], 'pingTimeout': 60000, 'pingInterval': 25000}
a5f56db4733b4b1b924b0cb2a599e7c6: Sending packet MESSAGE data 0
a5f56db4733b4b1b924b0cb2a599e7c6: Received request to upgrade to websocket
a5f56db4733b4b1b924b0cb2a599e7c6: Upgrade to websocket successful
a5f56db4733b4b1b924b0cb2a599e7c6: Received packet PING data None
a5f56db4733b4b1b924b0cb2a599e7c6: Sending packet PONG data None
a5f56db4733b4b1b924b0cb2a599e7c6: Received packet MESSAGE data 2["start"]
received event "start" from a5f56db4733b4b1b924b0cb2a599e7c6 [/]
emitting event "get name" to a5f56db4733b4b1b924b0cb2a599e7c6 [/]
a5f56db4733b4b1b924b0cb2a599e7c6: Sending packet MESSAGE data 21["get name"]
a5f56db4733b4b1b924b0cb2a599e7c6: Received packet MESSAGE data 31["Hermione Granger"]
received ack from a5f56db4733b4b1b924b0cb2a599e7c6 [/]
Hermione Granger

问题是您在 JavaScript 版本中对 returning 值使用 Python 样式。在 JavaScript 中,事件是异步的,当您想提供一个 return 值时,您必须使用回调函数来代替。

这是为 JavaScript 编写 get name 事件的正确方法:

socket.on('get name', function (cb) {
    console.log('Sending name');
    cb('Hermione Granger');
});