为什么这个ws4py / CherryPy示例会在一段时间后阻止消息?

时间:2018-01-23 16:59:25

标签: python linux websocket cherrypy ws4py

我有以下设置:

使用Python 3.4在Linux x64下运行是一个具有ws4py-0.4.2广播处理程序的CherryPy-10.2.1网络服务器,它将打印收到的消息(包含时间戳)和此消息的运行时。

然后有60个客户端线程(我也使用10,20,50和70个具有类似结果的线程)将使用ws4py连接到服务器。他们每0.1秒发送一次时间戳消息。

在服务器日志文件中大约48500行之后,消息将仅在10秒间隔后到达。但客户端线程继续以原始速度发送。似乎消息被发送,被缓冲并且仅在10秒后被释放。

如果我终止客户端线程,则消息不会丢失,但所有被阻止的消息都会被释放并显示在广播处理程序中(具有各自的运行时,具体取决于您保持线程运行的时间长度。可能是15如果让客户端线程发送那么长时间,则为分钟。)

如果我关闭客户端的sock并在850发送后再次连接(这将是51000消息之后),则消息首先被阻止,但由于重新连接,这些消息被"刷新"不久之后,消息显示在服务器日志中。

这些邮件被阻止在哪里? ws4py send()函数正在使用socket.sendall(),这个发送是一个问题吗?或者是在服务器端阻止了消息(因为如果我杀死了客户端,消息仍会被传递)?

有人知道这种阻止消息吗?

服务器:

# ws4py
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket
from ws4py import configure_logger

# general
import cherrypy
import logging
import datetime
import json

# settings
host_ip = '127.0.0.1'
host_port = 20000
filepath = '/path/to/server.log'
loglevel = logging.INFO

# logger
logger = configure_logger(stdout=True, filepath=filepath, level=loglevel)

# cherrypy
cherrypy.config.update({'server.socket_host': host_ip,'server.socket_port': host_port})
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()


class BroadcastWebSocketHandler(WebSocket):

    def opened(self):
        logger.info("BroadcastWebSocketHandler - opened")

    def received_message(self, message):
        msg = {}
        try:
            msg = json.loads(str(message))
        except Exception as e:
            logger.critical(repr(e))

        if 'timestamp' in msg:
            format_str = '%Y-%m-%d %H:%M:%S.%f'
            dt_now = datetime.datetime.utcnow()
            dt = datetime.datetime.strptime(msg['timestamp'], format_str)
            delta = dt_now - dt
            logger.info("BroadcastWebSocketHandler - received message: {} - runtime: {}".format(str(message), str(delta)))
        else:
            logger.info("BroadcastWebSocketHandler - received message: {}".format(str(message)))

        cherrypy.engine.publish('websocket-broadcast', str(message))


class Root(object):

    @cherrypy.expose
    def index(self):
        return 'Text.'

    @cherrypy.expose
    def ws(self):
        handler = cherrypy.request.ws_handler


if __name__ == '__main__':
    cherrypy.quickstart(Root(), '/', config={'/ws': {'tools.websocket.on': True,
                                                     'tools.websocket.handler_cls': BroadcastWebSocketHandler}})

客户端:

# ws4py
from ws4py.client.threadedclient import WebSocketClient, WebSocketBaseClient
from ws4py import format_addresses

# general
import logging
import json
import time
import datetime
import threading

# settings
host_ip = '127.0.0.1'
host_port = 20000
sleeptime = 0.1
n_clients = 60
filename = '/path/to/client.log'
loglevel = logging.INFO

# logging
log_format = '[%(asctime)-15s] %(message)s'
logging.basicConfig(level=loglevel, filename=filename, format=log_format)

# global
keep_sending = True


def send_messages():
    client = WebSocketBaseClient('ws://{}:{}/ws'.format(host_ip, host_port))
    logging.info('Connecting')
    client.connect()
    while keep_sending:
        time.sleep(sleeptime)
        client.send(json.dumps({'timestamp': datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')}))
    logging.info('Exiting')


if __name__ == '__main__':

    threads = []
    for i in range(n_clients):
        t = threading.Thread(target=send_messages)
        threads.append(t)
        t.daemon = True
        t.start()

    for t in threads:
        try:
            t.join()
        except KeyboardInterrupt:
            keep_sending = False
            logging.info('KeyboardInterrupt')

更新2018年 - 2007年2月:

"阻止行为的原因"是ws4py包的websocket.py文件中调用self.sock.sendall()的超时。

您可以编辑类broadcast()的{​​{1}}函数(manager.py)来记录异常。

但我仍然不知道为什么这个例子会产生这些超时。有一点我注意到,使用线程客户端WebSocketManager而不是WebSocketClient时似乎没有问题。

0 个答案:

没有答案