c# - 检测当前连接是否同时支持 IPv4 和 IPv6

标签 c# windows-runtime connection ipv6 ipv4

我需要在 中检测WinRT 应用程序在哪些协议(protocol)上有互联网访问(IPv4/IPv6/两者)。我有以下代码来确定支持的协议(protocol):

enum IpVersion
{
    None = 0,
    IPv4 = 1,
    IPv6 = 2,
    IPv46 = 3
}

IpVersion GetIpVersion(ConnectionProfile profile)
{
    var result = IpVersion.None;

    if (profile != null && profile.NetworkAdapter != null)
    {
        var hostnames = NetworkInformation.GetHostNames().Where(h => h.IPInformation != null && 
                                                                h.IPInformation.NetworkAdapter != null &&
                                                                h.IPInformation.NetworkAdapter.NetworkAdapterId == profile.NetworkAdapter.NetworkAdapterId);
        foreach (var hostname in hostnames)
        {
            if (hostname.Type == HostNameType.Ipv4)
            {
                result |= IpVersion.IPv4;
            }
            else if (hostname.Type == HostNameType.Ipv6)
            {
                result |= IpVersion.IPv6;
            }
        }
    }

    return result;
}  

我这样使用它:
GetIpVersion(NetworkInformation.GetInternetConnectionProfile()); 

现在我想知道每个可用协议(protocol)是否都有互联网访问权限。当然我可以 ping 一些东西,但我想知道是否有一些 SDK 方法。这些信息可在 Wi-Fi status 中找到。 window :

WiFi-status

有一个方法,例如可以返回NetworkConnectivityLevel.InternetAccess ,但它不包含有关存在连接的协议(protocol)的信息。
bool internetAccess = connectionProfile.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess

最佳答案

在您的代码中,ConnectionProfile 是什么?类型?没有 a good, minimal, complete code example 就很难理解这个问题并准确解释该代码的作用以及为什么它与您想要的不同。

也就是说,如果我正确理解了这个问题,您正在尝试确定您的 Internet 连接是否同时支持 IPv4 和 IPv6。如果是这样,那么我看不出有任何方法可以从 API 级别做到这一点。本地 PC 实际上可以安装 IPv4 协议(protocol),而无需连接到允许传输该协议(protocol)上的流量的网络。即使 LAN 支持该协议(protocol),互联网连接本身也可能只支持 IPv6。

同样的事情也适用于其他方式(即具有本地 IPv6 支持,但仅支持 Internet 上的 IPv4)。

在我看来,唯一可靠的方法与许多其他情况所需的方法相同:尝试一下,看看它是否有效。 IE。尝试通过所需的协议(protocol)版本连接到 Internet 上的远程端点;如果失败,则不支持。如果成功,则支持。

编辑:

感谢您更新问题。它仍然不是最好的代码示例,但它稍微改进了这个问题。

我仍然不是 100% 你需要做的事情,也不是我是否有对你最有用的方法。但这是一个简短的程序,我认为它可以满足您的需求:

XAML:

<Page x:Class="TestSO32781692NetworkProtocolConnectivity.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:TestSO32781692NetworkProtocolConnectivity"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"
      mc:Ignorable="d">

  <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel.Resources>
      <Style TargetType="TextBlock">
        <Setter Property="FontSize" Value="24"/>
      </Style>
    </StackPanel.Resources>
    <StackPanel Orientation="Horizontal" Margin="10, 50, 10, 0">
      <TextBlock Text="IpV4: "/>
      <TextBlock Text="{Binding IpV4}"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal" Margin="10, 10, 10, 0">
      <TextBlock Text="IpV6: "/>
      <TextBlock Text="{Binding IpV6}"/>
    </StackPanel>
    <Button Content="Check Network" Click="Button_Click"/>
    <ListBox ItemsSource="{Binding Profiles}"/>
  </StackPanel>
</Page>

