カテゴリー「c#」

C#で、IPアドレスを取得する際、Dns.GetHostEntryを使うという記事がよく出てきます。

当然、DNSサーバを利用する前提なので、DNSサーバから正引きできないと、

結局は、ローカルループバックアドレスしか取れなかったりします。

ローカルネットワークであっても、

consulやdnsmasqなどをつかって、DNS設定くらいちゃんとしとけよというのはもちろんですが、

IPアドレスだけで済むなら、そうしたいのものかと思います。(WINSサーバについては不明です)

このように、正引きできないが、ローカルアドレスを取りたい場合、

NICを直接見に行くほうが楽です。

自分のTCPサーバ・クライアントライブラリに、将来的に使いそうな気がして、実装しておきました。

https://github.com/shigenobu/PurpleSofa/blob/master/PurpleSofa/PsNetwork.cs

v4のアドレス取得部分だけ抜粋します。

    private static readonly IEnumerable<NetworkInterface> NetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces()
        .Where(i =>
            i.OperationalStatus == OperationalStatus.Up &&
            i.NetworkInterfaceType == NetworkInterfaceType.Ethernet &&
            i.NetworkInterfaceType != NetworkInterfaceType.Loopback);

    public static IEnumerable<IPAddress> GetLocalIpv4Addresses()
    {
        List<IPAddress> addresses = new();
        foreach (var networkInterface in NetworkInterfaces)
        {
            var address = networkInterface.GetIPProperties().UnicastAddresses
                .Where(a => a.Address.AddressFamily == AddressFamily.InterNetwork)
                .Select(a => a.Address)
                .FirstOrDefault();
            if (address != null)
                addresses.Add(address);
        }

        return addresses;
    }

要は、起動中のイーサネットのNICだけを取得して、それをIEnumerableで返している感じです。

これでWIFIも取れるかと思います。(LINUXでは大丈夫だったが)

NICを複数持っているケース、

たとえばゲートウェイサーバのように、外向きと内向きのアドレスを持つ場合などについては、

https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.aspnetcore.httpoverrides.ipnetwork?view=aspnetcore-7.0

なんていうクラス(ASPですが)を使うことで、

取得したアドレスが、指定のアドレス範囲内かどうかを判断して、取捨選択も出来るかと思います。

以上

投稿日時:2023年01月12日 23:27   カテゴリー:c#   [コメントがあればどうぞ]

私が作成しているPurpleSofaの0.0.9で、IPv6対応をしました。

https://www.nuget.org/packages/PurpleSofa/

v6のサーバというのは、初めて作ったのですが、

フォーマットや省略ルールなど、以下のIBMのサイトがよくまとめられていたので、記載します。

https://www.ibm.com/docs/ja/i/7.1?topic=6-ipv6-concepts

C#の実装におけるポイントですが、

  • v4の「0.0.0.0」(anywhere)は、v6では「::」に相当
  • ソケットオプションで、v6でlistenする場合は、v6onlyをfalseにしておくとv4のソケットをv6として扱ってくれる

ぐらいでした。

(v6でlistenしても、v4を扱う設定)

_socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);

クラウドなんかでは、フロントとなるCDNとかロードバランサが、v6→v4変換とかもしれくれるので、

あんまりv6を直接扱う需要性は低いような気はしますが、

海外では、v6アドレスしか提供しないプロバイダなんかもあるようで、

ある程度v6の対応というか準備もしておいたほうがいいのかなと思うこの頃です。

以上

投稿日時:2023年01月12日 22:59   カテゴリー:c#   [コメントがあればどうぞ]

mysqlやmariadbからData Ware House(以下、DWH)へレプリケーションしたいな、って最近思います。

実際のところ、DWHがupdate/deleteといった行操作に弱いので、

なかなかDWHが使えない状況が続いていますが、

最近ではTiDBのTiFlushや、OCIのheatwaveといったもの(行操作も強そうなもの)が出てきているので、

OLTPのmysql/mariadbから、シームレスにレプリケーションいけそうじゃないか?

という感触を持っています。

とはいえ、update/delete問題が解決しても、実際はOLTPのデータベースと、

DWHをつなぐときは、マルチソースレプリケーションである必要があったり、

