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 + "\r\n";
            }
            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 Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.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訂閱源的,太晚了,以后再補。晚安!

         


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM