🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

WebSocket

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

JavaScript

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

Python

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

Q&A

解決済

1回答

1747閲覧

PythonのWebSocketsライブラリで作成したサーバーに、ブラウザからコネクション確立後に即クローズされてしまいます。

gorimattyo23

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

WebSocket

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

JavaScript

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

Python

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

0グッド

0クリップ

投稿2021/03/28 15:55

編集2021/03/30 13:32

前提・実現したいこと

WebSocket通信を使用して、双方向通信を行いたいです。
現在WebSocketの学習をするために、オンライン対戦型のブラックジャックゲームを作成しています。
ブラウザでファイルを開いた時にサーバー側にハンドシェイクを行いに行き、そこからサーバーとの双方国通信を行っていくイメージで作成しているのですが、なかなかうまくいきません。
お知恵をおかしい頂けますと幸いです。

よろしくお願いします。

サーバー側はPythonのWebSocketsライブラリを使用、クライアント側はHTMLとJavaScriptで実装する予定です。

発生している問題・エラーメッセージ

ブラウザでHTMLファイルを開いて、サーバーとのハンドシェイクが確率した後にすぐに接続がクローズされてしまいます。
エラーコードは特に出ていませんので、このファイルをブラウザで開いた時のコンソール出力結果を貼らせていただきます。

console

1connect! 2app.js:13 WebSocket is closed now. 3app.js:14 Close Code = 1000 4app.js:15 Close Reason =

試したこと

WebSocketsライブラリの公式サイトを確認したところ、websocket.recv()を行うと受信処理が終了した後に接続をクローズするという記述があったため、該当場所をコメントアウトしてみましたが、接続確立後に切断される現象は治りませんでした。
色々と調べてみたものの、参考になる情報が見つからず、サーバー側が悪いのか、クライアント側が悪いのかも分からない状況です。

何卒、宜しくお願い致します。

補足情報(FW/ツールのバージョンなど)

・Python 3.6.7
・Python-WebSockets8.1 公式サイト:https://websockets.readthedocs.io/en/stable/intro.html

該当のソースコード

html

1 <body> 2 <h1>ブラックジャック</h1> 3 <h3>名前を入力してマッチ開始!</h3> 4 <p> 5 名前:<input id="username" type="text"> 6 <br> 7 <span id="errMsg"></span> 8 </p> 9 <a id="startMatching" href="">マッチ開始</a> 10 <p id="test"></p> 11 <script src="../client/js/index.js"></script> 12 <script src="../client/js/app.js"></script> 13 </body>

JavaScript

1// index.js 2// マッチ開始ボタン 3const startBtn = document.getElementById('startMatching'); 4const errMsg = document.getElementById('errMsg'); 5const socket = new WebSocket("ws://localhost:8888"); 6let userInfo = { 7 // 0=初期値、1=player1、2=player2 8 'playerNo': 0, 9 'username': '', 10 'roomId': '', 11 // 操作フラグ 1=初期値 12 'flag': 1 13} 14 15socket.onopen = function(event){ 16 // Web Socket接続オープン 17 console.log("connect!"); 18} 19 20 21startBtn.addEventListener('click', function(e) { 22 // マッチ開始ボタンクリック 23 // aタグの無効化 24 e.preventDefault(); 25 26 // エラーメッセージの初期化 27 errMsg.innerHTML = ""; 28 errMsg.style.display = "none"; 29 30 // ユーザー名チェック 31 let userDOM = document.getElementById('username'); 32 let cleanedData = userValid(userDOM.value); 33 if (cleanedData) { 34 // バリデーション通過 35 userInfo['username'] = cleanedData; 36 let a = JSON.stringify(userInfo); 37 console.log(a); 38 socket.send(a); 39 } 40 else { 41 // エラーメッセージ追加 42 errMsg.style.display = "block"; 43 errMsg.innerHTML = "名前は1~8文字の半角英数字でお願いします。"; 44 45 // 処理中断 46 e.stopImmediatePropagation(); 47 } 48}, false); 49 50 51function userValid(word){ 52 if (word) { 53 // 正規表現パターン 54 const regex = new RegExp(/^\w{1,8}$/); 55 if (regex.test(word)) { 56 return word; 57 } 58 else { 59 return false; 60 } 61 } 62 else { 63 // 空の場合 64 return false; 65 } 66} 67

js

1// app.js 2socket.onmessage = function(e) { 3 // メッセージ受信時 4 const reader = new FileReader(); 5 reader.onload = function() { 6 alert(reader.result); 7 let a = document.getElementById('test'); 8 a.innerHTML += reader.result + '<br>'; 9 } 10 reader.readAsText(e.data); 11} 12 13socket.onclose = function(e) { 14 console.log("WebSocket is closed now."); 15 console.log("Close Code = " + e.code); 16 console.log("Close Reason = " + e.reason); 17}; 18

python