そもそも各種DDLを解決したりと、なかなか簡単には事が運ばない印象です。

そんなこんなで、Change Data Capture(以下、CDC)が使えるんじゃないかな?

とずっと思っていたのですが、C#にCDCのライブラリがあったので、紹介しておきます。

https://github.com/rusuly/MySqlCdc

まだ、動作検証はしてないですが、かなり色々できそうな気がしてます。

CDCのソフトウェアは有償・無償と色々ありますが、

実際にSQL(イベント)をアプリケーションで捕まえることができるようになるので、

ある程度mysqlのレプリケーションをしっているエンジニアであれば、

かなり面白いことができそうな気はしてます。

以上

投稿日時:2022年11月29日 17:22   カテゴリー:c#, mariadb, mysql   [コメントがあればどうぞ]

ArmadaSuitさんが、fluentd / fluent-bit にfowardするC#クライアントを作成してくれました。

(Pigeon)

https://www.nuget.org/packages/Pigeon/

シンプルなライブラリではありますが、fluentdの4modeをサポートしています。

そのため、受け手側に合わせて柔軟な変更が対応が可能というものです。

基本的には、MessageModeで十分ですが、FluentNettingのようなリモートのサーバと直通信する場合は、

CompressedPackedForward Modeを使うことで、サイズを圧縮できるなどのメリットがあるかと思います。

ぜひ、FluentNettingと合わせておつかいください。

(FluentNetting)

https://www.nuget.org/packages/FluentNetting/

以上

投稿日時:2022年01月27日 19:12   カテゴリー:c#, fluentd   [コメントがあればどうぞ]

表題のとおり、fluentd / fluent-bitのoutput forwardを受信するC#のサーバライブラリを、

nugetにリリースしました。

(FluentNetting)

https://www.nuget.org/packages/FluentNetting/

これは、javaで作られているinfluentというライブラリをC#に移植したような感じのものです。

(influent)

https://github.com/okumin/influent

※私が作ったのではありません。すばらしいライブラリです。

で、FluentNettingでは、fluentdのv1プロトコルがサポートする4つのmodeに対応しつつ、

hostname / shared_key による認証までを対応しました。

さらにいうと、fluent-bitもテスト済みでございます。

このFluentNettingを使うといいことは、「遅延処理が自由自在」ということです。

アプリケーション → fluend / fluent-bit → FluentNettingを使った受信サーバ

のようにして、fluentd / fluent-bit でバッファリングしておけば特に良いのかなと思います。

メッセージキューイング系を使うのと同じじゃね?と思うかもしれませんが、

fluend / fluent-bit はアプリケーションと同一ホスト(k8sならサイドカー)にする形が多いので、

アプリケーションからの書き込みタイムが少なくできる利点があります。

プラグイン使えば良くない?と思うかもしれませんが、

プラグインはメンテナンスされていないものもあり、

場合によってはアプリケーションエンジニアが柔軟に変更するのが難しいケースがあります。

という事情を踏まえると、

fluentd / fluent-bit は forwardさえやればよく(設定が簡単)、

プラグインに悩まされずにデータを処理できる、

という利点があるのかと感じています。


各言語の対応ライブラリですが、基本的には公式が出しているものを使えば利用できます。

(fluentdのライブラリ)

https://docs.fluentd.org/language-bindings

ただし、確認した限りでは、PHPのライブラリはパーサがデフォルトJSONになっているので、

msgpackに変更する必要があります。

C#については、

(FluentdClient.Sharp)

https://www.nuget.org/packages/FluentdClient.Sharp/

というものがあるのですが、EventTimeがdouble型になっているようで、

fluent-bitではエラーとなってしまうようです。(fluentdでは大丈夫のようです)

各言語とFluentNettingの対応状況は後々確認していこうとおもいます。


最後になりましたが、今回ArmadaSuitさんにパーサ部分に尽力いただきました。

彼のおかげで、今回リリースまでこぎつけられました。感謝です。

その彼が、C#のクライアントライブラリを作成してくれているので、

近々nugetにアップされるのではないかと期待しています。

以上

投稿日時:2022年01月19日 17:57   カテゴリー:c#, fluentd   [コメントがあればどうぞ]

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

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