2011-11-17 9 views
6

最近、私は.Net同期受信メソッドの奇妙な動作に取り組んでいます。私はデータを送受信することによって互いに通信するノードを持つアプリケーションを書く必要がありました。各サーバーにはシリアライズされたレシピ・ループがあり、シリアライズされたクラスを受け取った後、シリアライズされて処理されます。その後、(AsynchSendToを使用して)このシリアル化されたクラスをいくつかの選択されたノードに非同期で送信します。.NET C#同期受信はブロックされません

MSDNを明確にすることを言います:あなたは、接続指向のソケットを使用している場合は、バッファのサイズまで、利用可能であるとして、受信方法 は、できるだけ多くのデータを読み込みます

」 場合。リモートホストはシャットダウン メソッドでソケット接続をシャットダウンし、利用可能なすべてのデータを受信した場合、受信方法 はすぐに完了し、ゼロバイトを返します。

私の場合、それは真実ではありません。 Receiveが接続を確立した直後に0バイト(非確定的なシチュエーション)をブロックして返さないランダムなケースがいくつかあります。私は、送信者が少なくとも1000バイトで送信していることを100%確信しています。もう一つの面白い事実:スリープ(500)を入れる前にすべてうまく動作します。以下は、受信コードです:

また
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
try 
{ 
    _listener.Bind(_serverEndpoint); 
    _listener.Listen(Int32.MaxValue); 
    while (true) 
    { 
     Console.WriteLine("Waiting for connection..."); 
     Socket handler = _listener.Accept(); 

     int totalBytes = 0; 
     int bytesRec; 
     var bytes = new byte[DATAGRAM_BUFFER]; 
     do 
     { 
      //Thread.Sleep(500); 
      bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None); 
      totalBytes += bytesRec; 
     } while (bytesRec > 0); 

     handler.Shutdown(SocketShutdown.Both); 
     handler.Close(); 
    } 
} 
catch (SocketException e) 
{ 
    Console.WriteLine(e); 
} 

送信部:

public void AsynchSendTo(Datagram datagram, IPEndPoint recipient) 
{ 

    byte[] byteDatagram = SerializeDatagram(datagram); 
    try 
    { 
     var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     socket.BeginConnect(recipient, ConnectCallback, new StateObject(byteDatagram, byteDatagram.Length, socket)); 
    } 
    catch (SocketException e) 
    { 
     Console.WriteLine(e); 
    } 
} 

public void ConnectCallback(IAsyncResult result) 
{ 
    try 
    { 
     var stateObject = (StateObject)result.AsyncState; 
     var socket = stateObject.Socket; 
     socket.EndConnect(result); 
     socket.BeginSend(stateObject.Data, 0, stateObject.Data.Length, 0, new AsyncCallback(SendCallback), socket); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("catched!" + ex.ToString()); 
    } 
} 

public void SendCallback(IAsyncResult result) 
{ 
    try 
    { 
     var client = (Socket)result.AsyncState; 
     client.EndSend(result); 
     client.Shutdown(SocketShutdown.Both); 
     client.Close(); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); 
    } 
} 

class StateObject 
{ 
    public Byte[] Data { get; set; } 
    public int Size; 
    public Socket Socket; 
} 

私の質問:私は、同期は間違った方法で受信使用していますか?受信するデータがあるのにイベントをブロックしないのはなぜですか?

+0

あなたの質問は、読解前に睡眠中に解決されている問題に関するものではないので、一度にたくさん読んでいる場合、各ループの半分の時間が実際に待ち時間を取ることができるので、100msecのような小さなスリープ時間で読んだ後に眠ってみましたか?これはシリアルポートからの読み込みで私にとってはうまくいきましたが、データ受信イベントも発生しました。 – jlafay

+0

これはちょうどソケットが動作する方法ではありません。すべてのtry/catchブロックを削除して診断を開始します。 –

答えて

4

あなたは足で自分を撃っています。接続の先頭に

bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None); 

Availableは、代わりに0ですぐに返すように強制的に、0になります、あなたはそれは、その後、あなたのバッファ(例えばbytes.Length-totalBytes)に自由であるバイト数を指定する必要がありますまたブロックされます。

6

ここで並行性の問題が発生している可能性があります。接続を受け入れると、すぐに受信にジャンプします。送信者プロセスは、送信する呼び出しに達するのに十分な時間がない可能性があります。したがって、handler.Availableは0であり、受信が戻ります。

これは、500msのスリープを追加したときに「バグ」が発生しない理由です。

+0

あなたは正しいですが、7分遅れて) – Lucero

+0

私はまた、500ミリ秒がそれを修正する理由を追加したと思います。私はあなたの答えをコピーしていませんでした... – Tudor

+0

申し訳ありません、私の意図はあなたの答えを私のものからコピーされたかのように見せることではありませんでした。それにもかかわらず、彼らは本質的に同じことを言います - 私は暗黙のうちに、 "最初から..."という文章で遅れて異なる行動に取り組んでいます。 ;) – Lucero

関連する問題