C#:
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.Networking;
using Windows.Networking.Connectivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace TestSO32781692NetworkProtocolConnectivity
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public static readonly DependencyProperty IpV4Property = DependencyProperty.Register(
            "IpV4", typeof(bool), typeof(MainPage), new PropertyMetadata(false));
        public static readonly DependencyProperty IpV6Property = DependencyProperty.Register(
            "IpV6", typeof(bool), typeof(MainPage), new PropertyMetadata(false));
        public static readonly DependencyProperty ProfilesProperty = DependencyProperty.Register(
            "Profiles", typeof(ObservableCollection<string>), typeof(MainPage), new PropertyMetadata(new ObservableCollection<string>()));

        public bool IpV4
        {
            get { return (bool)GetValue(IpV4Property); }
            set { SetValue(IpV4Property, value); }
        }

        public bool IpV6
        {
            get { return (bool)GetValue(IpV6Property); }
            set { SetValue(IpV6Property, value); }
        }

        public ObservableCollection<string> Profiles
        {
            get { return (ObservableCollection<string>)GetValue(ProfilesProperty); }
            set { SetValue(ProfilesProperty, value); }
        }

        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            bool ipV4 = false, ipV6 = false;
            ConnectionProfile internetProfile = NetworkInformation.GetInternetConnectionProfile();

            Profiles.Clear();
            Profiles.Add("Internet profile: " + internetProfile.ProfileName);

            var hostNames = NetworkInformation.GetHostNames()
                .Where(h => h.IPInformation != null &&
                       h.IPInformation.NetworkAdapter != null);

            foreach (HostName hostName in hostNames)
            {
                ConnectionProfile hostConnectedProfile =
                    await hostName.IPInformation.NetworkAdapter.GetConnectedProfileAsync();

                if (hostConnectedProfile.NetworkAdapter.NetworkAdapterId == internetProfile.NetworkAdapter.NetworkAdapterId)
                {
                    Profiles.Add("Host adapter: " + hostName.DisplayName);
                    if (hostName.Type == HostNameType.Ipv4)
                    {
                        ipV4 = true;
                    }
                    else if (hostName.Type == HostNameType.Ipv6)
                    {
                        ipV6 = true;
                    }
                }
            }

            IpV4 = ipV4;
            IpV6 = ipV6;
        }
    }
}

请注意,此代码示例不使用 NetworkInformation.GetConnectionProfiles() 方法。尽管这似乎是扩展您当前方法的有希望的方法,尽管 the documentation实际上 promise “调用 GetConnectionProfiles 方法会检索设备上当前建立的所有连接的配置文件, 包括 Internet 连接。”[强调我的],事实证明并非如此。特别是,至少在我安装并启用了 Hyper-V 的机器上(对于那些进行 WinRT/Windows Phone 开发的人来说这是一个常见的场景:)),ConnectionProfile NetworkInformation.GetInternetConnectionProfile() 返回的对象实际上不包含在 NetworkInformation.GetConnectionProfiles() 返回的配置文件集合中.

因此,上面的代码示例所做的只是简单地识别任何与 ConnectionProfile 对应的主机名对象。由 GetInternetConnectionProfile() 返回.

不幸的是,我所在的地方实际上并没有 IPv6 支持,所以我无法对此进行全面测试。我能够在支持 IPv6 到 Internet 的不同网络上测试上述内容,现在我可以确认,至少在我的测试中,它按预期工作。该代码正确检测 IPv4 和 IPv6 协议(protocol)上的 Internet 连接。我希望以上内容可以满足您的需求。

顺便说一句,除了(如您所述)使用 GetNetworkConnectivityLevel() 的明显问题外没有提供实际使用的协议(protocol),我发现该方法甚至没有返回至少直观地被认为是正确的信息。

特别是调用FindConnectionProfilesAsync(new ConnectionProfileFilter { IsConnected = true })确实返回与我用来连接到 Internet 的连接(例如无线网络)相对应的配置文件,但是当我调用 GetNetworkConnectivityLevel() 时在该配置文件上,它返回 LocalAccess只要。我猜这与我上面提到的安装 Hyper-V 的问题有关。

这可以通过比较 ConnectionProfile 来解决。由 GetConnectedProfileAsync() 返回NetworkAdapter 的方法FindConnectionProfilesAsync() 返回的每个连接配置文件的到 GetInternetConnectionProfile() 返回的配置文件.对顶级配置文件的网络适配器的配置文件进行间接处理似乎会产生预期的 Internet 连接配置文件。

当然,解决这个问题并不能解决所使用协议(protocol)的问题。我仅在其他人更多地针对配置文件管理方面而不是协议(protocol)连接问题查看此答案时才提及它。

关于c# - 检测当前连接是否同时支持 IPv4 和 IPv6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32781692/

相关文章:

c# - 创建表单(没有表单设计器)

c# - 发生异常时显示窗体 C#

c# - 如何获取 C# 中当前运行时的信息?

检测到 C# 无法访问的代码

c# - 为什么我从 ImportPfx DatAsync 获得 UnauthorizedAccessException?

xaml - winrt 文本 block 运行绑定(bind)设计时

c# - 在 ListView 中对项目进行分组 - Windows 应用商店应用

database - 更改 Laravel 数据库连接

java - C3P0 ComboPooledDataSource getConnection() 是否始终返回有效的连接?

c++ - 基本的 linux C++ 网络 : connection refused, 但是没有出现错误