私は次の設定をしています:
Python 3.4 を使用して Linux x64 で実行されているのは、受信したメッセージ (タイムスタンプを含む) とこのメッセージのランタイムを出力する ws4py-0.4.2 ブロードキャスト ハンドラーを備えた CherryPy-10.2.1 Web サーバーです。
次に、ws4py を使用してサーバーに接続する 60 のクライアント スレッド (同様の結果で 10、20、50、および 70 のスレッドも使用していました) があります。0.1 秒ごとにタイムスタンプ メッセージを送信します。
サーバー ログ ファイルの約 48500 行の後、メッセージは 10 秒のギャップの後にのみ到着します。ただし、クライアント スレッドは元の速度で送信し続けます。メッセージが送信され、バッファリングされ、10 秒後にのみ解放されるようです。
クライアント スレッドを終了しても、メッセージは失われませんが、ブロックされたメッセージはすべて解放され、ブロードキャスト ハンドラに表示されます (スレッドを実行し続ける時間に応じて、それぞれのランタイムで。クライアント スレッドはその長さを送信します)。
クライアントを閉じsock
て、850回の送信後(51000メッセージ後)に再度接続すると、最初はメッセージがブロックされますが、再接続により、これらのメッセージはすぐに「フラッシュ」され、メッセージがサーバーログに表示されます。
それらのメッセージはどこでブロックされますか? ws4pysend()
関数は を使用して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 年 2 月 7 日更新:
「ブロック動作」の理由はself.sock.sendall()
、ws4py パッケージの websocket.py ファイルでの呼び出しのタイムアウトです。
broadcast()
クラスWebSocketManager
(manager.py)の関数を編集して、例外をログに記録できます。
しかし、この例でこれらのタイムアウトが発生する理由はまだわかりません。私が気付いたことの 1 つWebSocketClient
は、WebSocketBaseClient
.