我有以下设置:
使用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')
"阻止行为的原因"是ws4py包的websocket.py文件中调用self.sock.sendall()
的超时。
您可以编辑类broadcast()
的{{1}}函数(manager.py)来记录异常。
但我仍然不知道为什么这个例子会产生这些超时。有一点我注意到,使用线程客户端WebSocketManager
而不是WebSocketClient
时似乎没有问题。