如何设置 Windows Phone 套接字的连接要求

2012/2/9

在某些应用程序中,将套接字通信限制为特定网络接口类型非常重要。Windows Phone OS 7.1 可以通过使用 SetNetworkRequirement 套接字扩展方法使应用程序来指定用于网络通信的网络接口类型。这可能是手机网络非手机网络,分别指使用手机网络技术的网络接口或不使用手机网络技术的网络接口。非手机网络技术的示例为 WLAN 和以太网。先设置网络要求,然后进行 ConnectAsync 调用。满足应用程序的网络接口要求时,才会将其用于网络通信。如果未满足网络接口要求,则 ConnectAsync 回调方法中将会接收到 SocketError.NetworkDown 错误,并且将不会连接套接字。本主题演示如何在套接字上设置网络接口要求,然后如果连接了该套接字,则会验证当前接口。

Microsoft.Phone.Net.NetworkInformation 命名空间向套接字类提供扩展方法。您可以使用 SetNetworkPreference(Socket, NetworkSelectionCharacteristics) 方法在套接字上设置网络接口的首选项。

注意注意:

有关扩展方法的更多信息,请参阅如何调用扩展方法 (Visual Basic)扩展方法(C# 编程指南)

在下面的步骤中,您可以仅出于测试目的将代码置于一个按键的点按事件中。在下面的步骤中,假设您拥有一款 Windows Phone 应用程序,且该应用程序的一个页面包含名为 button1 的按钮。

为套接字设置连接要求

  1. 在页面代码隐藏文件的顶部,添加以下 using 指令。

    
    using System.Net.Sockets;
    using Microsoft.Phone.Net.NetworkInformation;
    using System.Text;
    
    
  2. 将以下变量声明添加到代码隐藏文件中类的顶部。此操作能定义要求的网络接口,在此示例中其为 Cellular。如果无法使用此类型的网络接口建立连接,则套接字连接将会失败。

    
    NetworkSelectionCharacteristics _requiredNetwork = NetworkSelectionCharacteristics.Cellular;
    
    
  3. 将以下代码添加到您的按键点击事件中。这会创建一个套接字,并调用套接字上的 SetNetworkRequirement 扩展方法, 用于该套接字的要求网络接口设置为以前定义的 _requiredNetwork 变量值。然后启动连接。

    
    private void button1_Click(object sender, RoutedEventArgs e)
    {
       Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
       // Set the preferred network interface to be an interface that uses cellular technology. 
        socket.SetNetworkRequirement(_requiredNetwork);
    
       // To run this application, you should specify the name of a server on your network that is running
       // the required service. Replace the following "Placeholder" text with the name of the server.
       string serverName = "Placeholder";
    
       // This identifies the port over which to communicate. In this sample, we need to just
       // supply the Echo port number, but you are free to select your own.
       int portNumber = 7;
    
       // Create DnsEndPoint. 
       DnsEndPoint hostEntry = new DnsEndPoint(serverName, portNumber);
    
       // Create a SocketAsyncEventArgs object to be used in the connection request.
       SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
       socketEventArg.RemoteEndPoint = hostEntry;
       socketEventArg.UserToken = socket;
       socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(Connect_Completed);
    
       // Make an asynchronous Connect request over the socket.
       socket.ConnectAsync(socketEventArg);
     }
    
    
    重要说明重要说明:

    为了使此示例能够正常运行,必须在以下代码中将 serverNameportNumber 更改为引用可通过此 TCP 套接字与其进行通信的服务及其端口。如果未执行此操作,连接请求会收到超时。

    提示提示:

    您可以使用代表 IP 地址的字符串,而不使用下面的代码中 DnsEndPoint 构造函数中的服务器或主机名。您还可以使用 IPEndpoint,而不使用 SocketAsyncEventArgs 的 RemoteEndPoint 属性的 DnsEndPoint。

    在前面的方法中,我们将“已完成”的事件处理程序分配了 Connect_Completed。这是在异步套接字连接请求完成或超时时调用的回调。

  4. 在同一个代码隐藏页中,添加以下方法。

    
    void Connect_Completed(object sender, SocketAsyncEventArgs e)
    {
       switch (e.SocketError)
       {
          case SocketError.NetworkDown:
             DisplayMessage(String.Format("Could not connect over the required network interface '{0}'", _requiredNetwork.ToString()),"Error",MessageBoxButton.OK);
          break;
          case SocketError.Success:
             ShowNetworkInterfaceInformation(e);
             break;
         default:
            DisplayMessage(String.Format("Socket Connection Failed with the error: '{0}'", e.SocketError.ToString()),"Error",MessageBoxButton.OK);
            break;
       }
     }
    
    
    

    在前面的方法中,通过查看 SocketAsyncEventArgs 上的 SocketError 属性来确定连接请求是否成功。如果连接成功,将会调用 ShowNetworkInterfaceInformation 方法,此方法将会在下一个步骤中介绍。DisplayMessage 方法也将在以下各步骤中介绍。

    如果未满足网络要求,则回调中将会接收到 SocketError.NetworkDown 错误,并且将不会连接套接字。例如,如果我们在模拟器上运行此代码,并且将我们的要求设置为 Cellular,则可能发生此种情况。

  5. 添加以下方法。它会通过调用连接套接字上的 GetCurrentNetworkInterface 来检索 NetworkInterfaceInfo。StringBuilder 用于构造包含网络接口信息的信息文本。此文本在用户的 MessageBox 中显示。

    
    /// <summary>
    /// Display the network information using the GetCurrentNetworkInterface extension method on the socket.
    /// </summary>
    void ShowNetworkInterfaceInformation(SocketAsyncEventArgs e)
    {
       // When ConnectAsync was called, it was passed the socket object in
       // the UserToken field of the socketEventArg. This context is retrieved once
       // the ConnectAsync has completed.
       Socket socket = e.UserToken as Socket;
    
       // Call GetCurrentNetworkInterface only if the connection was successful.
       if (e.SocketError == SocketError.Success)
          {
             NetworkInterfaceInfo netInterfaceInfo = socket.GetCurrentNetworkInterface();
    
             // Use a StringBuilder to efficiently create text about this NetworkInterfaceInfo.
             StringBuilder sb = new StringBuilder();
    
             // For clarity, append a timestamp so that we can see when this information was gathered.
             sb.AppendLine("Last Updated: " + DateTime.Now.ToString());
    
             sb.Append("Interface Name: ");
             sb.AppendLine(netInterfaceInfo.InterfaceName);
    
             sb.Append("Interface State: ");
             sb.AppendLine(netInterfaceInfo.InterfaceState.ToString());
    
             sb.Append("Interface Type: ");
             sb.AppendLine(netInterfaceInfo.InterfaceType.ToString());
    
             sb.Append("Interface SubType: ");
             sb.AppendLine(netInterfaceInfo.InterfaceSubtype.ToString());
    
             DisplayMessage(sb.ToString(), "Network Interface Information", MessageBoxButton.OK);
          }
          else
          {
             DisplayMessage(e.SocketError.ToString(), "Error Getting Interface Information", MessageBoxButton.OK);
          }
    
       // Close our socket since we no longer need it. 
       socket.Close();
        
    }
    
    
  6. 在同一个代码隐藏页中,添加以下方法。

    
    /// <summary>
    /// This helper method ensures that MessageBox.Show() is called on the UI thread.
    /// </summary>
    void DisplayMessage(string text, string caption, MessageBoxButton buttonConfiguration)
    {
       Dispatcher.BeginInvoke(() =>
       {
          MessageBox.Show(text, caption, buttonConfiguration);
       });
    }
    
    
  7. 若要构建解决方案,请单击“构建”菜单上的“构建解决方案”。(Ctrl+Shift+B)。若要运行应用程序,请单击“启动调试”。(“调试”菜单上的 F5)。如果可以通过使用在 SetNetworkRequirement 方法中指定的网络接口类型建立套接字通信,则会显示以下消息框。

    “如何获取连接信息”的屏幕截图

    如果无法通过调用在 SetNetworkRequirement 中指定的网络接口类型建立套接字通信,则会显示一个消息框通知该事实。

    注意注意:

    在前面的图像中,“Interface SubType”的值为“未知”。但是,当手机连接到手机网络时,此字段不是通过 WLAN 叠接或连接,而是显示手机网络类型(例如 2G 和 3G)。

显示: