zoukankan      html  css  js  c++  java
  • 重新想象 Windows 8 Store Apps (62)

    [源码下载]


    重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP



    作者:webabcd


    介绍
    重新想象 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);
    
                        // 碰到 
    
     则说明已经完整地获取了 header 信息
                        if (sb.ToString().IndexOf("
    
    ") > 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
    ";
                            response += "Server:Custom Http Server
    ";
                            response += "Content-Length:2
    ";
                            response += "Connection: Keep-Alive
    
    "; // 头信息以 
    
     结尾
    
                            // 响应的内容
                            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
    [源码下载]

  • 相关阅读:
    WPF XAML之bing使用StringFormat
    C#程序以管理员权限运行
    注册表REG文件编写大全
    linux 的基本操作(编写shell 脚本)
    linux的基本操作(正则表达式)
    linux的基本操作(shell 脚本的基础知识)
    linux的基本操作(RPM包或者安装源码包)
    linux的基本操作(文件压缩与打包)
    linux的基本操作(文本编辑工具vim)
    linux的基本操作(磁盘管理)
  • 原文地址:https://www.cnblogs.com/webabcd/p/3340090.html
Copyright © 2011-2022 走看看