カテゴリー「network」

TCPに引き続き、UDPを作ってみた。

https://github.com/shigenobu/OrangeCabinet

一応、nugetに公開済みです。

これも、JAVA版があるのですが。。一応紹介。

https://github.com/shigenobu/blueshelf

一応、mavenで公開済みです。

この、C#のUDPライブラリの特徴は、以下となります。

  • 例によって、ハーフクローズを検知用に、最終受信からN秒でタイムアウト(UDPはそんなもんないけど)を処理
  • クライアントでもbindする

一番目は、送信元が同じ限り、タイムアウトするまでは独自のオブジェクトで任意変数を格納できる。

(セッションみたいなイメージ)

二番目は、クライアントでも予めbindすることで、ポートを決め打ちできる。

connectだと、ポートが決め打ちできないので、あえてbindを使う形にしています。

なんでこんなもんをつくっているのかというと、

実は、TCP/UDPのサーバ機能を必要とするあるものを作りたいと考えているからです。

うまくできたら、nugetに公開しようかと考えています。

今回ちょっとハマったのは、BeginXXXとEndXXXは対になっているらしく、

BeginReceiveFrom

EndReceiveFrom

はセットで使う必要があるということでした。

ただ、BeginReceiveFromの部分でも、使わないremote endpointインスタンスを生成しないといけないのは、ちょっと微妙な気がした。

完了時に、remote endpointが取れればいいと思うのだが。。

また、システムコールとしては、epoll_createは使われていたが、UDPなんでepollである必要もないのかなとは思った。

JAVAだと、UDPに対するepollの実装はないので(正確にはJAVA7でお蔵入りしたようだが)。

概ね問題なさそうだが、一時オブジェクトの生成が少し多い気がしている。

IAsyncResultオブジェクトを毎回作っているような感じなので、そこは調整できればとは思う。

(ただ、毎回作らないと受信バッファの読み込みがうまくいかないので、簡単にはいかない気がしている。)

以上

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

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   [コメントがあればどうぞ]

なにをいっているのか不明なタイトルですが、UDPクライアントでは、受信をするためにbindまたはconnectのシステムコールが必要です、ということです。

TCPクライアントでは、主にconnectのシステムコールが使われることで、一時的に受信ポートが設定されます。そのため、受信が可能となっています。

UDPクライアントでは、bindまたはconnectのシステムコールが内部的に使われている実装と、そうでない実装があります。

javaのNIOのudpにおいては、bindまたはconnectのシステムコールが使われていません。そのため、受信をするためには、上記のシステムコールを使う必要があります。

私が以前作成した、

https://github.com/shigenobu/blueshelf

というUDPのNIOのwrapperでは、クライアントでもbindし、bindしたポート(ファイルディスクリプタ)を使って、送信を行い、そのまま受信してます。

クライアントでbindするメリットは、受信ポートを事前に決めることができる点です。これにより、1対多の通信の実装が行いやすくなります。

もちろん、connectでも1対多は可能ですが、受信ポートを外側から知る手段が必要となります。(外部のサーバを利用するなど)

もちろん、NAT環境下では、外部のサーバを利用しないとはいけませんが、ローカルネットワーク通信においては、受信ポートを予めわかっているというのはクラスタリングをするときに有用かなと考えています(UDPでクラスタリングって微妙ですが)

たぶんあっていると思うのですが、もし間違っていたらごめんさない。

以上

投稿日時:2021年02月24日 18:40   カテゴリー:network, server   [コメントがあればどうぞ]