- PR -

C#でネットワークプログラム(Networkstream について)

1
投稿者投稿内容
未記入
大ベテラン
会議室デビュー日: 2005/08/25
投稿数: 145
投稿日時: 2006-12-21 19:43
MSDNでNetworkStream.EndReadの使用例が掲載されていますが
例のいったいどこで、メッセージを受信しているのでしょうか?

myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

ここでだとは思うのですが、
このコードだとmyCompleteMessageは空のままだと思うのですが、どうでしょうか?

受信したメッセージを引き継いでいるところが見当たりません。

例が正しい場合は、どこでメッセージを引き継いでいるのか教えてください。
また、間違っている場合は、どうすればただしいコードになるのか教えていただけるとうれしいです。

public static void myReadCallBack(IAsyncResult ar ){

NetworkStream myNetworkStream = (NetworkStream)ar.AsyncState;
byte[] myReadBuffer = new byte[1024];
String myCompleteMessage = "";
int numberOfBytesRead;

numberOfBytesRead = myNetworkStream.EndRead(ar);
myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

// message received may be larger than buffer size so loop through until you have it all.
while(myNetworkStream.DataAvailable){

myNetworkStream.BeginRead(myReadBuffer, 0, myReadBuffer.Length,
new AsyncCallback(NetworkStream_ASync_Send_Receive.myReadCallBack),
myNetworkStream);

}

// Print out the received message to the console.
Console.WriteLine("You received the following message : " +
myCompleteMessage);
}

よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2006-12-22 11:55
MSDNの例が間違っていますね。
BeginReadメソッドのパラメータに渡したバイト配列に、勝手にデータが読み込まれるわけですが、MSDNの例では、BeginReadメソッドのパラメータに渡したバイト配列ではなく新しく生成したバイト配列にアクセスしています。
よって、「BeginReadメソッドのパラメータに渡したバイト配列にアクセスしてデータを取得する」が正しいです。
未記入
大ベテラン
会議室デビュー日: 2005/08/25
投稿数: 145
投稿日時: 2006-12-22 22:02
ありがとうございます。やはり、そうでしたか。
やっと、迷宮から抜け出せました。

ただ、そうなってくると、新たな疑問が生じます。

NetworkStream.BeginRead メソッドの
http://msdn2.microsoft.com/ja-jp/library/system.net.sockets.networkstream.beginread(VS.80).aspx

public override IAsyncResult BeginRead (
byte[] buffer,
int offset,
int size,
AsyncCallback callback,
Object state
)

第5引数 Object state は何のためにあるのでしょうか?
存在意義がわかりません。
また、そこからつながってNetworkStream.EndRead メソッドの
http://msdn2.microsoft.com/ja-jp/library/system.net.sockets.networkstream.endread(VS.80).aspx

public static void myReadCallBack(IAsyncResult ar ){

NetworkStream myNetworkStream = (NetworkStream)ar.AsyncState;
byte[] myReadBuffer = new byte[1024];
String myCompleteMessage = "";
int numberOfBytesRead;

numberOfBytesRead = myNetworkStream.EndRead(ar);
myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

// message received may be larger than buffer size so loop through until you have it all.
while(myNetworkStream.DataAvailable){

myNetworkStream.BeginRead(myReadBuffer, 0, myReadBuffer.Length,
new AsyncCallback(NetworkStream_ASync_Send_Receive.myReadCallBack),
myNetworkStream);

}

// Print out the received message to the console.
Console.WriteLine("You received the following message : " +
myCompleteMessage);
}

先頭のpublic static void myReadCallBack(IAsyncResult ar )
の部分でIAsyncResult ar を引き継いで
numberOfBytesRead = myNetworkStream.EndRead(ar);
でarを渡していますよね。渡さなければいけない理由がわからないです。

arを抜いてmyNetworkStream.EndRead()としてデバッグしようと
思いましたが、文法が間違っているということでエラーになります。

何か、他の通信方法に対しての配慮からこのような仕様になっているのでしょうか?

お手数ではございますが、相談に乗っていただければありがたいです。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2006-12-22 22:35
引用:

未記入さんの書き込み (2006-12-22 22:02) より:
第5引数 Object state は何のためにあるのでしょうか?
存在意義がわかりません。


サンプルでは対象のNetworkStreamを渡すのに使ってますね。
この例だけで言えば、なければ動かせないと思うのですが…

引用:

