程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Windows 8 Store Apps學習(62) 通信: Socket TCP, Socket UDP

Windows 8 Store Apps學習(62) 通信: Socket TCP, Socket UDP

編輯:關於.NET

介紹

重新想象 Windows 8 Store Apps 之 通信

Socket - Tcp Demo

Socket - 實現一個自定義的 http server

Socket - Udp Demo

示例

1、演示 socket tcp 的應用(本例既做服務端又做客戶端)

Communication/Socket/TcpDemo.xaml

<Page
    x:Class="XamlDemo.Communication.Socket.TcpDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Communication.Socket"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    
    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0" Orientation="Horizontal">
                
            <StackPanel>
                <Button Name="btnStartListener" Content="start a socket listener" Click="btnStartListener_Click" />
                <Button Name="btnConnectListener" Content="connect to the socket listener" Click="btnConnectListener_Click" Margin="0 10 0 0" />
                <Button Name="btnSendData" Content="send data" Click="btnSendData_Click" Margin="0 10 0 0" />
                <Button Name="btnCloseSocket" Content="close server socket and client socket" Click="btnCloseSocket_Click" Margin="0 10 0 0" />
            </StackPanel>
                
            <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" Margin="20 0 0 0" />
                
        </StackPanel>
    </Grid>
</Page>

Communication/Socket/TcpDemo.xaml.cs

/*
 * 演示 socket tcp 的應用(本例既做服務端又做客戶端)
 * 
 * 通過 StreamSocketListener 實現 tcp 通信的服務端的 socket 監聽
 * 通過 StreamSocket 實現 tcp 通信的客戶端 socket
 * 
 * 注:需要在 Package.appxmanifest 中增加配置 <Capability 

Name="privateNetworkClientServer" />
 */
    
using System;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
    
namespace XamlDemo.Communication.Socket
{
    public sealed partial class TcpDemo : Page
    {
        /// <summary>
        /// 服務端 socket
        /// </summary>
        private StreamSocketListener _listener;
    
        /// <summary>
        /// 客戶端 socket
        /// </summary>
        private StreamSocket _client;
    
        /// <summary>
        /// 客戶端向服務端發送數據時的 DataWriter
        /// </summary>
        private DataWriter _writer;
    
        public TcpDemo()
        {
            this.InitializeComponent();
        }
    
