导出 (0) 打印
全部展开
信息
您所需的主题如下所示。但此主题未包含在此库中。

如何创建和使用 Windows Phone 8 的 TCP 套接字客户端应用

2014/6/18

适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

 

本主题介绍为 Windows Phone 创建简单 TCP 套接字客户端应用所需的步骤。典型方案是客户端应用通过 TCP 套接字连接与服务器进行通信。为了简便起见,同时也为了保持此主题的独立性,我们将使用计算机上的内置简单 TCP/IP 服务来作为本通信的服务器端。若要创建使用 UDP 套接字的类似客户端应用,请参见如何创建和使用 Windows Phone 8 的 UDP 套接字客户端应用

重要说明重要说明:

本主题要求使用 TCP 套接字服务器进行客户端通信。在本示例中,将 Windows 的简单 TCP/IP 服务功能用作为服务器组件。下列过程提供了在您的计算机上启用简单 TCP/IP 服务功能的说明。您可能更喜欢使用自己的套接字服务器实现。

本主题包括以下部分。

 

在本节中,创建用于演示 TCP 套接字客户端功能的 UI。

创建 TCP 套接字客户端 UI

  1. 在 Visual Studio 中,通过选择“文件” | “新建项目”菜单命令创建新的项目。

  2. 将显示“新建项目”窗口。展开“Visual C#”模板,然后选择“Windows Phone”模板。

  3. 选择 Windows Phone 应用  模板。用您选择的名称填写“名称”

  4. 单击“确定”。将显示 Windows Phone 平台选择对话框。选择面向的版本或接受默认版本。

  5. 单击“确定”。将创建一个新的项目,并且“MainPage.xaml”将在 Visual Studio 设计器窗口中打开。

  6. “MainPage.xaml”中,删除名为“TitlePanel”的 StackPanel 的 XAML 代码,然后使用以下代码进行替换:

    
    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="TCP Socket Application" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="Client" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
    
    
    

    XAML 代码向应用添加了两个 TextBlock 元素,一个用于名为“ApplicationTitle”的应用标题,另一个用于名为“PageTitle”的页面标题。

  7. “MainPage.xaml”中,删除名为“ContentPanel”的 Grid 的 XAML 代码,然后使用以下代码进行替换:

    
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,-8,12,8">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>    <!-- Fit to content -->
            <ColumnDefinition Width="Auto"/>    <!-- Fit to content -->
            <ColumnDefinition Width="Auto"/>    <!-- Fit to content -->
            <ColumnDefinition Width="*"/>       <!-- Take up remaining space -->
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>      <!-- Fit to content -->
            <RowDefinition Height="Auto"/>      <!-- Fit to content -->
            <RowDefinition Height="Auto"/>      <!-- Fit to content -->
            <RowDefinition Height="*"/>         <!-- Take up remaining space -->
        </Grid.RowDefinitions>
        
        <!-- Grid Row 0: Remote Host Input Field >-->
        <TextBlock Grid.Row="0" Grid.Column="0" Text="Host Name:"  
                   VerticalAlignment="Center" HorizontalAlignment="Center" 
                   FontSize="{StaticResource PhoneFontSizeNormal}" />
        <TextBox x:Name="txtRemoteHost" Grid.Row="0" Grid.Column="1"  Height="70" Width="200" 
         VerticalAlignment="Top" HorizontalAlignment="Left" 
         FontSize="{StaticResource PhoneFontSizeNormal}"  />
              
        <!-- Grid Row 1: Echo >-->
        <!-- TextBlock for Echo command label-->
        <TextBlock Grid.Row="1" Grid.Column="0" Text="Text To Echo:" 
                   VerticalAlignment="Center" HorizontalAlignment="Center" 
                   FontSize="{StaticResource PhoneFontSizeNormal}" />
              
        <!-- TextBox for Echo command text input-->
        <TextBox x:Name="txtInput" Grid.Row="1" Grid.Column="1" Height="70" Width="200"  
                 VerticalAlignment="Top" HorizontalAlignment="Left" 
                 FontSize="{StaticResource PhoneFontSizeNormal}" />
               
        <!-- Button to the right of the input textbox for the Echo command >-->
        <Button x:Name="btnEcho" Grid.Row="1" Grid.Column="2" Height="70"  Width="120" 
                Content="Echo" 
                FontSize="{StaticResource PhoneFontSizeNormal}" Click="btnEcho_Click"/>
                
        <!-- Grid Row 2: Quote of the Day-->
        <!-- Button for the Quote command >-->
        <Button x:Name="btnGetQuote" Grid.Row="2" Grid.ColumnSpan="4" Height="70" 
                Content="Get Quote of the Day" 
                FontSize="{StaticResource PhoneFontSizeNormal}" Click="btnGetQuote_Click"/>
    
        <!-- Grid Row 3: Output-->
        <!-- Output TextBox named 'txtOutput' >-->
        <TextBox x:Name="txtOutput" Grid.Row="3" Grid.ColumnSpan="4" Background="Black" BorderBrush="Green" 
                 AcceptsReturn="False" Foreground="LightGray" FontFamily="Courier New"  
                 IsHitTestVisible="False" FontSize="{StaticResource PhoneFontSizeSmall}" TextWrapping="Wrap" />
    </Grid>
    
    

    XAML 代码创建 Grid 元素,用来包含所有其他元素。首先,定义 Grid 拥有三行和三列。接着,XAML 定义了 TextBox(用于远程主机名称数据输入)和 TextBlock(作为该字段的标签)。下一行 Grid 包含另一个 TextBox(用于来自用户的更多数据输入)和两个分配了 Click 事件处理程序的 Button 元素。最后,XAML 定义了另外一个 TextBox,用来显示应用中的输出。在以下几节中将实现 btnEcho_ClickbtnGetQuote_Click 方法。设计器中的布局应与下图类似。

    Socket Sample Screenshot

