カテゴリー「c#」

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くらい)より小さい値で分割受信するケースもあるので、

このあたりもアプリケーションで吸収する必要があるかと思います。

以上

投稿日時:2021年12月07日 22:52   カテゴリー:c#, java, network   [コメントがあればどうぞ]

C#で、非同期ソケット(TCP)を扱う場合、

  • BeginXXXのメソッドを使うパターン
  • SocketAsyncEventArgsクラスを使うパターン

の2つがあるようです。

使われているシステムコールに差異があるのかと思い、linux上の.NET5で試してみたところ、

straceのログには、両方ともepollのシステムコールが使われていました。

というわけで、両方とも、linux上で使う場合は、IO性能の差はほぼなさそうです。

では、何が違うのかというと、

BeginXXXのメソッドのコールバックでは、

IAsyncResultオブジェクトのアロケーションが、ソケット操作のたびに行われるのに対し、

SocketAsyncEventArgsは、接続ごとにアロケーションをする(つまり1クライアント1オブジェクト)形にすることで、

処理軽減を図っているのではないかと思われます。

(SocketAsyncEventArgsの公式ドキュメント)

https://docs.microsoft.com/ja-jp/dotnet/api/system.net.sockets.socketasynceventargs?redirectedfrom=MSDN&view=net-6.0

IAsyncResultオブジェクトで、接続先クライアントの情報もあれもこれも含めて渡す方法は悪くないが、

accept/readのインターフェースを統一しようとしていたのか、やはり無駄なように思える。

とはいえ、SocketAsyncEventArgsも初見では理解が難しい気もする。

なので、このあたりをラップしたライブラリを作っておいたほうがいい気がしている。

以上

投稿日時:2021年11月25日 14:29   カテゴリー:c#   [コメントがあればどうぞ]