2011-08-17 25 views
5

シリアルポートのDataReceivedイベントを模倣するシステムを実装しました。これにより、TCPClientオブジェクトのNetworkStreamからのデータの読み取りは、BeginRead()別のスレッドからの次のメソッドを呼び出しますC#でBeginRead()を呼び出した後にNetworkStreamを閉じる

TcpClient server = new TcpClient(); 
server.Connect(IPAddress.Parse(ip), 10001); 
server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), server.GetStream()); 

は:

private void DataReceived(IAsyncResult result) 
    { 
     res = result; 
     server.GetStream().EndRead(result); 

     //append received data to the string buffer 
     stringBuffer += System.Text.ASCIIEncoding.ASCII.GetString(buffer); 

     //clear the byte array 
     Array.Clear(buffer, 0, buffer.Length); 

     //trigger the parser 
     waitHandle.Set(); 

     server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), buffer); 
    } 

これは正しく動作しているように見えます。私は問題のないネットワーク上のデバイスにデータを送受信できます。しかし、私は次のメソッドを使用して接続を切断しようとすると、プログラムがクラッシュ:

public override void disconnect() 
{ 
    server.Close(); 
} 

これは、次のエラーがスローされます。

A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll 

は、私はまた、次のようにdisconnectメソッドを実装しようとしている:

server.GetStream().Close(); 

この結果、次のエラーが発生します。

A first chance exception of type 'System.InvalidOperationException' occurred in System.dll 

これは、BeginRead()メソッドが呼び出され、EndRead()メソッドが呼び出されていないという事実と関係があります。その場合、ストリームをクラッシュさせずにストリームを閉じることはできますか?

+1

EndRead()呼び出しのまわりでtryブロックを使用して、ObjectDisposedExceptionを捕捉できるようにする必要があります。ソケットが予期せず閉じられたことを示す信頼できる指標です。 –

+1

私はこの問題を発見しました。 EndRead()メソッドとBeginRead()メソッドの呼び出しがtry/catchブロックに囲まれていないため、 '' System.ObjectDisposedException ''を取得していました。ストリームを閉じたとき、これらのメソッドはもはや存在しなかったオブジェクトで実行しようとしていました。 – isometrik

+0

これらの回答を確認してください。それらは同じ質問に関するものです:http://stackoverflow.com/questions/43096943/how-to-stop-reading-from-networkstream/43101953#comment73305491_43101953 –

答えて

1

私はGetStreamをちょうど1回呼び出して、その結果をどこかに保存し、それをストリームにアクセスするために使用します。すべてのために使用nstrmNetworkStreamへのアクセス

Stream nstrm = server.GetStream(); 

...

最も安全な方法は閉鎖し、ちょうどdisconnect()でそのフラグを設定するためのフラグを維持するだろう。

DataReceived

直接もしそのフラグのEndRead確認後、あなたはこれを行うに設定されます:

server.Close(); 
nstrm.Close(); 

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.getstream.aspx

EDITを参照してください - コメントどおり:

if (flag2Close) 
{ 
    server.Close(); 
    nstrm.Close(); 
    flag2Close = false; 
} 
else 
{ 
    nstrm.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), buffer); 
} 

BTW:プロダクションコードでは、例外処理などが必要です。

+0

これは機能しますが、 EndRead()が呼び出されると、接続を終了する前にデータを受信する必要があります。だから、私が接続していたら、接続を解除してからもう一度接続すると、接続が一度も閉じられていないので、エラーが発生します。私が接続し、切断し、いくつかのデータを送信した後、再び接続すると動作します。 – isometrik

+0

私は理解していません... TcpClientを閉じるためにフラグを処理し、ストリームは完全にあなた次第です - あなたは次のBeginReadの前に直接チェックを入れ、BeginRead IF偽です...上記の私の編集を参照してください – Yahia

+0

はい、BeginRead()メソッドが呼び出されると、DataReceivedメソッドがコールされ、データが受信されるまでブロックされます。つまり、データが受信されたときに発生するメソッドの次の反復まで、フラグはチェックされません。 – isometrik

関連する問題