        // 在服務端啟動一個 socket 監聽
        private async void btnStartListener_Click(object sender, RoutedEventArgs e)
        {
            // 實例化一個 socket 監聽對象
            _listener = new StreamSocketListener();
            // 監聽在接收到一個連接後所觸發的事件
            _listener.ConnectionReceived += _listener_ConnectionReceived;
    
            try
            {
                // 在指定的端口上啟動 socket 監聽
                await _listener.BindServiceNameAsync("2211");
    
                lblMsg.Text += "已經在本機的 2211 端口啟動了 socket(tcp) 監聽";
                lblMsg.Text += Environment.NewLine;
    
            }
            catch (Exception ex)
            {
                SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                lblMsg.Text += "errStatus: " + errStatus.ToString();
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // socket 監聽接收到一個連接後
        async void _listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
        {
            // 實例化一個 DataReader,用於讀取數據
            DataReader reader = new DataReader(args.Socket.InputStream);
    
            await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                lblMsg.Text += "服務端收到了來自: " + args.Socket.Information.RemoteHostName.RawName + ":" + args.Socket.Information.RemotePort + " 的 socket 連接";
                lblMsg.Text += Environment.NewLine;
            });
    
            try
            {
                while (true)
                {
                    // 自定義協議(header|body):前4個字節代表實際數據的長度,之後的實際數據為一個字符串數據
    
                    // 讀取 header
                    uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
                    if (sizeFieldCount != sizeof(uint))
                    {
                        // 在獲取到合法數據之前,socket 關閉了
                        return;
                    }
    
                    // 讀取 body
                    uint stringLength = reader.ReadUInt32();
                    uint actualStringLength = await reader.LoadAsync(stringLength);
                    if (stringLength != actualStringLength)
                    {
                        // 在獲取到合法數據之前,socket 關閉了
                        return;
                    }
    
                    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                    () =>
                    {
                        // 顯示客戶端發送過來的數據
                        lblMsg.Text += "接收到數據: " + reader.ReadString(actualStringLength);
                        lblMsg.Text += Environment.NewLine;
                    });
                }
            }
            catch (Exception ex)
            {
                var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                    lblMsg.Text += "errStatus: " + errStatus.ToString();
                    lblMsg.Text += Environment.NewLine;
                    lblMsg.Text += ex.ToString();
                    lblMsg.Text += Environment.NewLine;
                });
            }
        }
    
        // 創建一個客戶端 socket,並連接到服務端 socket
        private async void btnConnectListener_Click(object sender, RoutedEventArgs e)
        {
            HostName hostName;
            try
            {
                hostName = new HostName("127.0.0.1");
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
    
                return;
            }
    
            // 實例化一個客戶端 socket 對象
            _client = new StreamSocket();
    
            try
            {
                // 連接到指定的服務端 socket
                await _client.ConnectAsync(hostName, "2211");
    
                lblMsg.Text += "已經連接上了 127.0.0.1:2211";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                lblMsg.Text += "errStatus: " + errStatus.ToString();
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // 從客戶端 socket 發送一個字符串數據到服務端 socket
        private async void btnSendData_Click(object sender, RoutedEventArgs e)
        {
            // 實例化一個 DataWriter,用於發送數據
            if (_writer == null)
                _writer = new DataWriter(_client.OutputStream);
    
            // 自定義協議(header|body):前4個字節代表實際數據的長度,之後的實際數據為一個字符串數據
    
            string data = "hello webabcd " + DateTime.Now.ToString("hh:mm:ss");
            _writer.WriteUInt32(_writer.MeasureString(data)); // 寫 header 數據
            _writer.WriteString(data); // 寫 body 數據
    
            try
            {
                // 發送數據
                await _writer.StoreAsync();
    
                lblMsg.Text += "數據已發送: " + data;
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                lblMsg.Text += "errStatus: " + errStatus.ToString();
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // 關閉客戶端 socket 和服務端 socket
        private void btnCloseSocket_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                _writer.DetachStream(); // 分離 DataWriter 與 Stream 的關聯
                _writer.Dispose();
    
                _client.Dispose();
                _listener.Dispose();
    
                lblMsg.Text += "服務端 socket 和客戶端 socket 都關閉了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    }
}

2、演示 socket 的應用(演示如何實現一個 http server,需要注意的是此 http server 只能在此 app 內部調用,而不能在外部調用)

Communication/Socket/CustomHttpServer.xaml

<Page
    x:Class="XamlDemo.Communication.Socket.CustomHttpServer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Communication.Socket"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    
    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0" Orientation="Horizontal">
    
            <StackPanel>
                <Button Name="btnLaunchHttpServer" Content="啟動 http server" 

Click="btnLaunchHttpServer_Click" />
                <Button Name="btnRequestHttpServer" Content="請求 http server" 

Click="btnRequestHttpServer_Click" Margin="0 10 0 0" />
                <Button Name="btnCloseHttpServer" Content="關閉 http server" 

Click="btnCloseHttpServer_Click" Margin="0 10 0 0" />
            </StackPanel>
    
            <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" 

Margin="20 0 0 0" />
    
        </StackPanel>
    </Grid>
</Page>

Communication/Socket/CustomHttpServer.xaml.cs

/*
 * 演示 socket 的應用(演示如何實現一個 http server,需要注意的是此 http server 

只能在此 app 內部調用,而不能在外部調用)
 * 
 * 注:需要在 Package.appxmanifest 中增加配置 <Capability 

Name="privateNetworkClientServer" />
 */
    
using System;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using System.Text;
using System.Net.Http;
    
namespace XamlDemo.Communication.Socket
{
    public sealed partial class CustomHttpServer : Page
    {
        /// <summary>
        /// http server 的 socket
        /// </summary>
        private StreamSocketListener _listener;
    
        public CustomHttpServer()
        {
            this.InitializeComponent();
        }
    
        // 啟動 http server,即在服務端啟動一個 socket 監聽
        private async void btnLaunchHttpServer_Click(object sender, RoutedEventArgs e)
        {
            // 實例化一個 socket 監聽對象
            _listener = new StreamSocketListener();
            // 監聽在接收到一個連接後所觸發的事件
            _listener.ConnectionReceived += _listener_ConnectionReceived;
    
            try
            {
                // 在指定的端口上啟動 socket 監聽
                await _listener.BindServiceNameAsync("2212");
    
                lblMsg.Text += "已經在本機的 2212 端口啟動了 socket 監聽,即 http server 的地址為:http://localhost:2212/";
                lblMsg.Text += Environment.NewLine;
    
            }
            catch (Exception ex)
            {
                SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                lblMsg.Text += "errStatus: " + errStatus.ToString();
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // socket 監聽接收到一個連接後,即收到一個 http 請求後
        async void _listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
        {
            // 實例化一個 DataReader,用於讀取數據
            DataReader reader = new DataReader(args.Socket.InputStream);
    
            try
            {
                // 用於保存 http 請求的 header
                StringBuilder sb = new StringBuilder();
                while (true)
                {
                    // 一個字節一個字節地讀
                    uint loaded = await reader.LoadAsync(1);
                    if (loaded != 1)
                        return;
    
                    char c = (char)reader.ReadByte();
                    sb.Append(c);
    
                    // 碰到 \r\n\r\n 則說明已經完整地獲取了 header 信息
                    if (sb.ToString().IndexOf("\r\n\r\n") > 0)
                    {
                        await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            lblMsg.Text += "接收到的 http request header: ";
                            lblMsg.Text += Environment.NewLine;
                            lblMsg.Text += sb.ToString();
                            lblMsg.Text += Environment.NewLine;
                        });
    
    
                                                   
                        // 用於保存 http 響應的數據
                        string response = "";
    
                        // 響應的 http 頭信息
                        response += "HTTP/1.1 200 OK";
                        response += "Content-Type:text/html\r\n";
                        response += "Server:Custom Http Server\r\n";
                        response += "Content-Length:2\r\n";
                        response += "Connection: Keep-Alive\r\n\r\n"; 

// 頭信息以 \r\n\r\n 結尾
    
                        // 響應的內容
                        response += "ok";
    
                        // 將已經構造好的數據響應給客戶端
                        DataWriter writer = new DataWriter(args.Socket.OutputStream);
                        writer.WriteString(response);
                        await writer.StoreAsync();
    
                        sb.Clear();
                    }
                }
            }
            catch (Exception ex)
            {
                var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                    lblMsg.Text += "errStatus: " + errStatus.ToString();
                    lblMsg.Text += Environment.NewLine;
                    lblMsg.Text += ex.ToString();
                    lblMsg.Text += Environment.NewLine;
                });
            }
        }
    
        private async void btnRequestHttpServer_Click(object sender, RoutedEventArgs e)
        {
            HttpClient client = new HttpClient();
            // 請求 http server
            string result = await client.GetStringAsync(new Uri("http://localhost:2212/abc.html"));
                
            // 輸出 http server 的響應結果
            lblMsg.Text += "response: " + result;
            lblMsg.Text += Environment.NewLine;
    
        }
    
        // 關閉 http server,即關閉服務端 socket
        private void btnCloseHttpServer_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                _listener.Dispose();
    
                lblMsg.Text += "http server 關閉了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    }
}

查看本欄目

3、演示 socket udp 的應用(本例既做服務端又做客戶端)

Communication/Socket/UdpDemo.xaml

<Page
    x:Class="XamlDemo.Communication.Socket.UdpDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Communication.Socket"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    
    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0" Orientation="Horizontal">
                
            <StackPanel>
                <Button Name="btnStartListener" Content="start a socket 

listener" Click="btnStartListener_Click" />
                <Button Name="btnSendData" Content="send data" 

Click="btnSendData_Click" Margin="0 10 0 0" />
                <Button Name="btnCloseSocket" Content="close server socket and 

client socket" Click="btnCloseSocket_Click" Margin="0 10 0 0" />
            </StackPanel>
                
            <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" 

Margin="20 0 0 0" />
                
        </StackPanel>
    </Grid>
</Page>

Communication/Socket/UdpDemo.xaml.cs

/*
 * 演示 socket udp 的應用(本例既做服務端又做客戶端)
 * 
 * 通過 DatagramSocket 來實現 udp 通信的服務端和客戶端
 * 
 * 注:需要在 Package.appxmanifest 中增加配置 <Capability 

Name="privateNetworkClientServer" />
 * 注:udp 報文(Datagram)的最大長度為 65535(包括報文頭)
 */
    
using System;
using System.Threading;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
    
namespace XamlDemo.Communication.Socket
{
    public sealed partial class UdpDemo : Page
    {
        /// <summary>
        /// 服務端 socket
        /// </summary>
        private DatagramSocket _listener;
    
        /// <summary>
        /// 客戶端 socket
        /// </summary>
        private DatagramSocket _client;
    
        /// <summary>
        /// 客戶端向服務端發送數據時的 DataWriter
        /// </summary>
        private DataWriter _writer;
    
        public UdpDemo()
        {
            this.InitializeComponent();
        }
    
        // 在服務端啟動一個 socket 監聽
        private async void btnStartListener_Click(object sender, RoutedEventArgs e)
        {
            // 實例化一個 socket 監聽對象
            _listener = new DatagramSocket();
            // 服務端監聽在接收到信息後所觸發的事件
            _listener.MessageReceived += _listener_MessageReceived;
    
            try
            {
                // 在指定的端口上啟動 socket 監聽
                await _listener.BindServiceNameAsync("2213");
    
                lblMsg.Text += "已經在本機的 2213 端口啟動了 socket(udp) 監聽";
                lblMsg.Text += Environment.NewLine;
    
            }
            catch (Exception ex)
            {
                SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                lblMsg.Text += "errStatus: " + errStatus.ToString();
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // 服務端的 socket udp 監聽接收到信息後
        private void _listener_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
        {
            try
            {
                // 輸出接收到的數據
                DataReader dataReader = args.GetDataReader();
                uint stringLength = dataReader.UnconsumedBufferLength;
                var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    lblMsg.Text += "接收到數據: " + dataReader.ReadString(stringLength) + " - 數據來自: " + args.RemoteAddress.RawName + ":" + args.RemotePort;
                    lblMsg.Text += Environment.NewLine;
                });
            }
            catch (Exception ex)
            {
                SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                lblMsg.Text += "errStatus: " + errStatus.ToString();
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // 從客戶端 socket 發送數據到服務端 socket
        private async void btnSendData_Click(object sender, RoutedEventArgs e)
        {
            if (_client == null)
            {
                HostName hostName;
                try
                {
                    hostName = new HostName("127.0.0.1");
                }
                catch (Exception ex)
                {
                    lblMsg.Text += ex.ToString();
                    lblMsg.Text += Environment.NewLine;
    
                    return;
                }
    
                try
                {
                    // 實例化客戶端 DatagramSocket,並准備往 127.0.0.1:2213 發送數據
                    _client = new DatagramSocket();
                    await _client.ConnectAsync(hostName, "2213"); // ConnectAsync() 並非連接的意思,udp 沒有連接一說,這裡用於設置發送數據的目標
    
                    lblMsg.Text += "准備往 127.0.0.1:2213 發送數據";
                    lblMsg.Text += Environment.NewLine;
                }
                catch (Exception ex)
                {
                    SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                    lblMsg.Text += "errStatus: " + errStatus.ToString();
                    lblMsg.Text += Environment.NewLine;
                    lblMsg.Text += ex.ToString();
                    lblMsg.Text += Environment.NewLine;
                }
    
            }
    
            // 實例化一個 DataWriter,用於發送數據
            if (_writer == null)
                _writer = new DataWriter(_client.OutputStream);
    
            try
            {
                string data = "hello webabcd " + DateTime.Now.ToString("hh:mm:ss");
                _writer.WriteString(data);
    
                // 發送數據
                await _writer.StoreAsync();
    
                lblMsg.Text += "數據已發送: " + data;
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                SocketErrorStatus errStatus = SocketError.GetStatus(ex.HResult);
    
                lblMsg.Text += "errStatus: " + errStatus.ToString();
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    
        // 關閉客戶端 socket 和服務端 socket
        private void btnCloseSocket_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                _writer.DetachStream(); // 分離 DataWriter 與 Stream 的關聯
                _writer.Dispose();
    
                _client.Dispose();
                _listener.Dispose();
    
                lblMsg.Text += "服務端 socket 和客戶端 socket 都關閉了";
                lblMsg.Text += Environment.NewLine;
            }
            catch (Exception ex)
            {
                lblMsg.Text += ex.ToString();
                lblMsg.Text += Environment.NewLine;
            }
        }
    }
}

OK

[源碼下載]:http://files.cnblogs.com/webabcd/Windows8.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved