質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1248閲覧

pythonのwebsocketでリアルタイム表示時に更新すると止まる

takadaimiku

総合スコア76

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/10/18 10:03

編集2022/10/18 10:11

以下の様なHTMLとPythonファイルがあります。
クライアント接続されたらカウントを表示するプログラムです。
しかし、表示される→更新すると止まる→更新すると表示されるを繰り返します。
更新すると2回に一回はカウントが表示されません。
どの様にすれば更新しても毎回カウントが表示されますか?

html

1<html> 2<head> 3 <script src="http://code.jquery.com/jquery-latest.min.js"> 4 </script> 5 <script> 6 $(function(){ 7 var ws = new WebSocket("ws://localhost:9999/"); 8 var log = ""; 9 ws.onmessage = function(message){ 10 log = message.data; 11 document.getElementById("txt").innerHTML = log; 12 } 13 }) 14 </script> 15</head> 16 17<body> 18 message: <br> 19 <div id = "txt"></div> 20</body> 21 22</html>

python

1from websocket_server import WebsocketServer 2import time 3 4class Test: 5 def __init__(self): 6 print('開始') 7 self.count=0 8 server = WebsocketServer(port=9999, host="localhost") 9 server.set_fn_new_client(self.new_client) 10 server.run_forever() 11 12 def new_client(self,client, server): 13 while True: 14 server.send_message_to_all(str(self.count)) 15 print(self.count) 16 self.count=self.count+1 17 time.sleep(1) 18 19if __name__ == '__main__': 20 test=Test()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

問題点
new_client はクライアントが新規接続時に呼ばれるイベントハンドラなので
この中で時間の掛かるループ等は行ってはいけません。(イベント駆動型プログラミングでの注意点)
イベントハンドラとして呼び出される関数は即座に終了しないと、他のメッセージ送受信処理を止めてしまいます。

websocket server から自発的に定期メッセージを送信したい場合は、
タイムをカウントするループを別スレッドを作成する必要があります。

実装例(概要のみ

  • new_client でカウントループを別スレッドで起動
  • client_left でカウントループが終了するように

注意点
過去のバージョンの websocket_server ライブラリはマルチスレッドで安全に扱える実装とはなってません。
過去のREADME内に記載有り。送信タイミングが被ると意図しないメッセージが送られる可能性があります。

確認事項
send_message_to_all は接続中の全てのクライアントにメッセージを送りますが、
2つ以上の画面で websocket サーバーに接続した時、意図された挙動になりますか?

他に代案としてとれる実装は、
JavaScript 側の setInterval で、毎秒 websocker server へ何かのメッセージを投げかけて
そのメッセージに対する返信 message_recieved ハンドラ内でカウント数を送出するようにする、等。

他の実装案2:
asyncio を用いた他の websocket ライブラリでは
接続時に呼び出されるハンドラ内に、ループ処理で非同期に実行されるコードを書けます。


サーバーを別スレッドで実行するコードのサンプルを追記

python

1 2import time 3from websocket_server import WebsocketServer 4 5def main() -> None: 6 """ 7 この利用では変数 count は数値型なので問題ありませんが、 8 この利用例 (run_forever(threaded=True)) では new_client 関数は別スレッドで呼ばれる為、 9 複数スレッドから参照されるオブジェクトを扱う際は、排他制御を独自に行う必要があります。 10 11 websocket サーバに対する複数スレッドからの同時メッセージ送信については 12 websocket_server ライブラリが最新であれば問題ありません。過去バージョンではマルチスレッドに未対応。 13 """ 14 count = 0 15 16 def new_client(client, server): 17 # 新規接続時にリセット 18 nonlocal count 19 count = 0 20 21 server = WebsocketServer(port=9999) 22 server.set_fn_new_client(new_client) 23 server.run_forever(threaded=True) 24 25 while True: 26 count += 1 27 server.send_message_to_all(f"{count}") 28 time.sleep(1) 29 30if __name__ == '__main__': 31 main()

投稿2022/10/18 12:05

編集2022/10/18 13:54
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takadaimiku

2022/10/18 12:36

ありがとうございます!!そもそも作りたい動きに対し、new_clientで実行すること自体が良い方法ではないこと通関しました! 確認事項 2つ以上の画面で確認したところ意図した挙動となっていました。 一応作りたかったものとしてはpython内の変数をリアルタイムに表示させるwebページだったので、new_clientのイベントハンドラは必要なく、websocketサーバーを起動と同時にwhile文でsend_message_to_allし続けるプログラムの形にしました。
takadaimiku

2022/10/18 12:37

変更後のコードは以下 from websocket_server import WebsocketServer import time import threading class Test: def __init__(self): print('websocketサーバー開始') self.count=0 server = WebsocketServer(port=9999, host="localhost") run_thread = threading.Thread(target=server.run_forever) run_thread.start() self.loop(server) def loop(self,server): while True: server.send_message_to_all(str(self.count)) self.count=self.count+1 print(self.count) time.sleep(1) if __name__ == '__main__': test=Test()
teamikl

2022/10/18 13:40

全接続で共通なのであれば別アプローチもあって、 run_forever の引数にスレッドで実行できるものがあり、 メイン側でループ処理という方法もとれるようです。回答にコードを追記しました
teamikl

2022/10/18 21:35 編集

上のコメントのコードに関しては、 恐らく接続の数だけカウントループのスレッドが走ってしまい、 接続が切れても残り続ける為、client 側の onmessage 内で console.log(msg) すれば 複数画面でページを開いた時、メッセージが多重に送られるのが確認できると思います。 訂正: 上のコメントのコードは、カウントループは一つのみなので大丈夫でした。 countの値が、接続毎に固有なのか、全接続で共通なのかで対処法が変わるところですが、 send_message_to_all でよいのであれば、値は全接続で共通になるはずなので、 カウントループは接続毎に個別ではなく、全体で一つで良くなります。
takadaimiku

2022/10/18 14:20

ご丁寧にありがとうございます。 より、シンプルに書くことができそうです。 非常に参考になりました。ありがとうございました!
takadaimiku

2022/10/19 01:08

ちなみに作成したwebsocketサーバー(server = WebsocketServer(port=9999, host="localhost"))を終了させる方法ご存じではないでしょうか? server.close()的なメソッドが見つからなくて困っていますTT
teamikl

2022/10/19 06:57

別質問を建てられて回答済みだったようなので、 そちらにマルチスレッドの場合の補足説明を寄せました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問