在本节中,将使用 System.Net.Sockets API 创建套接字并连接到服务器。为了清楚起见,对 System.Net.Sockets API 的调用被封装在 SocketClient 类中。

连接到 TCP 套接字服务器的步骤

  1. 创建一个新类,方法是在“解决方案资源管理器”窗口中选择项目,右键单击该项目,然后从上下文菜单中选择“添加 | 类…”…。此操作将打开“添加新项”对话框,并且对话框中的类模板处于选中状态。将“名称”字段中的类名称更改为“SocketClient”,然后单击“添加”。将在项目中创建一个名为“SocketClient”的新类。

  2. 打开 SocketClient.cs 并在页面顶部添加以下 using 指令:

    
    using System.Net.Sockets;
    using System.Threading;
    using System.Text;
    
    
  3. SocketClient 类的顶部定义以下变量:

    
    // Cached Socket object that will be used by each call for the lifetime of this class
            Socket _socket = null;
    
            // Signaling object used to notify when an asynchronous operation is completed
            static ManualResetEvent _clientDone = new ManualResetEvent(false);
    
            // Define a timeout in milliseconds for each asynchronous call. If a response is not received within this 
            // timeout period, the call is aborted.
            const int TIMEOUT_MILLISECONDS = 5000;
    
            // The maximum size of the data buffer to use with the asynchronous socket methods
            const int MAX_BUFFER_SIZE = 2048;
    
    

    使用 _socket 变量存储创建好的 Socket 对象。_clientDone 变量是 ManualResetEvent,用于协调通过 System.Net.Sockets API 调用的异步调用。

  4. SocketClient.cs 中,添加以下方法,该方法将创建 TCP 套接字,并向服务器发送异步连接请求。此操作的响应将由内联回调进行处理。

    
            /// <summary>
            /// Attempt a TCP socket connection to the given host over the given port
            /// </summary>
            /// <param name="hostName">The name of the host</param>
            /// <param name="portNumber">The port number to connect</param>
            /// <returns>A string representing the result of this connection attempt</returns>
            public string Connect(string hostName, int portNumber)
            {
                string result = string.Empty;
    
                // Create DnsEndPoint. The hostName and port are passed in to this method.
                DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber);
    
                // Create a stream-based, TCP socket using the InterNetwork Address Family. 
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                
                // Create a SocketAsyncEventArgs object to be used in the connection request
                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
                socketEventArg.RemoteEndPoint = hostEntry;
    
                // Inline event handler for the Completed event.
                // Note: This event handler was implemented inline in order to make this method self-contained.
                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
                {
                    // Retrieve the result of this request
                    result = e.SocketError.ToString();
    
                    // Signal that the request is complete, unblocking the UI thread
                    _clientDone.Set();
                });
    
                // Sets the state of the event to nonsignaled, causing threads to block
                _clientDone.Reset();
    
                // Make an asynchronous Connect request over the socket
                _socket.ConnectAsync(socketEventArg);
    
                // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
                // If no response comes back within this time then proceed
                _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
    
                return result;
            }
    
    
    

    此方法介绍了以下概念:

    • 创建终结点:DnsEndPoint 类包含应用连接到主机上的服务所需的主机名或 IP 地址和远程端口信息。

    • 创建套接字:通过将 AddressFamily 参数设置为 AddressFamily.InterNetwork、将 SocketType 参数设置为 SocketType.Stream,以及将 ProtocolType 参数设置为 ProtocolType.Tcp 来实例化 Socket 对象。AddressFamily 参数指定 Socket 用来解析地址的寻址方案。例如,AddressFamily.InterNetwork 指示当 Socket 连接到结束点时,需要一个 IP 版本 4 地址。请注意,尚未建立套接字连接。我们只是将我们的套接字设置为使用 TCP 协议的基于流的套接字。服务器的实际连接尝试发生在 ConnectAsync 调用中。

      重要说明重要说明:

      在 Windows Phone OS 7.1 中的 Socket 构造函数中,AddressFamily 参数的唯一有效值是 InterNetwork。选择 AddressFamily 枚举的任何其他成员都将会导致错误。

    • 创建上下文对象:该对象是对其调用异步方法的任何上下文对象(在本例中为 ConnectAsync)。将会在该对象上设置数据缓冲区、回调方法和各种其他特定于上下文的数据,然后将这些数据传递到异步调用。在调用完成后,可以检查该对象的完成状态和操作结果。

    • 定义 Completed 事件的回调:该方法使用委托处理 ConnectAsync 方法中的 Completed 事件。

    • 等待直到调用完成:在本示例中,WaitOne 方法将会阻止 UI 线程,直到 Completed 事件引发或调用超时。

    说明注意:

    当从休眠状态重新激活应用时,无需创建套接字的新实例。若要再次建立连接,则调用 ConnectAsync。如果为套接字定义了任何连接首选项或要求,则在休眠状态期间将会保持它们。 有关执行模型和应用状态的详细信息,请参见 Windows Phone 8 的应用激活和停用