1import asyncio 2import websockets 3import json 4 5address = "localhost" 6port = 8888 7# Roomインスタンスを格納するリスト 8# 待機中のルーム 9WAITING_ROOMS = {} 10# ゲーム中のルーム 11PLAYING_ROOMS = {} 12 13# 受信コールバック 14async def server(websocket, path): 15 print(vars(websocket)) 16 print('connect.') 17 # 受信 18 # received_packet = await websocket.recv() 19 # dictionary = json.loads(received_packet) 20 # print("{}: {}".format(path, dictionary)) 21 # 送信 22 # dictionary['message'] = "Hi! Mr:{}.".format(dictionary['username']) 23 # dictionary['bool'] = False 24 # packet = json.dumps(dictionary).encode() 25 print('send') 26 # print(packet) 27 # await websocket.send(packet) 28 29 30start_server = websockets.serve(server, address, port) 31asyncio.get_event_loop().run_until_complete(start_server) 32asyncio.get_event_loop().run_forever()

*追記(ご指摘頂いたように修正)

python

1import asyncio 2import websockets 3import json 4 5 6address = "localhost" 7port = 8888 8 9Users = [] 10 11# 受信コールバック 12async def server(websocket, path): 13 print(websocket) 14 print('connect.') 15 Users.append(websocket) 16 while(True): 17 # 受信 18 19 received_packet = await websocket.recv() 20 # dictionary = json.loads(received_packet) 21 print(type(received_packet)) 22 print("{}: {}".format(path, received_packet)) 23 # 送信 24 # dictionary['message'] = "Hi! Mr:{}.".format(dictionary['username']) 25 # dictionary['bool'] = False 26 # packet = json.dumps(dictionary).encode() 27 print('send') 28 packet = 'Hi! I received :{}'.format(received_packet) 29 for user in Users: 30 await user.send(packet) 31 32 # print(vars(websocket)) 33 34 35 36 37start_server = websockets.serve(server, address, port) 38asyncio.get_event_loop().run_until_complete(start_server) 39asyncio.get_event_loop().run_forever()

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/03/30 02:20 編集

ウェブソケットのサーバーはクライアントが接続している間は無限ループでwsから読み出しが必要です。また必要に応じて書き出しのループを使うこともあります。このコードはそれが無いので終了してしまっているわけです。クライアントのコードを書き出す前にメッセージの書式と手順を設計して、それを実装した方が良いでしょう。ブラウザでいきなりテストせずにnpm install wscat -gしてコマンドでwscat --connect ws://localhost:8888として手で入力してみれば簡単にテストができます。
退会済みユーザー

退会済みユーザー

2021/03/30 06:18

ちなみにdef serverは接続されたクライアントの数だけ同時に走ります。接続数が3ならだけ無限ループも3つあるわけです。そこでグローバルな辞書connections = {}を作ってconnections[websocket]=usernameとかすれば自分以外のソケットを参照して読み書きすることもできるわけです。
gorimattyo23

2021/03/30 12:40

回答いただきありがとうございます。 また、テストの方法等も詳しく記載していただきありがとうございまいただ ご教授頂いた方法で試してみます。
gorimattyo23

2021/03/30 13:39 編集

ご指摘頂いた通り無限ループを作成し、その中で処理を行うように変更したら無事接続を維持したまま通信が行えました。 また、自分以外のソケットにもメッセージを送信することもできるようになりました! さらに、教えていただいたwscat素晴らしいですね!!これからはブラウザと同時に実装するのではなく、ご教授頂いたようにwscatでテストしながらサーバー側をまずは作りこんでいこうと思います!!! ありがとうございました! さて、もしよろしければなにか簡単に回答を書いて頂けませんでしょうか? 是非ベストアンサーをつけさせて頂けたらと思います。 もし不要な場合は自己解決にいたしますが、いかがでしょうか? よろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2021/03/31 05:03

うまく行ったようでよかったです!この先ゲームサーバーを作るには、設計をガラッと変える必要があるでしょう。現状ではwsサーバが主役になっていて、wsのループの中にゲームのロジックを実装するとすぐに行き詰まると思います。主役はゲームサーバーで、ゲームサーバのイベント駆動ループの中で、サブシステムの処理をするイメージです。入室イベントでWAITING_ROOMSに追加とか全部ゲームサーバの仕事ですね。 ベストアンサーは自己解決あるいは他の方の回答でも良いと思います。
gorimattyo23

2021/03/31 14:48

設計方法についてもご説明頂き、ありがとうございます! ゲームサーバーについては勉強不足でして・・・・ でもありがとうございます! 学習して、またわからない箇所があったら質問することもあると思いますので、機会がありましたらまたよろしくお願いいたします。 ベストアンサーの件、承知しました! ありがとうございました!
guest

回答1

0

ベストアンサー

すでに解決されたようですが、WebSocketsライブラリの公式サイトでは次のような書き方が案内されています。ご参考までに。

python

1async def handler(websocket, path): 2 async for message in websocket: 3 print(message)

https://websockets.readthedocs.io/en/stable/faq.html#why-does-the-server-close-the-connection-after-processing-one-message

投稿2021/03/30 14:44

etherbeg

総合スコア1195

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

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

gorimattyo23

2021/03/31 14:49

ありがとうございます! もう一度公式サイトを読み直してみます!! ありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問