• Windows 10开发基础——网络编程


    主要内容:

    1. HttpClient类
    2. Socket通信
    3. WCF通信

         HttpClient类

         在UWP中可以用来进行网络通信的HttpClient类有两个,System.Net.Http.HttpClient和Windows.Web.Http.HttpClient,两者使用上的差别并不大,但我们优先考虑后者,因为它位于Windows.Foundation.UniversalApiContract程序集中,是本地代码,效率更高。我们主要学习的也是Windows.Web.Http.HttpClient了。

         使用HttpClient类,我们可以向指定的URI发出HTTP请求,并获取从服务器返回的数据。发起请求的方式有GET、POST PUT和 DELETE,请求都是异步请求。同时我们还需要一个HttpResponseMessage对象,用来声明从 HTTP 请求接收到的 HTTP 响应消息。

          HttpClient httpClient = new HttpClient();

         //添加用户代理标头

          httpClient.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (compatible;MSIE 10.0;Windows NT 6.2;WOW64;Trident/6.0)");

          HttpResponseMessage response =  await httpClient.GetAsync(new Uri(tbUrl.Text));//发送请求,此处是GET的方式,其他方式类似

          response.EnsureSuccessStatusCode();//确保请求成功

       

         //Buffer方式读取返回结果

          IBuffer buffer = await response.Content.ReadAsBufferAsync();

          //流方式读取返回结果

           IInputStream inputStream= await response.Content.ReadAsInputStreamAsync();

          //字符串方式读取返回结果

          string result = await response.Content.ReadAsStringAsync();

       

          上面是HttpClient类来实现HTTP请求的一般方式了,ok,看常规演示:

          请求HTML页面:我们请求返回的HTML,最后都转换成了string类型,然后将这个string类型的值给了WebView控件的NavigateToString方法,它会自动处理HTML标记。(PS:你如果觉得这样还不如直接把URI给WebView控件的Navigate方法,反正显示效果一样,那你就把string值用其他文本控件显示吧!)还有,读取字符串直接用ReadAsStringAsync方法就行啦,后面的只为折腾一下。

          private async void btn_get_Click(object sender, RoutedEventArgs e)
            {
                //http://static.cnblogs.com/images/logo_small.gif
                //http://www.cnblogs.com/czhwust/p/Win10_file.html
                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (compatible;MSIE 10.0;Windows NT 6.2;WOW64;Trident/6.0)");
    
                if (String.IsNullOrEmpty(tbUrl.Text))
                {
                    tbstatus.Text = "输入的URL为空";
                }
                else
                {
                    try
                    {                
                        tbstatus.Text = " 等待响应......";
                        HttpResponseMessage response =  await httpClient.GetAsync(new Uri(tbUrl.Text));
                   
                        response.EnsureSuccessStatusCode();//确保请求成功
                        tbstatus.Text = response.StatusCode + " " + response.ReasonPhrase;
    
                        //请求html
    
                        //字符串方式读取返回结果
                        string result = await response.Content.ReadAsStringAsync();
                        wv.NavigateToString(result);
    
                        //Buffer方式读取
                        //IBuffer buffer = await   response.Content.ReadAsBufferAsync();
                        //using (var dataReader = DataReader.FromBuffer(buffer))
                        //{
                        //    string result = dataReader.ReadString(buffer.Length);
                        //    wv.NavigateToString(result);
                        //}
    
                        //Stream方式读取
                        //var inputstream = await  response.Content.ReadAsInputStreamAsync();
                        // Stream stream= inputstream.AsStreamForRead();
                        // using (StreamReader reader=new StreamReader(stream))
                        // {
                        //   string result= reader.ReadToEnd();
                        //   wv.NavigateToString(result);
                        // }               
                    }
                    catch (Exception ex)
                    {
                        tbstatus.Text = ex.ToString();
                    }
                }
            }

         请求图片在请求图片的时候,WriteToStreamAsync方法最简捷,后面的同样是为了折腾,但可以仔细体会一下。。。(PS:直接把网络图片的地址赋值给Image控件的Source属性就能显示图片啦,我是砸场子的!)

      private async void btn_get_Click(object sender, RoutedEventArgs e)
            {
                //http://static.cnblogs.com/images/logo_small.gif
                //http://www.cnblogs.com/czhwust/p/Win10_file.html
                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (compatible;MSIE 10.0;Windows NT 6.2;WOW64;Trident/6.0)");
    
                if (String.IsNullOrEmpty(tbUrl.Text))
                {
                    tbstatus.Text = "输入的URL为空";
                }
                else
                {
                    try
                    {
                        tbstatus.Text = " 等待响应......";
                        HttpResponseMessage response = await httpClient.GetAsync(new Uri(tbUrl.Text));
    
                        response.EnsureSuccessStatusCode();//确保请求成功
                        tbstatus.Text = response.StatusCode + " " + response.ReasonPhrase;
    
                        //请求图片                
                        BitmapImage bitmap = new BitmapImage();
    
                        //   WriteToStreamAsync
                        using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
                        {
                            await response.Content.WriteToStreamAsync(stream);
                            stream.Seek(0ul);
                            bitmap.SetSource(stream);
                            img.Source = bitmap;
                        }
    
                        //         IInputStream   >>  IRandomAccessStream
                        //IInputStream inputStream = await response.Content.ReadAsInputStreamAsync();
                        //using (IRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream())
                        //{
                        //    using (IOutputStream outputStream = randomAccessStream.GetOutputStreamAt(0))
                        //    {
                        //        await RandomAccessStream.CopyAsync(inputStream, outputStream);
                        //        randomAccessStream.Seek(0);
    
                        //        bitmap.SetSource(randomAccessStream);
                        //        img.Source = bitmap;
                        //    }
                        //}
    
                        //          IBuffer  >> IRandomAccessStream
                        //IBuffer buffer = await response.Content.ReadAsBufferAsync();
                        //using (IRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream())
                        //{
                        //    using (DataWriter datawriter = new DataWriter(randomAccessStream.GetOutputStreamAt(0)))
                        //    {
                        //        datawriter.WriteBuffer(buffer, 0, buffer.Length);
                        //        await datawriter.StoreAsync();
                        //        randomAccessStream.Seek(0);
                        //        bitmap.SetSource(randomAccessStream);
                        //        img.Source = bitmap;
                        //    }
                        //}
                    }
                    catch (Exception ex)
                    {
                        tbstatus.Text = ex.ToString();
                    }
                }
            }

         Socket通信

          Socket通信是一种点对点的通信技术,我们可以利用它开发点对点交互通信的软件。作为一种常见的底层网络通信技术,Socket具有简单易用、连接稳定、数据传送能力强等特点。HTTP通信是一种临时的,无状态的通信,在客户端发出HTTP请求,服务端做出一次响应之后,HTTP连接就会断开,当我们希望获取新的数据时,只能再发送一次HTTP请求,而Socket通信则是以IP地址和端口号为连接的一个通信句柄,以端到端为通信模型的网络通信协议。Socket能够保证连接的持久性,一旦与服务器成功建立连接,服务器相应的端口将会处于开放状态,此时客户端能够通过Socket建立的通道,向服务器开放的端口发出操作指令,而客户端同时也能得到服务端即时反馈的信息,直到程序发出断开指令或网络断开,Socket才会结束整个连接过程。

          Socket通信支持两种工作模式。一种是基于TCP模式,该模式是面向连接的,顺序进行的可靠交付方式,另一种是UDP模式,它是无连接的,资源消耗少的不可靠交付方式。关于二者更详细的区别,请自行百度了解。在UWP中Socket通信相关的类位于Windows.Networking.Sockets命名空间下,StreamSocket类对应于UDP,DatagramSocket类对应TCP。

          直接开始演示:

          首先,我们要完成服务端的编码,新建一个控制台应用程序。(贴出全部代码,不作过多解释。)   

         static void Main(string[] args)
            {
                int receiveLength;
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 9900);
                Socket newSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Udp);
                newSocket.Bind(ipEndPoint);
                newSocket.Listen(10);
                Console.WriteLine(" 等待客户端的连接 ");
    
                Socket client = newSocket.Accept();
                IPEndPoint clientIp = (IPEndPoint)client.RemoteEndPoint;
                Console.WriteLine(" 连接客户端地址 :" + clientIp.Address + ",端口号:" + clientIp.Port);
    
                while (true)
                {
                    byte[] data = new byte[1024];
                    receiveLength = client.Receive(data);
                    Console.WriteLine(" 获取字符串的长度 " + receiveLength);
                    if (receiveLength == 0)
                        break;
                    string getData = Encoding.UTF8.GetString(data, 0, receiveLength);
                    Console.WriteLine(" 从客户端获得的数据 :" + getData);
    
                    byte [] send = new byte[1024];
                    send = Encoding.UTF8.GetBytes("response :" + getData);
                    client.Send(send, send.Length, SocketFlags.None);
                }
    
                Console.WriteLine("Discnnected from " + clientIp.Address);
                client.Close();
                newSocket.Close();
            }

           然后就是客户端了,这里需要注意的是客户端在给服务端发消息时,同时读取了服务端发送给客户端的消息(服务端发给客户端的消息是 response:+客户端发来的消息)。  

        private async void btnConnect_Click(object sender, RoutedEventArgs e)
            {
                try
                {
                    socket = new StreamSocket();
                    await socket.ConnectAsync(new HostName(tbIP.Text), tbPort.Text);//与服务端建立连接
                    tbInfo.Text = " 连接成功";
                }
                catch (Exception ex)
                {
                    tbInfo.Text = " 连接服务器错误:"+ex.ToString();
                }
            }
    
            private void btnClose_Click(object sender, RoutedEventArgs e)
            {
                //断开建立
                reader.Dispose();
                writer.Dispose();
                socket.Dispose();
                tbInfo.Text = " 关闭成功";
            }
    
            private void btnSend_Click(object sender, RoutedEventArgs e)
            {
                string str = tbMsg.Text;
                SendMsg(str,socket);//发送消息
            }
    
            private async void SendMsg(string str, StreamSocket socket)
            {
                try
                {
                    //发送数据流
                    writer = new DataWriter(socket.OutputStream);
                    writer.WriteString(str);
                    await writer.StoreAsync();
    
                    //读取数据流
                    reader = new DataReader(socket.InputStream);
                    reader.InputStreamOptions = InputStreamOptions.Partial;
                    await reader.LoadAsync(1024);
                    string data = reader.ReadString(reader.UnconsumedBufferLength);
    
                    tbReceivedMsg.Text += data + "
    ";
                }
                catch (Exception ex)
                {
                    tbInfo.Text = " 出现异常:"+ex.ToString();
                }
            }

             运行结果:

              

         WCF通信

          WCF(Windows Communication Foundation)也是一种重要的数据通信技术,它在.NET Framework 3.0中引入,主要优点在于服务集成,使分布式开发更加灵活稳定。客户端与WCF服务进行通信时需要借助代理,也就是添加服务引用。

          首先我们来完成WCF服务部分的编码,新建一个Visual C#语言的ASP.NET空Web应用程序。我们需要添加一个DataClass.cs的类文件和一个NewsDataService.svc的WCF服务文件。

    DataClass.cs:

    我们在添加[DataContract]时,可能无法导入命名空间,这时候我们要手动添加引用System.Runtime.Serialization,它的详细路径是 C:Program Files (x86)Reference AssembliesMicrosoftFramework.NETFrameworkv4.5System.Runtime.Serialization.dll

    namespace WCFServer
    {
       [DataContract]
      public  class DataClass
        {
            [DataMember]
            public string NewsTime { set; get; }
    
            [DataMember]
            public string NewsTitle { get; set; }      
        }
    }

    NewsDataService.svc:

       public class NewsDataService : INewsDataService
        {
           public DataClass [] News()
            {
                List<DataClass> newsData = new List<DataClass>()
                {
                    new DataClass {NewsTitle="这是新闻标题1",NewsTime="2015-10-10" },
                    new DataClass {NewsTitle="这是新闻标题2",NewsTime="2015-10-11" },
                    new DataClass {NewsTitle="这是新闻标题3",NewsTime="2015-10-12" },
                    new DataClass {NewsTitle="这是新闻标题4",NewsTime="2015-10-13" },
                    new DataClass {NewsTitle="这是新闻标题5",NewsTime="2015-10-14" },
                };
                return newsData.ToArray();
            }
        }

    INewsDataService.cs:

    namespace WCFServer
    {
        [ServiceContract]
        public interface INewsDataService
        {
            [OperationContract]
            DataClass[] News();
        }
    }

          然后是客户端部分的编码。首先我们要添加服务引用(右键”解决方案资源管理器“中的“引用”节点即可看到此选项),然后在下面的对话框中的“地址”输入WCF服务端的URI,点击“转到”,等加载完毕,自定义一个命名空间名称,点击“确定”即可,然后就可以在客户端调用服务器上的WCF服务了。

          

          我们首先得将服务端运行起来,客户端才能调用,在运行服务端时,可能我们直接运行项目,会报错(Forbidden),这时,我们可以选中NewsDataService.svc,然后右键,选择“在浏览器中查看”,出现上边右图的效果,ok!

        客户端程序界面部分:

        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="49,54,0,0" TextWrapping="Wrap" Text="WCF网络通信" VerticalAlignment="Top"/>
            <ListView x:Name="listView" HorizontalAlignment="Left" Height="266" Margin="49,118,0,0" VerticalAlignment="Top" Width="228">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding NewsTitle}"></TextBlock>
                            <TextBlock Text="{Binding NewsTime}"></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <Button x:Name="btn_getData" Content="获取数据" HorizontalAlignment="Left" Margin="49,409,0,0" VerticalAlignment="Top" Click="btn_getData_Click"/>
        </Grid>

         后台代码:

        private async void btn_getData_Click(object sender, RoutedEventArgs e)
            {
                NewsDataServiceClient client = new NewsDataServiceClient();
                ObservableCollection<DataClass> data = await client.NewsAsync();
                listView.ItemsSource = data;
            }

         运行效果:

         

            紧接着,我们再来看如何调用Web Service。这个其实和调用WCF服务差不多的,首先也是添加服务引用(http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx),在http://webservice.webxml.com.cn这个网站上可以找到很多的Web Service供调用(不过好像经常打不开),然后这几行代码就OK

     private async void btn_getData_Click(object sender, RoutedEventArgs e)
            {
                MobileCodeWSSoapClient client = new MobileCodeWSSoapClient();
                string result=await  client.getMobileCodeInfoAsync(tbTel.Text," ");
                txtresult.Text = result;
            }

           运行结果:

           

    好了,先到这里,本来还有一个RSS订阅源的,太晚了,以后再补。晚安!

             

  • 相关阅读:
    libxml2 解析文档的例子
    FreeRTOS之任务优先级的分配
    idea中快速重写父类方法
    组件里面调用组建的方法
    sproot 注解学习记录 (含给实现类起名字的方法)
    直播技术没有那么神秘,你也可以DIY
    Java服务端API接口统一加密和解密
    把对象交给spring管理的3种方法及经典应用
    Dart空安全的底层原理与适配
    Dart 中 final和const 区别
  • 原文地址:https://www.cnblogs.com/czhwust/p/Win10_net1.html
Copyright © 2020-2023  润新知