在本节中,将向 SocketClient 类添加 Send 方法,以便向服务器发送数据。

向 TCP 套接字服务器发送数据的步骤

  • SocketClient.cs 中,添加以下方法。

       
    /// <summary>
    /// Send the given data to the server using the established connection
    /// </summary>
    /// <param name="data">The data to send to the server</param>
    /// <returns>The result of the Send request</returns>
    public string Send(string data)
    {
        string response = "Operation Timeout";
    
        // We are re-using the _socket object initialized in the Connect method
        if (_socket != null)
        {
            // Create SocketAsyncEventArgs context object
            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
    
            // Set properties on context object
            socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
            socketEventArg.UserToken = null;
    
            // Inline event handler for the Completed event.
            // Note: This event handler was implemented inline in order 
            // to make this method self-contained.
            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
            {
                response = e.SocketError.ToString();
    
                // Unblock the UI thread
                _clientDone.Set();
            });
    
            // Add the data to be sent into the buffer
            byte[] payload = Encoding.UTF8.GetBytes(data);
            socketEventArg.SetBuffer(payload, 0, payload.Length);
    
            // Sets the state of the event to nonsignaled, causing threads to block
            _clientDone.Reset();
    
            // Make an asynchronous Send request over the socket
            _socket.SendAsync(socketEventArg);
    
            // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
            // If no response comes back within this time then proceed
            _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
        }
        else
        {
            response = "Socket is not initialized";
        }
    
        return response;
    }
    
    

    本方法会说明以下概念:

    • 创建上下文对象:该对象是对其调用异步方法的任何上下文对象(在本例中为 SendAsync)。将会在该对象上设置数据缓冲区、回调方法和各种其他特定于上下文的数据,然后将这些数据传递到异步调用。在调用完成后,可以检查该对象的完成状态和操作结果。

    • 在上下文对象上设置缓冲区:要发送到服务器的数据将作为字节数组放置在 SocketAsyncEventArgs 对象的缓冲区中。

    • 定义 Completed 事件的回调:该方法使用委托处理 SendAsync 调用中的 Completed 事件。

    • 等待直到调用完成:在本示例中,WaitOne 方法将会阻止 UI 线程,直到 Completed 事件引发或调用超时。

在本节中,将向 SocketClient 类添加 Receive 方法,以便向服务器发送数据。

