1

次の要件を満たすネットワーク ライブラリを c# で開発したいと考えています。

  • 双方向の複数のリクエストに同じ接続を使用する
  • 次のような簡単なラッパーメソッドを提供しますresponse = Connection.Send(message);
  • SSL をサポートします (これが、SocketAsyncEventArgs を使用しない理由です)。

基本的に私は2つのスレッドを持っています:

  • 最初のスレッドは受信メッセージを (同期的に) リッスンし、すべてをディスパッチします
  • 2 番目のスレッドは要求処理を担当します

したがって、基本的にコードは次のようになります (非常に短縮されます)。

BlockingCollection _receivingQueue;
ConcurrentDictionary <MessageID, ResponseHandlerDelegate> _responseHandlers;
Dictionary <MessageID, Message> _responses;

void ListeningThread()
{
     while(true)
     {
          Message = ReadNetworkStream();
          _receivingQueue.Add(Message);
     }
}

void ProcessingThread()
{
      if(Message == Request)
            Dispatch(message);
      if(Message == ResponseForARequest)
      {
            _responses.Add(Message.ID, Message);
            _responseHandlers[Message.ID](Message);
      }

}

これはうまくいくようです。

ただし、これは「使いやすい」ライブラリとして意図されていたため、上記の関数を開発したいと考えていました。Response = Connection.Send(Message)

基本的に、新しい応答が到着したときに、通知のために ManuelResetEvent を使用してこれを行うことができると考えました。

Dictionary <Guid, ManualResetEvents> _resetters;

Message Send(Message)
{
     ManualResetEvent mre = new ManuelResetEvent(false);
     _resetters.Add(Message.ID, mre);

     Connection.Send(Message);

     WaitFor(mre);

     return _responses[Message.ID];
}

MRE は、登録された ResponseHandlerDelegate から設定されます

ResponseArrived(Message)
{
     _responses.Add(Message.ID, Message);
     _resetters[Message.ID].Set();
}

これは、同時双方向通信がない限り機能します。サーバー側とクライアント側の両方が同じコードを使用しているため、どちらも MRE が設定されるのを待っています...

実際のクラスは長すぎるため、上記のすべてはある種の疑似コードであることに注意してください。特定のコード部分が必要な場合はお知らせください。

それで、私の質問は何ですか?

私が作ったものはめちゃくちゃだと思います。これを修正する簡単な方法はありますか?または、誰かがこれを別の方法で実装する方法を教えてください。

私は WCF を使用したくありません。下位レイヤーをより適切に制御するためです。主に、自分で開発したいからです :-)

ありがとう

4

1 に答える 1

1

同期送信で応答を待っている間のブロックまたはデッドロックを防ぐために、送信スレッド PER 要求が必要です。それ以外の場合、Send B は A の応答を待ち、A は B の応答を待つことができ、WaitFor は Send メソッドを呼び出したスレッドが実際に何も受信しないようにする同期ロックであるため、どちらも何もしません (デッドロック)。

マシン A と B がライブラリを実行しているステート マシンのように考えてください。

A --> send to B
B --> send to A
A --> wait for response
B --> wait for response
A --> receive message from B, but still waiting for B's response
B --> receive message from A, but still waiting for A's response

結果:

A --> has message from B but can't stop waiting to process it
B --> has message from A but can't stop waiting to process it

つまり、2 つ以上のスレッドが必要です。これらすべてのスレッドが 1 つの接続を共有している場合でも、 N スレッドが必要です。ここで、N は同時に実行するリクエストの数です。組み込みまたは自作のスレッド プールを使用すると、スレッドの再利用とガベージ コレクション コストの削減に役立ちます。

リクエストごとにスレッドをスピンアップしても問題ありません...実際、推奨されています。単一のスレッドが応答も待機している場合、単一のスレッドで複数の要求を適切に処理することは不可能です。ただし、応答を待っていなかった場合、これは別の話になります.

于 2013-06-28T18:23:49.807 に答える