sh1’s diary

プログラミング、読んだ本、資格試験、ゲームとか私を記録するところ

C# インターネットに接続しているかどうかを調べる方法

f:id:shikaku_sh:20210823173353p:plain:h300

ローカルアプリケーションを作るときに、ネットワーク接続の有無をチェックすることがあります。どういうコードを書くでしょうか。

Windows 10 から Windows 11 への更新要件のひとつに「ネットワーク接続の有無」がありました。Windows 11 の更新チェックツールとして、有名どころ「ReadySunValley」がどんなコードを書いているのかチェックしてみました。

ReadySunValley 0.61.0 のコード

ReadySunValley のコードはこれ:

public bool IsInet()
{
    try
    {
        using (var CheckInternet = new WebClient())
        using (CheckInternet.OpenRead("http://clients3.google.com/generate_204"))
        {
            return true;
        }
    }
    catch
    {
        return false;
    }
}

ReadySunValley 0.52.1 以前のコード

[System.Runtime.InteropServices.DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);

public static bool isINet()
{
    return InternetGetConnectedState(out _, 0);
}

補足

コード修正されているもののリリースログを見る限りはバグなどの Issue が挙がってきて、ネットワーク接続の確認方法が修正されたというわけではなさそうです。

ただし「Improved Inet connectivity check」と書いてあるので、改善されたコードということになると思います。

新しいコードでは、WebClient を利用して以下の URL を開いています。この URL が開けたらネットワーク接続は可能ということみたいですが、これはどういった URL なのか:

https でも 204 のステータスコードを確認できます。

調べてみたところだと、「The Chromium Projects - Network Portal Detection」が回答になりそうです。

空のページを HTTP Status 204 で返却することで知られている URL のようです。実際に wget で調べてみると、このとおり。

f:id:shikaku_sh:20210823173306p:plain:w600

この修正は Android のネットワーク接続チェックと似たようなコードに修正したかったのだと思います。Android の場合は以下の URL で同じようなコードを確認しています:

f:id:shikaku_sh:20210823173329p:plain:w600

Android Code Search で「generate_204」を検索すると実際のコードを確認できます。

ちなみに https でも 204 を返しました。

こんなテストコードもありました:

@Test
public void testGetCaptivePortalServerUrl() throws Exception {
    String url = mCm.getCaptivePortalServerUrl();
    assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
}

というわけで、ネットワーク接続の有無のチェックで google 系は URL を叩いてステータスコードを確認してそうです。なので、それに倣ったネットワーク接続の有無のチェックに更新された、と考えることができそうです。

おまけ

(その昔よく利用した)dobon.net では NetworkInterface.GetIsNetworkAvailable メソッドが紹介されています。

Refernece source でコードを確認してみると:

NetworkInterface クラスを取得して、どれかひとつでも if 条件をパスする状態だとネットワーク接続できる、というような感じです。

条件としては:

  1. ネットワークインターフェースが稼働していて (OperationalStatus.Up)
  2. ネットワークインターフェースの種類がトンネル接続でもループバック (!NetworkInterfaceType.Tunnel & Loopback) でもない

また、実際の接続を試してみる、というコードも記載されていますが、yahoo に接続してステータスを確認するような内容になっていて、最適化されたコードではなさそうです。

参考