接收来自 TCP 套接字服务器的数据

  • SocketClient.cs 中,添加以下代码。

    
    /// <summary>
    /// Receive data from the server using the established socket connection
    /// </summary>
    /// <returns>The data received from the server</returns>
    public string Receive()
    {
        string response = "Operation Timeout";
    
        // We are receiving over an established socket connection
        if (_socket != null)
        {
            // Create SocketAsyncEventArgs context object
            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
            socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
    
            // Setup the buffer to receive the data
            socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
    
            // Inline event handler for the Completed event.
            // Note: This even handler was implemented inline in order to make 
            // this method self-contained.
            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    // Retrieve the data from the buffer
                    response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                    response = response.Trim('\0');
                }
                else
                {
                    response = e.SocketError.ToString();
                }
    
                _clientDone.Set();
            });
    
            // Sets the state of the event to nonsignaled, causing threads to block
            _clientDone.Reset();
    
            // Make an asynchronous Receive request over the socket
            _socket.ReceiveAsync(socketEventArg);
    
            // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
            // If no response comes back within this time then proceed
            _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
        }
        else
        {
            response = "Socket is not initialized";
        }
    
        return response;
    }
    
    /// <summary>
    /// Closes the Socket connection and releases all associated resources
    /// </summary>
    public void Close()
    {
        if (_socket != null)
        {
            _socket.Close();
        }
    }
    
    
    

    本方法会说明以下概念:

    • 创建上下文对象:该对象是对其调用异步方法的任何上下文对象(在本例中为 ReceiveAsync)。将会在该对象上设置数据缓冲区、回调方法和各种其他特定于上下文的数据,然后将这些数据传递到异步调用。在调用完成后,可以检查该对象的完成状态和操作结果。

    • 在上下文对象上设置缓冲区:要从服务器接收的数据将作为字节数组放置在 SocketAsyncEventArgs 对象的缓冲区中。

    • 定义 Completed 事件的回调:该方法使用委托处理 ReceiveAsync 调用中的 Completed 事件。

    • 等待直到调用完成:在本示例中,Connect 方法将会阻止,直到 Completed 事件引发或调用超时。

    • 关闭方法。为了使客户端应用可以显式关闭创建的 Socket,向 SocketClient 类添加 Close 方法。

在上几节中,实现了一个 SocketClient 类,用来封装通过基于流的 TCP 套接字与服务器进行通信所需所有操作。现在,我们将返回到客户端应用,并添加使用此 SocketClient 类所需的功能。本应用将与计算机上的 Echo 服务和 Quote of the Day (QOTD) 服务进行通信。无论向 Echo 服务发送任何数据,Echo 服务都会回显。Quote of the Day 服务在消息中以一行或多行文本的形式返回报价。我们为 btnEchobtnGetQuote 按键的 Click 事件添加事件处理程序。我们还将添加一些方法来执行 txtOutput TextBox 的输出,并验证来自 txtRemoteHosttxtInput TextBox 元素的输入。

