带有eventlet的Python-socketio使用轮询而不是websockets

时间:2019-06-13 21:06:32

标签: python websocket socket.io python-socketio

问题

我使用带Python 3.7的eventlet 0.25.0和python-socketio 4.0.3,试图将两个Python脚本与websockets进行通信。服务器脚本运行良好:

import socketio   # type: ignore
import eventlet
import json
import util as u  # type: ignore

eventlet.monkey_patch()

WSGI_LOG_FORMAT = '%(client_ip)s "%(request_line)s" %(status_code)s %(body_length)s %(wall_seconds).6f'


class DatabaseServer:
    """ Initializes a server using socketio and eventlet. Use start() and stop() to... start and stop it.
        push() pushes new data to all clients
    """
    def __init__(self):
        self.server = socketio.Server(async_mode='eventlet', namespace='/socket.io')
        self.server.on('connect', self.connect, namespace='/socket.io')
        self.server.on('disconnect', self.disconnect, namespace='/socket.io')
        self.server.on('client_response', self.client_response, namespace='/socket.io')
        self.app = socketio.WSGIApp(self.server)
        self.realtime_timestamp = 0
        self.data_full = None
        self.data_update = None

    def connect(self, sid, environ):
        u.server_logger.info('Client connected: %s', sid)

    def client_response(self, sid, data):
        u.server_logger.info('Client %s sent: %s', sid, data)

    def disconnect(self, sid):
        u.server_logger.info('Client disconnected: %s', sid)

    def push(self):
        u.server_logger.info('Pushing the realime data to web_server')
        with open(u.REALTIME_PARSED_PATH + 'data_full.protobuf.bz2', 'rb') as full_infile, \
                open(u.REALTIME_PARSED_PATH + 'data_update.protobuf.bz2', 'rb') as update_infile:
            self.data_full = full_infile.read()
            self.data_update = update_infile.read()

        self.server.emit('new_data_full', self.data_full, namespace='/socket.io')
        self.server.emit('new_data_update', self.data_update, namespace='/socket.io')

    def server_process(self):
        eventlet.wsgi.server(eventlet.listen((u.IP, u.PORT)), self.app, log=u.server_logger, log_format=WSGI_LOG_FORMAT)

    def start(self):
        u.server_logger.info('Starting eventlet server @ %s:%s', u.IP, u.PORT)
        self.server_thread = eventlet.spawn(self.server_process)

    def stop(self):
        u.server_logger.info('Stopping eventlet server')
        self.server_thread.kill()

而且,我可以通过浏览器轻松地与JS建立websocket连接:

var socket = io.connect('http://127.0.0.1:8000/socket.io');
socket.on('new_data_full', function(data) {
  console.log('got some data_full!');
  socket.emit('client_response', 'thanks!')
})
socket.on('new_data_update', function(data) {
  console.log('got some data_update!');
  socket.emit('client_response', 'thanks!')
})

但是!如果我尝试使用另一个Python脚本创建Websocket连接,则它仅使用轮询,而无法建立Websocket:

import socketio  # type: ignore
import eventlet
import util as u  # type: ignore

eventlet.monkey_patch()

DB_SERVER_URL = f'http://{u.DB_IP}:{u.DB_PORT}'

class DatabaseClient:
    """ doc
    """
    def __init__(self):
        self.client = socketio.Client()
        self.client.on('connect', self.on_connect, namespace='/socket.io')
        self.client.on('disconnect', self.on_disconnect, namespace='/socket.io')
        self.client.on('new_data_full', self.on_new_data_full, namespace='/socket.io')
        self.client.on('new_data_update', self.on_new_data_update, namespace='/socket.io')

    def start(self):
        u.server_logger.info('~~~~~~~~~~~~~~~ Starting Database Client ~~~~~~~~~~~~~~~')
        attempt = 0
        max_attempts = 5
        while True:
            try:
                self.client.connect(DB_SERVER_URL, namespaces=['/socket.io'])
                break
            except socketio.exceptions.ConnectionError as err:
                if attempt < max_attempts:
                    attempt += 1
                    eventlet.sleep(1)
                else:
                    u.server_logger.error('Unable to connect to %s, %s', DB_SERVER_URL, err)
                    return

        eventlet.spawn(self.client.wait())
        u.server_logger.info('Connected to db_server')

    def stop(self):
        self.client.disconnect()

    def on_connect(self):
        u.server_logger.info('Connected to Database Server at %s', DB_SERVER_URL)

    def on_disconnect(self):
        u.server_logger.info('Disconnected from Database Server at %s', DB_SERVER_URL)
        # TODO: handle reconnection!

    def on_new_data_full(self, data):
        u.server_logger.info('Received new data_full')
        self.client.emit('client_response', 'Received data_full', namespace='/socket.io')

    def on_new_data_update(self, data):
        u.server_logger.info('Received new data_update')
        self.client.emit('client_response', 'Received data_update', namespace='/socket.io')

client = DatabaseClient()
client.start()

日志:

2019-06-13 16:33:09.935 INFO 127.0.0.1,127.0.0.1 "GET /socket.io/?transport=polling&EIO=3&t=1560457989.6019762 HTTP/1.1" 200 357 0.000298
2019-06-13 16:33:09.941 INFO Client 7dbe94bde7264ac39d03d55199184f0f sent: Thanks!
2019-06-13 16:33:09.941 INFO 127.0.0.1,127.0.0.1 "POST /socket.io/?transport=polling&EIO=3&sid=7dbe94bde7264ac39d03d55199184f0f HTTP/1.1" 200 175 0.000580
2019-06-13 16:33:09.947 INFO Client 7dbe94bde7264ac39d03d55199184f0f sent: Thanks!
2019-06-13 16:33:09.947 INFO 127.0.0.1,127.0.0.1 "POST /socket.io/?transport=polling&EIO=3&sid=7dbe94bde7264ac39d03d55199184f0f HTTP/1.1" 200 175 0.000526

1 个答案:

答案 0 :(得分:0)

我最终意识到,不仅仅是安装:

pip install python-socketio

我应该做的:

pip install python-socketio
pip install python-socketio[client]

显然,您必须单独安装客户端模块,该客户端模块将安装名为websocket-client的软件包。现在可以使用!