2012-02-26 9 views
2

この数時間を調査し、これを理解するためにさまざまなことを試しましたが、私は立ち往生しています。私は、複数のスレッドからアクセスする非同期ソケットを作成しようとしています。同じ時刻に近く送信しようとしているスレッドがいくつかあるまでは正常に動作する傾向があります。 EndReceive()がデータを読み込もうとすると、0バイトが返され、ソケットエラーは "success"になります。私はこれが正常なシャットダウンであったことを意味し、サーバーには送信するデータはもうありませんが、接続するサーバーのタイプはすべてのデータを送信してはいけません。サーバーのタイプではありません。読み取るデータは常にあるべきで、閉じてはいけません。多くのパケットを一度に送信すると、非同期ソケットは常に0バイトを読み取る

いくつかのSystem.Threading.Timersがどこに送信されたのかのスレッドは、スレッドセーフではありません。私もSystem.Timers.Timerで試しましたが、同じ結果でした。私はまた、一度にたくさんのパケットを送信するために1つのスレッドしか使用せず、100msの間スリープしていましたが、同じ結果が得られます。

コードを受信するには、以下のとおりです。送信のために、私はちょうど定期的なブロッキングSendとBeginSendを試しましたが、それは違いはありませんでした。

void Receive() 
    { 
     try 
     { 
      if (_datacb == null) 
       _datacb = new AsyncCallback(OnRecvData); 

      byte[] buffer = new byte[FBufferSize]; 
      FSocket.BeginReceive(buffer, 0, FBufferSize, SocketFlags.None, _datacb, buffer); 
     } 
     catch (SocketException ex) 
     { 
      OnSocketError(ex); 
     } 
    } 

    void OnRecvData(IAsyncResult ar) 
    { 
     try 
     { 
      SocketError err; 
      int bytesRead = FSocket.EndReceive(ar, out err); 

      if (bytesRead == 0) 
      { 
       throw new SocketException(); 
      } 

      byte[] buffer = ar.AsyncState as byte[]; 
      FReceived.AddBytes(buffer, bytesRead); 
      ByteBuffer message = FReceived.GetNextMessage(); 
      while (message != null) 
      { 
       Process(message); 
       message = FReceived.GetNextMessage(); 
      } 
     } 
     catch (SocketException ex) 
     { 
      OnSocketError(ex); 
     } 

     Receive(); 
    } 

は、私はそれがあまりにも速く送信するためのソケットをシャットダウンしてサーバーであると考えていたが、私は実際に私はVS2008で行われたブロッキングバージョンを持っていると私は1パケットを送信した50種類のタイマーを使用することができました毎秒と私は切断されなかった。私はVS2010でほとんど同じコードを試しましたbytesReadは0でした。私はVS2008でasycソケットコードを試してみました。ちょっと変わったことがあったのですが、VS2008ではまだ私にbytesRead == 0が与えられています。トン私を抜い:

tcpClient = new TcpClient(host, 443); 
networkStream = tcpClient.GetStream(); 
mReader = new BinaryReader(networkStream); 
mWriter = new BinaryWriter(networkStream); 
receiveMessage = new Thread(new ThreadStart(ReceiveMessages)); 
receiveMessage.Start(); 

private void ReceiveMessages() 
    { 
     while (true) 
     { 
      if ((tcpClient != null) && (tcpClient.Connected)) 
      { 
       if (tcpClient.Available >= 4) 
       { 
        if (!isConnected) isConnected = true; 

        try 
        { 
         ByteBuffer message = new ByteBuffer(); 
         message.AddBytes(mReader.ReadBytes(4)); 
         int mSize = message.ReadInt(); 
         message.AddBytes(mReader.ReadBytes(mSize - 4)); 
         processor.Process(message); 
        } 
        catch (Exception ex) 
        { 
         Print("Recv Msg: " + ex.Message); 
        } 
       } 

       Thread.Sleep(1); 
      } 
} 

を送信:それであまりにも満足していない

mWriter.Write(send); 
mWriter.Flush(); 

を、それがCPUの多くを使用しているため。私は他の方法でこれほど多くのCPUを使わずにこのようなソケットをブロックしようとしましたが、切断する傾向があります。

+0

タイトルに「C#」などのプレフィックスを付けないでください。それがタグのためのものです。 –

+0

これは、例外があってもReceiveを呼び出しているという事実に関連する可能性はありますか?受信は、 "キャッチ"の後ではなく "試行"の最後にあるはずです。IMO –

+0

ブロッキングバージョンは実際にブロックされていますか? IIRCでは、 'tcpClient.Available'は4バイトが利用できるようになるまでブロックしないので、CPUが浪費するsleep(1)ループで待ち時間を浪費します。 –

答えて

0

明らかに、実際の送信とは関係なく、送信されていたデータです。サーバーは、ある種のフィンガープリントが各パケットとともに送信されることを期待していました。あなたが指紋を取得するたびに、値を調整する必要があります。私は実際の送信でスレッドロックを行っていましたが、指紋を計算した部分でロックする必要がありました。いくつかのパケットは間違った指紋で送信されたため、サーバは順番に計算されなかったため、サーバはそのように切断されました。

私はおそらく私の質問でそれを言及すべきでしたが、私はそれが関係していたとは思わなかった。

0

ソケットはスレッドセーフではありません。 here

ソケットへのアクセスを同期させるか、またはすべてのスレッドを処理するようにしてください(よりクリーンで簡単なデバッグにつながると思います)。

+0

あなたが見ると、次の受信は前の受信の終了によってトリガされます。それは完全に正常で安全です –

+0

私は受信がそのように安全だと信じています。送信する限り、私はオブジェクトにロックすることで安全にしようとしました。それは役に立たなかったので、スレッドがパケットを追加できるBlockingCollectionを使用して、1つのスレッドだけがSend()にアクセスしていることを確認しようとしました。私はSystem.Timers.Timerを使用してコレクションを頻繁にチェックし、10msから100msに変更しました。私はまだ0バイトを読み取って最終的に切断して同じ問題に遭遇します。 – baffler

0

ソケット読み取り0バイト。これは正常です。あなたがしなければならないのは、完全なデータパケットが得られるまで、を再度読むことです。これは、サーバーが送信したのと同じ量のバイトをソケットが読み取ることを人々が期待するとき、よくある間違いです。はい、これはしばしば運動です。しかし、実際にはデータが断片化し、データチャンクだけが得られます。したがって、データ断片化が差し迫っているため、コードはソケットからデータチャンクをアセンブルする準備ができているはずです。

関連する問題