在应用中使用 SocketClient 类的步骤

  1. 在 MainPage.xaml.cs 类的顶部,定义以下常量:

    
    // Constants
    const int ECHO_PORT = 7;  // The Echo protocol uses port 7 in this sample
    const int QOTD_PORT = 17; // The Quote of the Day (QOTD) protocol uses port 17 in this sample
    
    
  2. MainPage.xaml.cs 中,添加以下代码。

    
    /// <summary>
    /// Handle the btnEcho_Click event by sending text to the echo server 
    /// and outputting the response
    /// </summary>
    private void btnEcho_Click(object sender, RoutedEventArgs e)
    {
        // Clear the log 
        ClearLog();
    
        // Make sure we can perform this action with valid data
        if (ValidateRemoteHost() && ValidateInput())
        {
            // Instantiate the SocketClient
            SocketClient client = new SocketClient();
            
            // Attempt to connect to the echo server
            Log(String.Format("Connecting to server '{0}' over port {1} (echo) ...", txtRemoteHost.Text, ECHO_PORT), true);
            string result = client.Connect(txtRemoteHost.Text, ECHO_PORT);
            Log(result, false);
    
            // Attempt to send our message to be echoed to the echo server
            Log(String.Format("Sending '{0}' to server ...", txtInput.Text), true);
            result = client.Send(txtInput.Text);
            Log(result, false);
    
            // Receive a response from the echo server
            Log("Requesting Receive ...", true);
            result = client.Receive();
            Log(result, false);
    
            // Close the socket connection explicitly
            client.Close();
        }
    
    }
    
    /// <summary>
    /// Handle the btnEcho_Click event by receiving text from the Quote of 
    /// the Day (QOTD) server and outputting the response 
    /// </summary>
    private void btnGetQuote_Click(object sender, RoutedEventArgs e)
    {
        // Clear the log 
        ClearLog();
    
        // Make sure we can perform this action with valid data
        if (ValidateRemoteHost())
        {
            // Instantiate the SocketClient object
            SocketClient client = new SocketClient();
    
            // Attempt connection to the Quote of the Day (QOTD) server
            Log(String.Format("Connecting to server '{0}' over port {1} (Quote of the Day) ...", txtRemoteHost.Text, QOTD_PORT), true);
            string result = client.Connect(txtRemoteHost.Text, QOTD_PORT);
            Log(result, false);
    
            // Note: The QOTD protocol is not expecting data to be sent to it.
            // So we omit a send call in this example.
    
            // Receive response from the QOTD server
            Log("Requesting Receive ...", true);
            result = client.Receive();
            Log(result, false);
    
            // Close the socket conenction explicitly
            client.Close();
        }
    }
    
    #region UI Validation
    /// <summary>
    /// Validates the txtInput TextBox
    /// </summary>
    /// <returns>True if the txtInput TextBox contains valid data, otherwise 
    /// False.
    ///</returns>
    private bool ValidateInput()
    {
        // txtInput must contain some text
        if (String.IsNullOrWhiteSpace(txtInput.Text))
        {
            MessageBox.Show("Please enter some text to echo");
             return false;
         }
    
        return true;
    }
    
    /// <summary>
    /// Validates the txtRemoteHost TextBox
    /// </summary>
    /// <returns>True if the txtRemoteHost contains valid data,
    /// otherwise False
    /// </returns>
    private bool ValidateRemoteHost()
    {
        // The txtRemoteHost must contain some text
        if (String.IsNullOrWhiteSpace(txtRemoteHost.Text))
        {
            MessageBox.Show("Please enter a host name");
            return false;
        }
    
        return true;
    }
    #endregion
    
    #region Logging
    /// <summary>
    /// Log text to the txtOutput TextBox
    /// </summary>
    /// <param name="message">The message to write to the txtOutput TextBox</param>
    /// <param name="isOutgoing">True if the message is an outgoing (client to server)
    /// message, False otherwise.
    /// </param>
    /// <remarks>We differentiate between a message from the client and server 
    /// by prepending each line  with ">>" and "<<" respectively.</remarks>
    private void Log(string message, bool isOutgoing)
    {
        string direction = (isOutgoing) ? ">> " : "<< ";
        txtOutput.Text += Environment.NewLine + direction + message;
    }
    
    /// <summary>
    /// Clears the txtOutput TextBox
    /// </summary>
    private void ClearLog()
    {
        txtOutput.Text = String.Empty;
    }
    #endregion
     
    

    在上述代码中按如下方式实现了 Echo 操作:

    • 处理 btnEcho 按键上的 Click 事件: Echo 操作在 btnEcho_Click 事件中实现。Echo 操作由套接字上的 ConnectSendReceive 操作组成。这与 GetQuote 操作相反,后者仅使用 ConnectReceive 操作。

    • SocketClient 对象的作用域被限制在方法中:这样做的目的是出于简便和保持 Echo 和 GetQuote 调用的独立性。还可以在类作用域内存储和重新使用 SocketClient 类的实例。

    • 端口号被设置为常量:在本示例中,客户端使用熟知的端口号 7 连接到 Echo 协议。在 MainPage.xaml.cs 类中,此端口号被定义为 ECHO_PORT

    • 连接:此操作通过调用 SocketClientConnect 方法完成,传递了 txtRemoteHost 中接收的主机名和 ECHO_PORT 常量中定义的端口号。验证输入,并使用 Log 方法将该操作的反馈写入到 txtOutput

    • 发送:使用 SocketClient 对象上的 Send 方法将 txtInput 字段中的文本发送到服务器。验证输入,并使用 Log 方法将该操作的反馈写入到 txtOutput

    • 接收:接着,通过调用 SocketClient 对象上的 Receive 方法接收来自回显服务器的数据。该数据通过 Log 方法写入 txtOutput

    • 关闭:最后,通过显示调用 SocketClient 对象的 Close 方法关闭套接字。

    在上述代码中按如下方式实现了 GetQuote 操作:

    • 处理 btnGetQuote 按键上的 Click 事件: GetQuote 操作在 btnGetQuote_Click 事件中实现。GetQuote 操作由套接字上的 ConnectReceive 操作组成。这与 Echo 操作相反,后者使用 ConnectSendReceive 操作。

    • SocketClient 对象的作用域被限制在方法中:这样做的目的是出于简便和保持 Echo 和 GetQuote 调用的独立性。还可以在类作用域内存储和重新使用 SocketClient 类的实例。

    • 端口号被设置为常量:在本示例中,客户端使用熟知的端口号 17 连接到 Quote of the Day (QOTD) 协议。在 MainPage.xaml.cs 类中,此端口号被定义为 QOTD_PORT

    • 连接:此操作通过调用 SocketClientConnect 方法完成,传递了 txtRemoteHost 中接收的主机名和 QOTD_PORT 常量中定义的端口号。验证输入,并使用 Log 方法将该操作的反馈写入到 txtOutput

    • 发送:对于 Quote of the Day,没有发出发送请求。我们只是通过使用“接收”请求提取了来自服务器的报价。

    • 接收:接着,通过调用 SocketClient 对象上的 Receive 方法接收来自 Quote of the Day 服务器的数据。该数据通过 Log 方法写入 txtOutput

    • 关闭:最后,通过显示调用 SocketClient 对象的 Close 方法关闭套接字。

