C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: AcceptTcpClientについて


(過去ログ 113 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■66801 / inTopicNo.1)  AcceptTcpClientについて
  
□投稿者/ katsu (3回)-(2013/05/28(Tue) 17:50:09)

分類:[.NET 全般] 

サーバーを作成しています(VS2010、C#)

クライアント8軸から13秒ごとに30000データ受取り、受け取ったデータを、表示、保存しています(非同期)

サーバーがAcceptTcpClientで接続待ちしている状態で、クライアントが接続しようとしても107秒程度待たされることがあります
発生頻度:100回に1〜2回程度
発生タイミング:軸によってバラバラ、同じタイミングもある

改善策をご教授お願いします

下記にプログラムを記します

private void Form2_Load(object sender, EventArgs e)
{
// ワーカースレッドの作成と開始
work = new System.Threading.Thread(DoWork);
work.Start();
}

public void DoWork()
{
byte[] rcv_data = new byte[50000];
// リスナーを作成すると開始
server = new TcpListener(IPAddress.Any, 51001);
server.Start();
try
{
while (true)
{
// クライアントからの接続を受け付ける
TcpClient client = server.AcceptTcpClient();
client.ReceiveBufferSize = 50000;
NetworkStream stream = client.GetStream();
while (true)
{
// 受信データの読み出し
len = stream.Read(rcv_data, 0, rcv_data.Length);
str += System.Text.Encoding.ASCII.GetString(rcv_data, 0, len);
if (str.EndsWith("END")) break; //末尾"END"受信完了
}
client.Close();
 stream.Close();
data_save(); //受信データをテキストファイルに保存
 plot(); //グラフ表示
}
}
catch (Exception ex)
{
System.Console.WriteLine(ex.Message);
}
}
引用返信 編集キー/
■66803 / inTopicNo.2)  Re[1]: AcceptTcpClientについて
□投稿者/ オショウ (75回)-(2013/05/28(Tue) 18:15:27)
> クライアント8軸から13秒ごとに30000データ受取り、受け取ったデータを、表示、保存しています(非同期)

  13秒毎にオープンして受信してクローズして・・・
  なので、クローズしないで受信し続けるようにしたら?

  もしくは、UDPで受信し続けるように変更するとか。

以上。参考まで
引用返信 編集キー/
■66822 / inTopicNo.3)  Re[2]: AcceptTcpClientについて
□投稿者/ katsu (4回)-(2013/05/29(Wed) 17:40:48)
オショウ 様

早速の回答ありがとうございます

プログラムの記述がおかしいわけではないと言う事でしょうか?

オショウ様の仰るとおりにcloseなしにデバッグしてみようと思います

ただ、クライアントが途中で電源を落とす可能性があります
この時、クライアントは接続要求から始まりますが、サーバーは、受信待ちの状態です

クライアントの電源が落ちた時に、サーバーも接続待ちに戻る良い方法が思い浮かびません

何か良い方法は、あるでしょうか?
ご教授頂けると幸いです
引用返信 編集キー/
■66843 / inTopicNo.4)  Re[3]: AcceptTcpClientについて
□投稿者/ 名無しのプログラマ (1回)-(2013/05/30(Thu) 20:12:48)
サーバーのListen処理は複数クライアントからの接続を受け入れるように記述するのが基本
だと思います。
// クライアントからの接続を受け付ける
TcpClient client = server.AcceptTcpClient();
ここでクライアントからの接続を受け入れたら受信処理はTcpClient clientを引数とした
受信スレッドで行って、そのスレッドを生成したら直ちに
// クライアントからの接続を受け付ける
TcpClient client = server.AcceptTcpClient();
の部分に戻らないと別クライアントからの接続を受けることができません。たぶん。少なく
ともCを使ったサーバープログラミンではそのように記述します。C#でも同様ではないです
か??
引用返信 編集キー/
■66844 / inTopicNo.5)  Re[3]: AcceptTcpClientについて
□投稿者/ オショウ (76回)-(2013/05/30(Thu) 20:49:46)
> ただ、クライアントが途中で電源を落とす可能性があります
> この時、クライアントは接続要求から始まりますが、サーバーは、受信待ちの状態です
>
> クライアントの電源が落ちた時に、サーバーも接続待ちに戻る良い方法が思い浮かびません

  セッション切断時に、そのイベントをサーバー側は知ることができますので
  それによって、受信待ちからクローズし、リッスン状態に遷移する。

  と言うコーディングになります。

  結果的には、TCP/IPのプログラムの作り方が悪い。と言うことです。

  なので、UDPの方では?と書いたまで。

