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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

8029閲覧

C# Socket通信の切断について

akiya_0608

総合スコア14

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2019/06/26 04:54

編集2019/06/26 05:34

質問

C#のソケット通信について質問なのですが、クライアント側が強制終了した場合,サーバー側まで強制終了されてしまうのでどうにか出来ないでしょうか。

サーバーとクライアントが通信しているときにクライアント側でControl+Cで強制終了させてみたところサーバー側が固まってしまいます。
何かアイデアを頂けると幸いです。

サーバー:

C#

1class Program 2{ 3 static void Main(string[] args) 4 { 5 //Server 6 BaseServer listener = new BaseServer(); 7 listener.Init("127.0.0.1", 12345); 8 var task = listener.StartAccept(); 9 10 while (true) 11 { 12 listener.BeginUpdate(); 13 14 if (listener.clientList.Count > 0) 15 { 16 foreach (TcpRecvServer client in listener.clientList) 17 { 18 while (client.RecvDataListCount() > 0) 19 { 20 byte[] data = client.GetRecvDataList(); 21 if(client.Send(data, data.Length)<0) 22 { 23 break; 24 } 25 Console.WriteLine("data合計={0}", client.RecvDataListCount()); 26 } 27 } 28 } 29 30 listener.EndUpdate(); 31 } 32 33 } 34 35} 36class TcpRecvServer 37{ 38 public const int BUFSIZE = 2048; 39 object lockObj = new object(); 40 public Socket socket { get; } 41 public byte[] ReceiveBuffer; 42 public List<byte> recvTempDataList = new List<byte>(); 43 public List<byte[]> recvDataList = new List<byte[]>(); 44 public bool deleteFlg { get; private set; } = false; 45 public bool threadDeleteFlg { get; private set; } = false; 46 public TcpRecvServer(Socket _socket) 47 { 48 socket = _socket; 49 ReceiveBuffer = new byte[BUFSIZE]; 50 } 51 public byte[] GetRecvDataList() 52 { 53 byte[] returnData; 54 lock (lockObj) 55 { 56 returnData = recvDataList[0]; 57 recvDataList.RemoveAt(0); 58 } 59 return returnData; 60 } 61 62 public void AddRecvDateList(byte[] _data) 63 { 64 lock (lockObj) 65 { 66 recvDataList.Add(_data); 67 } 68 } 69 70 public int RecvDataListCount() 71 { 72 int count; 73 lock (lockObj) 74 { 75 count= recvDataList.Count; 76 } 77 return count; 78 } 79 80 81 public int Send(byte[] _sendData, int _dataSize) 82 { 83 int sendSize=-1; 84 85 byte[] sendHeader; 86 87 //header設定 88 sendHeader = BitConverter.GetBytes(_dataSize); 89 //sendBytes作成 90 byte[] sendBytes = new byte[sendHeader.Length + _dataSize]; 91 sendHeader.CopyTo(sendBytes, 0); 92 _sendData.CopyTo(sendBytes, sendHeader.Length); 93 94 try 95 { 96 if (socket.Connected) 97 { 98 sendSize=socket.Send(sendBytes, sendBytes.Length, 0); 99 } 100 else 101 { 102 Console.WriteLine("sendError"); 103 } 104 } 105 catch(System.ObjectDisposedException) 106 { 107 //閉じた時 108 /* 109 System.Console.WriteLine("閉じました。"); 110 this.OnDeleteFlg(); 111 */ 112 } 113 catch (SocketException e) 114 { 115 Console.WriteLine("ソケットが切断されています。"); 116 Console.WriteLine(e); 117 } 118 119 return sendSize; 120 } 121 122 public void OnDeleteFlg() 123 { 124 lock (lockObj) 125 { 126 deleteFlg = true; 127 } 128 } 129 public void OnThreadDeleteFlg() 130 { 131 lock (lockObj) 132 { 133 deleteFlg = true; 134 } 135 } 136 137} 138 139 140class BaseServer 141{ 142 public List<TcpRecvServer> clientList { get;} = new List<TcpRecvServer>(); 143 private List<TcpRecvServer> addClientList = new List<TcpRecvServer>(); 144 private readonly object lockObj=new Object(); 145 Socket listener; 146 147 public BaseServer() { } 148 149 150 public void BeginUpdate() 151 { 152 //addClientListのための排他制御 153 lock (lockObj) 154 { 155 if (addClientList.Count > 0) 156 { 157 clientList.AddRange(addClientList); 158 addClientList = new List<TcpRecvServer>(); 159 } 160 } 161 } 162 163 public void EndUpdate() 164 { 165 if (clientList.Count <= 0) return; 166 167 List<TcpRecvServer> deleteList = new List<TcpRecvServer>(); 168 foreach (TcpRecvServer client in clientList) 169 { 170 if (client.deleteFlg == true) 171 { 172 deleteList.Add(client); 173 } 174 } 175 foreach (TcpRecvServer client in deleteList) 176 { 177 clientList.Remove(client); 178 } 179 } 180 public void Init(string _ip, int _port) 181 { 182 //ListenするIPアドレス 183 IPAddress ipAdd = IPAddress.Parse(_ip); 184 185 //TcpListenerオブジェクトを作成する 186 IPEndPoint ipe = new IPEndPoint(ipAdd, _port); 187 listener = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 188 listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 189 listener.Bind(ipe); 190 listener.Listen(1000); 191 192 } 193 194 public async Task StartAccept() 195 { 196 await Task.Run(() => 197 { 198 while (true) 199 { 200 TcpRecvServer temp =new TcpRecvServer(listener.Accept()); 201 lock (lockObj) 202 { 203 addClientList.Add(temp); 204 Console.WriteLine("接続あり"); 205 } 206 StartReceive(temp); 207 } 208 }); 209 } 210 211 212 //=========================================================================== 213 //recv関係 214 //=========================================================================== 215 //データ受信スタート 216 private static void StartReceive(TcpRecvServer _server) 217 { 218 //非同期受信を開始 219 _server.socket.BeginReceive(_server.ReceiveBuffer, 220 0, 221 _server.ReceiveBuffer.Length, 222 System.Net.Sockets.SocketFlags.None, 223 new System.AsyncCallback(ReceiveDataCallback), 224 _server); 225 } 226 227 228 //BeginReceiveのコールバック 229 private static void ReceiveDataCallback(System.IAsyncResult ar) 230 { 231 //状態オブジェクトの取得 232 TcpRecvServer server = (TcpRecvServer)ar.AsyncState; 233 234 //読み込んだ長さを取得 235 int len = 0; 236 try 237 { 238 if(server.socket.Connected)len = server.socket.EndReceive(ar); 239 } 240 catch (System.ObjectDisposedException) 241 { 242 //閉じた時 243 System.Console.WriteLine("閉じました。"); 244 server.OnDeleteFlg(); 245 return; 246 } 247 248 //切断されたか調べる 249 if (len <= 0) 250 { 251 System.Console.WriteLine("切断されました。"); 252 server.socket.Close(); 253 server.OnDeleteFlg(); 254 return; 255 } 256 257 //受信したデータを蓄積する 258 Array.Resize(ref server.ReceiveBuffer, len); 259 server.recvTempDataList.AddRange(server.ReceiveBuffer); 260 261 //受信用配列のサイズを元に戻す 262 Array.Resize(ref server.ReceiveBuffer, TcpRecvServer.BUFSIZE); 263 264 //データの整形 265 while (server.recvTempDataList.Count>sizeof(int)) 266 { 267 int byteSize = (int)server.recvTempDataList[0]; 268 if (server.recvTempDataList.Count > byteSize+sizeof(int)) 269 { 270 byte[] addData; 271 addData = server.recvTempDataList.GetRange(sizeof(int), byteSize).ToArray(); 272 server.AddRecvDateList(addData); 273 server.recvTempDataList.RemoveRange(0, sizeof(int) + byteSize); 274 } 275 else 276 { 277 break; 278 } 279 } 280 281 //再び受信開始 282 if(server.socket.Connected)server.socket.BeginReceive(server.ReceiveBuffer, 283 0, 284 server.ReceiveBuffer.Length, 285 System.Net.Sockets.SocketFlags.None, 286 new System.AsyncCallback(ReceiveDataCallback), 287 server); 288 } 289 290} 291 292 293

実装環境

mac
visual studio for mac

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

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

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

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

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

guest

回答2

0

自己解決

Releaseモードで実行することで解決致しました。

投稿2019/07/02 01:01

akiya_0608

総合スコア14

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

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

0

クライアント側ではなくサーバー側を修正してください。

投稿2019/06/26 05:05

Zuishin

総合スコア28656

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

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

akiya_0608

2019/06/26 05:36

サーバー側のプログラムを質問に記述してみましたが、どの辺りを修正するべきでしょうか
Zuishin

2019/06/26 05:51

原因を探るには結果を知ることが大きなヒントになると思います。強制終了されるのと固まるのとでは結果が違います。 次にサーバーの方を IDE からデバッグ起動し、クライアントを接続してから一時停止してください。ショートカットはデフォルトで [Shift]+[F5] です。 そして [F11] で一行ずつステップ実行していくと、どこで不具合が生じるのかが特定できます。その際、例外が発生するのであれば、何という例外なのかもメモしておいてください。 これで不具合の原因となる箇所とその種類が特定できるはずです。それを見て、より詳細な調査の方針を決めることになります。
akiya_0608

2019/06/26 14:43

Zuishinさんのおっしゃられるデバッグも既にしておりそこから私の推測では、class BaseServerのReceiveDataCallbackで恐らくエラーが出ているのだと思います。 というのもmain関数内の処理は一通りコメントアウトしてもエラーが出るのですがStartReceiveをコメントアウトするとエラーが出なくなるからです。 ここでいうエラーは「ソースは利用できません。このモジュールのデバッグ情報にはソース情報がありません。」という文言でこれが表示されてプログラムが止まっています。 ちなみにReceiveDataCallbackにブレイクポイントを貼ると別スレッドで切断処理をされてしまうのでエラーが出てくれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問