本主题使用每台 Windows 计算机上提供的 EchoQuote of the Day 服务。在所有 Windows 版本中都提供了简单 TCP/IP 服务功能。该功能会提供了以下服务:Character GeneratorDaytimeDiscardEchoQuote of the Day。每个服务都可以通过 TCP 访问,并且都分配了一个用于通信的默认端口。默认服务与端口的映射如下所示。

服务名称

描述

端口

Echo

回显在该服务器端口上接收到的任何消息中的数据。Echo 作为网络调试和监视工具可能非常有用。

7

Quote of the Day

在消息中以一行或多行文本的形式返回报价。报价从以下文件中随机提取:%SYSTEMROOT%\System32\Drivers\Etc\Quotes。示例报价文件会与简单的 TCP/IP 服务一起安装。如果该文件丢失,则报价服务会失败。

17

Daytime

返回包含星期几、月、天、年、当前时间(以 hh:mm:ss 格式表示)和时区信息的消息。某些程序可能会将该服务的输出用于调试或监视系统时钟时间中或不同主机上的变化。

13

Character Generator

所发送数据包含一组 95 个可打印的 ASCII 字符。作为测试或解决行打印机问题的调试工具非常有用。

19

Discard

放弃该端口上接收到的所有消息,而不响应或确认。在网络设置和配置过程中,可以用作空端口来接收和路由 TCP/IP 测试消息,或者在某些情况下,程序可将其用作为消息放弃函数。

9

在您的计算机上启用简单 TCP/IP 服务的步骤

  1. 在“控制面板”中,打开“程序和功能”

  2. 单击“打开或关闭 Windows 功能”

  3. “Windows 功能”对话框中,选中“简单 TCP/IP 服务”复选框以启用此功能,然后单击“确定”

    重要说明重要说明:

    若要执行此过程,您必须是本地计算机上 Administrators 组或 Network Configuration Operators 组的成员。

  4. 在计算机上的“服务”列表中,验证“简单 TCP/IP 服务”服务是否已经启动。如果没有启动,请手动启动该服务。有关启动服务的更多信息,请参见配置服务启动方式

本节介绍如何运行本主题中生成的应用。

运行 TCP 套接字客户端应用的步骤

  1. 在设备上,通过选择“调试 | 启动调试”菜单命令来运行应用。

  2. 尝试 Echo 功能的步骤:

    1. “主机名”字段中添加主机名。

    2. “Echo 文本”字段中添加您希望发送的文本。

    3. 单击“Echo”按键。

    在输出窗口中,应会看到手机上的客户端与服务器间的通信往返过程,包括可能发生的任何错误。

  3. 尝试 Quote of the Day 功能的步骤:

    1. “主机名”字段中添加主机名。

    2. 单击“获得配额”按键。

    在输出窗口中,应会看到手机上的客户端与服务器间的通信往返过程,包括可能发生的任何错误。

显示:
© 2015 Microsoft