以上。
引用返信 編集キー/
■66850 / inTopicNo.6)  Re[3]: AcceptTcpClientについて
□投稿者/ 甕星 (12回)-(2013/05/31(Fri) 01:23:52)
No66822 (katsu さん) に返信
>サーバーがAcceptTcpClientで接続待ちしている状態で、クライアントが接続しようとしても107秒程度待たされることがあります

おそらくserver.Start();でキューの数を指定していないからです。

あなたの実装では複数のクライアントからの接続要求と通信を、一つのスレッドで裁いています。一つのクライアントとの通信が完了するまで他のクライアントは通信を出来ません。このとき処理終了まで接続要求を保留しておきたいなら、同時に8台からの接続要求を処理できるように8以上の数を指定する必要がありますが、引数を指定していないためにTCPプロトコルスタックはバックエンドでクライアントに対して接続エラーを返しているものと思います。


> ただ、クライアントが途中で電源を落とす可能性があります
> この時、クライアントは接続要求から始まりますが、サーバーは、受信待ちの状態です
>
> クライアントの電源が落ちた時に、サーバーも接続待ちに戻る良い方法が思い浮かびません

ええ、その通りで良い方法はありません。

この状態はハーフオープンと言われて、TCPを使用する上での古くからの問題点の一つです。解決方法としてはKeepAliveオプションを有効にする(数時間毎に生存監視のための通信をバックグラウンドで行なう機能です)を有効とするか、アプリケーションプロトコルレベルでタイムアウト等により通信相手の消失を検知するための機能を設けることになります。

接続クライアント数が少ないなら、まず基本に忠実に接続要求を受け付けるスレッドと、通信を行なうスレッドを分けたら良いでしょう。同じクライアントから再接続を受けたら、以前のクライアントとの接続を破棄するようにしてはいかがかと。
引用返信 編集キー/
■66852 / inTopicNo.7)  Re[4]: AcceptTcpClientについて
□投稿者/ katsu (5回)-(2013/05/31(Fri) 11:27:25)
オショウ様、名無しのプログラマ様、甕星様
回答ありがとうございます

重要なことを記述おらず、申し訳ありません
formを12個用意し、各々でスレッドを作成しています

クライアント1軸に対し、スレッド1つ

form2:TcpListener(IPAddress.Any, 51001);
form3:TcpListener(IPAddress.Any, 51002);
・・・
form9:TcpListener(IPAddress.Any, 51008);
・・・
form13:TcpListener(IPAddress.Any, 51012);

form2〜form9を使用
4つ(form10〜form13)は、クライアントがいないので常に接続要求待ち

クライアントは、接続要求→データ送信→切断(繰り返し)
クライアントIPadress:192.168.xxx.201〜208

「IPAddress.Any」の代わりに「192.168.xxx.201〜208」を入れると早くならないかなぁ?
と思いましたが、IPAddress.Parse("192.168.xxx.201")でエラーが発生
書き方がわからず格闘中です

初めから書いとけよとお叱りを受けそうですが、何かしら意見お願いします

引用返信 編集キー/
■66888 / inTopicNo.8)  Re[5]: AcceptTcpClientについて
□投稿者/ 甕星 (13回)-(2013/06/02(Sun) 05:39:30)
No66852 (katsu さん) に返信
> 「IPAddress.Any」の代わりに「192.168.xxx.201〜208」を入れると早くならないかなぁ?
> と思いましたが、IPAddress.Parse("192.168.xxx.201")でエラーが発生
> 書き方がわからず格闘中です

そういう使い方のパラメーターじゃ無いです。

サーバー側に複数のNICやIPアドレスがある場合に、サーバー側で使うIPアドレスを指定するパラメーターです。例えばサーバー側が192.168.1.1と192.168.2.1の二つのIPアドレスを漏っている場合、192.168.1.1を引数で指定していれば、192.168.1.1当ての接続要求にだけ応答し、192.168.2.1当ての接続要求を無視すると言うことが出来ます。

クライアントのIPアドレスを指定するパラメーターではありません。
引用返信 編集キー/
■66897 / inTopicNo.9)  Re[6]: AcceptTcpClientについて
□投稿者/ katsu (6回)-(2013/06/03(Mon) 18:03:28)
甕星様

> クライアントのIPアドレスを指定するパラメーターではありません。
理解しました
ありがとうございます

サーバーがAcceptTcpClientで接続待ちで時間がかかる件ですが、毎回closeせずに受信待ちし、
お甕星様の助言通り、KeepAliveを使い、切断を検知すると、接続待ちとすることでスムーズに動くようになりました

まだ、接続待ちに時間がかかることが気にかかりますが解決とさせて頂きます
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -