Ⅰ. 現在の環境
# | 機能、役割 |
---|---|
1 | WebSocketのみで通信可能なAPIサーバ |
2 | 1と3の仲介を行うサーバ。1にある機能をHTTPアクセス可能なAPIとして実装します。いわゆる1のラッパーとなるサーバ。 |
3 | HTTPのみで通信可能なクライアント |
2の開発・動作環境
Windows 10 64bit
Visual Studio 2017
C# 7.0
ASP.NET としてプロジェクトを作成しました。
Ⅱ. 作りたい物(やりたい事)
1と3を通信させたいです。
しかし、以下の2つの理由の為2のサーバを作成しました。
- 通信プロトコルが異なる
1と3はそれぞれ WebSocket と HTTP でしか通信できません。
1でHTTP通信, 3でWebSocket通信といった事が許されていません。
- WebSocket は一定時間ごとにPingしないと切断されてしまう
2のサーバは常駐するタイプのアプリケーションとして作成しました。
よって、一定時間ごとにPingする事に対応できました。
Ⅲ. 発生している問題
同時に複数リクエストがあった場合失敗してしまう
- 「3のクライアント」から「2のサーバ」に対して同時にリクエストされた場合、
同時にリクエストされた物が全て失敗し、クライアントに正しくレスポンスを返す事ができません。
- エラー内容は無く、WebSocket.csの無限ループを無限に実行している形となってしまう為、クライアントに正しくレスポンスを返すことができていない状態です。
- 「1の上位サーバ」と「2のサーバ」間は複数同時リクエストに問題が無いことは確認がとれています。
以下のプログラムが「2のサーバ」のプログラムです。
UserProfileController.cs
cs
1[Route("api/[controller]")] 2public class UserProfileController : Controller 3{ 4 // 以下のようなリクエストでこの関数が呼ばれる 5 // http://example.com/api/userprofile/1000 6 [HttpGet] 7 public async Task<JsonResult> Get(int userId) 8 { 9 return Json(WebSocket.Instance.GetUserProfile(userId)); 10 } 11}
WebSocket.cs
WebSocket クラスはシングルトンとして作っています。
「2のサーバ」の起動と同時に「WebSocket クラス」のインスタンスが作成(初期化)されます。
cs
1public class WebSocket 2{ 3 private WebSocket websocket; 4 private int messageId = 0; 5 private static Api instance; 6 public static Api Instance 7 { 8 get 9 { 10 if (instance == null) 11 { 12 instance = new Api(); 13 } 14 15 return instance; 16 } 17 } 18 19 private WebSocket() 20 { 21 websocket = new WebSocket($"ws://example.com"); 22 websocket.AutoSendPingInterval = 60; // 60 秒ごとに自動的にPingを送信する 23 websocket.EnableAutoSendPing = true; 24 } 25 26 public async Task<dynamic> GetUserProfile(int userId) 27 { 28 // WebSocket の接続確立後は messageId は常にユニークな数値 29 var tmpMessageId = this.messageId++; 30 31 // ユーザーID 1000のプロファイルを取得する 32 // { "messageId": 1, "action" : "GetUserProfile", "userId" : 1000 } 33 var message = new 34 { 35 messageId = tmpMessageId, 36 action = "GetUserProfile", 37 userId = userId 38 }; 39 40 dynamic response = null; 41 EventHandler<MessageReceivedEventArgs> handler = null; 42 handler = (sender, e) => 43 { 44 // e.Message にはレスポンスのJSONが含まれている 45 // { "messageId" : 1, "result" : { "user_name" : "hoge", "age" : 10 }} 46 var json = (dynamic)JsonConvert.DeserializeObject(e.Message); 47 if (json.messageId == tmpMessageId) 48 { 49 // レスポンスを変数に保存する 50 // この匿名関数ではreturnできない。 51 response = json; 52 } 53 54 // 受信が成功したのでイベントハンドラを消す 55 websocket.MessageReceived -= handler; 56 }; 57 58 // リクエストする前にイベントハンドラを設定する 59 websocket.MessageReceived += handler; 60 61 // リクエストする 62 websocket.send(JsonConvert.SerializeObject(message)); 63 64 // 受信できるまで待つ 65 while(true) 66 { 67 if(response != null) 68 { 69 break; 70 } 71 await Task.Delay(100); 72 } 73 74 return JsonConvert.SerializeObject(response); 75 } 76}
Ⅳ. 聞きたいこと
どの点を改善すれば同時複数リクエストでも失敗しないサーバになりますでしょうか?
また、現在の構成以外でも1と3をうまく通信させる方法はありますでしょうか?
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/13 04:14
2017/05/13 04:39
2017/05/13 05:28 編集
2017/05/13 05:45
2017/05/13 06:24 編集