先頭のpublic static void myReadCallBack(IAsyncResult ar )
の部分でIAsyncResult ar を引き継いで
numberOfBytesRead = myNetworkStream.EndRead(ar);
でarを渡していますよね。渡さなければいけない理由がわからないです。


基本的に、非同期実行のプログラミングモデルとして、インターフェイスが
統一されているだけの話です。

ストリームの読み出しでは、こういうことはないかもしれませんが、
他の何らかの処理を非同期実行したい場合、Begin〜を呼び出したオブジェクトが、
同時にはひとつの処理だけを非同期呼び出しするとは限りません。
非同期呼び出しなんですから、2つくらいの処理を平行に呼び出すかもしれません。
このような場合、どの非同期呼び出し(Begin〜)に対応するEnd〜の呼び出しかを、
End〜に伝える必要があります。

AsyncStateも、基本的にはどの呼び出しかを識別できるようにするための情報を
保持するためのものです。
CallBackを使用する場合、AsyncStateのような機構が無いと、どのBegin〜が
完了したのか分かりません。
また、例のように、Begin〜を実行したオブジェクトを引き渡したりするのに
便利でもあります。
※使い方は使用者の自由で、必要なければ使わなければ良い話です。

ストリームの非同期実行と、その他さまざまな非同期実行で、
各々ルールが違うと不便でしょう?
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2006-12-22 23:57
> 第5引数 Object state は何のためにあるのでしょうか?
> 存在意義がわかりません。
非同期(Begin〇〇系)メソッドには、AsyncCallback型とObject型のパラメータが必ずあります。この例では、myReadCallBackメソッド内でEndReadメソッドを呼び出すために、NetworkStreamオブジェクトを渡しています。他にも、stateというパラメータ名が示しているように、(Begin〇〇メソッドの)呼び出し元の情報を伝えるために使われるようです。(私はあまり詳しくないので断言できませんが。。。)

> 先頭のpublic static void myReadCallBack(IAsyncResult ar )
> の部分でIAsyncResult ar を引き継いで
> numberOfBytesRead = myNetworkStream.EndRead(ar);
> でarを渡していますよね。渡さなければいけない理由がわからないです。
例えば、Begin〇〇メソッドを立て続けに複数回呼び出したとします。
すると、AsyncCallbackデリゲートは立て続けに複数回呼び出されます。そのとき、IAsyncResultオブジェクトを渡すことによって、どの(Begin〇〇メソッドの)呼び出しに対応しているのかを知らせる必要があるわけです。
なお、End〇〇メソッドは、Begin〇〇メソッドによって開始した非同期処理が終了するまで待機します。

> arを抜いてmyNetworkStream.EndRead()としてデバッグしようと
> 思いましたが、文法が間違っているということでエラーになります。
EndReadメソッドに、パラメータを受け取らない形式のオーバーロードは存在しないので、当然コンパイルは通りません。


Begin〇〇メソッド・End〇〇メソッドによる非同期プログラミングは少々難しいので、以下のページで学習することをお勧めします。

非同期プログラミングのデザイン パターン
http://msdn2.microsoft.com/ja-jp/library/ms228969(VS.80).aspx


# もたもたしているうちに、回答が付いてますね orz せっかく書いたので一応投稿させてもらいます^^;
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2006-12-23 00:17
すみません、いくつか書き忘れてたことがありました。

もしEnd〇〇メソッドの戻り値を受け取る必要がないのならば、End〇〇メソッドを呼び出す必要はありません。
End〇〇メソッドを呼び出さなくても、IAsyncResultプロパティのIsCompletedプロパティで、非同期操作が完了したかどうかを調べることができます。

また、AsyncCallbackデリゲートも必須ではありません。AsyncCallbackデリゲートが不要な場合は、Begin〇〇メソッドのAsyncCallbackパラメータとObjectパラメータにnullを指定します。
その場合、Begin〇〇メソッドの戻り値でIAsyncResultオブジェクトが返されるのでそれを受け取ります。理由は、先に述べたように、非同期処理が完了したかどうかを、IAsyncResultのIsCompletedプロパティで調べることができるためです。調べないのなら受け取らなくていいです。NetworkStreamのBeginReadメソッドの場合は調べなきゃまずいと思いますが。


[ メッセージ編集済み 編集者: よこけん 編集日時 2006-12-23 00:19 ]
1

スキルアップ/キャリアアップ(JOB@IT)