Javaで以前作ったTCPサーバ・クライアントみたいな感じで、
C#の非同期・ノンブロッキングTCPサーバ・クライアントを作ってみた。
https://github.com/shigenobu/PurpleSofa
一応、nuget.orgには登録してあります。
ちなみにJavaのもの。
https://github.com/shigenobu/redchest
一応、mavenには登録済みです。
以前、C#のTCP実装では、
- BeginXXXのメソッドを使うパターン ※async/awaitではない
- SocketAsyncEventArgsクラスを使うパターン
があるようだと書いたのですが、
「SocketAsyncEventArgsクラスを使うパターン」では、どう頑張っても接続ごとにスレッドを割り当てて、
受信を待機する形にせざるを得ない感じでした。
「SocketAsyncEventArgsクラスを使うパターン」は、少ないクライアントで大量のやりとりをするケースに向いているのかな?
と感じています。
そのため、汎用的な側面から、今回は「BeginXXXのメソッドを使うパターン」のパターンで実装しました。
C#版もJava版と同様、
- openハンドラ(acceptもしくはconnect時に1回呼び出される)
- messageハンドラ(read時にN回呼び出される)
- closeハンドラ(close時に1回呼び出される)
という形となっています。
C#版もJava版同様、
- 最終受信からN秒(デフォルト60秒)経過で、タイムアウト切断します。
- 切断処理は、キューを経由して非同期で行われます。
- 接続(セッション)のオブジェクト内に、任意の値を入れられます。
という実装になっています。(Java版は上記に加えて、シャットダウンハンドラーの実装もあります。)
このライブラリの最大の特徴は、「最終受信からN秒経過でタイムアウト切断」というところでしょうか。
なんでこんなことしているかっていうと、keep aliveをしようがなにしようが、
この方法でしか結果的に”ハーフクローズ”を検知できないからです。(経験的に)
C#版を作るにあたって、ちょっと気になった点として、
連続的にメッセージを送信すると、まれに受信時に2つのメッセージを同時に取得してしまうケースがあるようです。
Javaのときはなかったのですが、どんなに排他制御をしても無理な感じでした。(受信時の問題っぽいので)
そのため、実際に利用するときは、プロトコロル(というかメッセージフォーマット)をよく決めて、
アプリケーションでメッセージを分割できるようにする必要があるのかと感じます。
また、デフォルトで、バッファサイズを2048byteとっていますが、
広域通信だと、MTU(通常1500byteくらい)より小さい値で分割受信するケースもあるので、
このあたりもアプリケーションで吸収する必要があるかと思います。
以上
コメントがあればどうぞ