不知道大家有沒有“談Socket色變”的經歷?就像我一位朋友所說的,Socket這家伙啊,不得已而用之。哈,Socket真的那么恐怖嗎?
其實這話一點也不假,Socket有時候真的不太好操控,也不好維護,但不管怎么樣,我們還是要面對它的,沒準Socket是一位大美女哦。
關于Socket的前世今生就不用我詳述了,關于她的歷史,已經不少人仁志士為她立傳寫著了,像我們國內的百度百科、互動百科等;全球著名的如維基百科之屬。而且,能加入WP開發的學習行列的,我想各位對.NET的其它技術肯定是有一定基礎的。我也相信,各位同仁過去一定也寫過與Socket打交道的程序。那么,WP中的Socket又將如何呢?
前提公布答案吧,在WP中使用Socket跟你在其它桌面應用項目如WinForm,WPF等中是一樣的,而且說白了,WP中的Socket只不過是從Silverlight框架中繼承過來的。
.NET的一大優勢就是集成性和統一性都好,這不,你看,無論你是編寫桌面應用程序,還是WP上的應用程序,你會發現,你的學習成本不高,很多東西都是一樣的,而且是相通的。顯然這也是Win8和WP8的應用程序可以整合的原因吧。
在WP中使用Socket要注意以下幾點:
1、WP客戶端應用程序一般不被視為服務器端,因為不能進行綁定本地終結點和監聽連接。但是,收發數據是沒問題D。
2、在WP中的Socket操作(連接、接收以及發送)都是異步進行的。如果希望UI線程和后前線程進行同步,不妨使用System.Threading.ManualResetEvent類,這個東西不好講述,也不好理解。這樣吧,我舉一個例子。
有一天,NC和腦殘因為一件小事鬧沖突,鬧來鬧去還是不能解決,怎么辦呢?于是,NC和腦殘決定來一場比試。兩人約定以跑步方式比試,誰跑得快誰就是勝利者。然而,NC這個人一向比較自負,他相信腦殘絕對跑不過他。這樣,NC就修改了比賽規則:
NC讓腦殘先跑5秒,然后他才開始。
假設NC是主線程,腦殘是后臺線程,現在的情況是:主線程先等待一會兒,讓后臺線程先執行;后臺線程執行5秒后向主線程發出信號,主線程收到信號后再繼續往下執行。按照故事里的情節:NC先讓腦殘跑5秒鐘,他自己就在起跑線上等待,腦殘跑了5秒后向NC發出信號,NC看到信號后就開始跑。
下面介紹一個類——SocketAsyncEventArgs。
這個類作為啟動異步操作時傳遞的參數,它可以包含如接收數據的緩沖區、遠程主機、用戶自定義對象等內容,這個類并不復雜,打開“對象瀏覽器”看看就一目了然了。
要設置用于異步接收數據的緩沖區,應調用SetBuffer方法。
好,理論就扯到這兒,其實也沒有什么新的知識點,我只是簡單提一下罷了。
按照慣例,大家都會猜到,理論過后要干什么了,是的,付諸實踐。
?
在很多情況下,關于Socket的例子,都會做一個聊天程序的,不過,聊天程序要求服務器端和客戶都具有發送和接收數據的功能,這樣會增加實例的難度和代碼長度,不方便入門者閱讀。所以,想了一下,今天咱們不玩聊天的,今天咱們玩遙控飛機,如何?
程序代碼較長,也不便于逐一來講解,這樣吧,為了保持代碼的可讀性,我會把完整的代碼都貼出來,在代碼中我會適當地加上注釋。
先說一下原理,利用Socket進行通訊這不用說了,那是肯定的。功能是通過WP手機客戶端應用程序來控制PC端播放、暫停和停止動畫,而動畫嘛,也不弄那么復雜了,就弄個矩形從左邊移到右邊的動畫吧。
?
第一部分? 服務器端
既然要播放動畫,少不了要用WPF了,而且,也方便貼界面布局的代碼。
1、新建WPF應用程序項目。
2、打開MainWindow.xaml文件(默認新建項目后自動打開),輸入以下XAML代碼。
[html]?view plaincopyprint?
<Window?x:Class="MYServer.MainWindow"??????????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"??????????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"??????????Title="服務器端"?Height="350"?Width="525">????????????<Window.Resources>??????????<Storyboard?x:Key="std">??????????????<DoubleAnimation?Duration="0:0:5"???????????????????????????????????Storyboard.TargetName="rect"???????????????????????????????????Storyboard.TargetProperty="(Rectangle.RenderTransform).(TranslateTransform.X)"???????????????????????????????????To="400"/>??????????</Storyboard>??????</Window.Resources>????????????<Grid>??????????<Grid.RowDefinitions>??????????????<RowDefinition?/>??????????????<RowDefinition?Height="Auto"?/>??????????</Grid.RowDefinitions>??????????<Rectangle?x:Name="rect"?Grid.Row="0"?Width="50"?Height="50"?Fill="Orange"?HorizontalAlignment="Left"?VerticalAlignment="Center">??????????????<Rectangle.RenderTransform>??????????????????<TranslateTransform?X="0"?Y="0"/>??????????????</Rectangle.RenderTransform>??????????</Rectangle>??????????<TextBlock?Name="txtDisplay"?Grid.Row="1"/>??????</Grid>??</Window>??
3、打開MainWindow.xaml.cs文件,完成后臺代碼邏輯。
[csharp]?view plaincopyprint?
using?System;??using?System.Collections.Generic;??using?System.Linq;??using?System.Text;??using?System.Windows;??using?System.Windows.Controls;??using?System.Windows.Data;??using?System.Windows.Documents;??using?System.Windows.Input;??using?System.Windows.Media;??using?System.Windows.Media.Imaging;??using?System.Windows.Navigation;??using?System.Windows.Shapes;????using?System.Windows.Media.Animation;??using?System.IO;??using?System.Net;??using?System.Net.Sockets;??????namespace?MYServer??{????????????????????????public?partial?class?MainWindow?:?Window??????{??????????Storyboard?std?=?null;???????????public?MainWindow()??????????{??????????????InitializeComponent();??????????????????????????????std?=?this.Resources["std"]?as?Storyboard;????????????????????????????Socket?Server?=?new?Socket(AddressFamily.InterNetwork,?SocketType.Stream,?ProtocolType.Tcp);??????????????IPEndPoint?local?=?new?IPEndPoint(IPAddress.Any,?1377);???????????????Server.Bind(local);??????????????Server.Listen(100);????????????????????????????Server.BeginAccept(new?AsyncCallback(this.AcceptSocketCallback),?Server);??????????}??????????????????????????????????????????private?void?AcceptSocketCallback(IAsyncResult?ia)??????????{??????????????Socket?_socket?=?ia.AsyncState?as?Socket;??????????????Socket?accptSocket?=?_socket.EndAccept(ia);??????????????try??????????????{??????????????????IPEndPoint?remote?=?(IPEndPoint)accptSocket.RemoteEndPoint;????????????????????????????????????Dispatcher.BeginInvoke(new?Action<string>(this.SetIPForText),?remote.Address.ToString());??????????????????StateObject?so?=?new?StateObject();??????????????????so.theSocket?=?accptSocket;????????????????????????????????????accptSocket.BeginReceive(so.Buffer,?0,?so.Buffer.Length,?SocketFlags.None,?new?AsyncCallback(this.ReceiveCallback),?so);??????????????}??????????????catch??????????????{????????????????}????????????????????????????_socket.BeginAccept(new?AsyncCallback(this.AcceptSocketCallback),?_socket);??????????}????????????????????????????????????????private?void?ReceiveCallback(IAsyncResult?ia)??????????{??????????????StateObject?_so?=?ia.AsyncState?as?StateObject;??????????????Socket?_socket?=?_so.theSocket;??????????????try??????????????{??????????????????int?n?=?_socket.EndReceive(ia);??????????????????string?msg?=?Encoding.UTF8.GetString(_so.Buffer,?0,?n);????????????????????????????????????switch?(msg)??????????????????{??????????????????????case?"play":??????????????????????????Dispatcher.BeginInvoke(new?Action(this.Play),?null);??????????????????????????break;??????????????????????case?"pause":??????????????????????????Dispatcher.BeginInvoke(new?Action(this.Pause),?null);??????????????????????????break;??????????????????????case?"stop":??????????????????????????Dispatcher.BeginInvoke(new?Action(this.Stop),?null);??????????????????????????break;??????????????????????default:??????????????????????????break;??????????????????}??????????????}??????????????catch???????????????{??????????????}??????????????_so?=?new?StateObject();??????????????_so.theSocket?=?_socket;????????????????????????????_socket.BeginReceive(_so.Buffer,??????????????????????????????????0,??????????????????????????????????_so.Buffer.Length,??????????????????????????????????SocketFlags.None,??????????????????????????????????new?AsyncCallback(this.ReceiveCallback),??????????????????????????????????_so);??????????}????????????????????????????????????????private?void?SetIPForText(string?ip)??????????{??????????????this.txtDisplay.Text?=?"客戶端IP:"?+?ip;??????????}???????????#region?控制動畫的方法??????????private?void?Play()??????????{??????????????std.Begin();??????????}??????????private?void?Pause()??????????{??????????????std.Pause();??????????}??????????private?void?Stop()??????????{??????????????std.Stop();??????????}??????????#endregion??????}??????????????????????????public?class?StateObject??????{??????????private?const?int?BUFFER_SIZE?=?512;????????????public?byte[]?Buffer?{?get;??set;?}????????????public?Socket?theSocket?{?get;?set;?}??????????????????????????????????????????public?StateObject()??????????{??????????????this.Buffer?=?new?byte[BUFFER_SIZE];??????????}??????}??}??
?
?
第二部分? WP客戶端
1、新建Windows Phone應用程序項目。
2、打開MainPage.xaml文件,參考下面的XAML代碼。
[html]?view plaincopyprint?
<phone:PhoneApplicationPage???????x:Class="WPClient.MainPage"??????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"??????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"??????xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"??????xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"??????xmlns:d="http://schemas.microsoft.com/expression/blend/2008"??????xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"??????mc:Ignorable="d"?d:DesignWidth="480"?d:DesignHeight="768"??????FontFamily="{StaticResource?PhoneFontFamilyNormal}"??????FontSize="{StaticResource?PhoneFontSizeNormal}"??????Foreground="{StaticResource?PhoneForegroundBrush}"??????SupportedOrientations="Portrait"?Orientation="Portrait"??????shell:SystemTray.IsVisible="True">??????????????<Grid?x:Name="LayoutRoot"?Background="Transparent">??????????<Grid.RowDefinitions>??????????????<RowDefinition?Height="Auto"/>??????????????<RowDefinition?Height="*"/>??????????</Grid.RowDefinitions>??????????????????????<StackPanel?x:Name="TitlePanel"?Grid.Row="0"?Margin="12,17,0,28">??????????????<TextBlock?x:Name="ApplicationTitle"?Text="我的應用程序"?Style="{StaticResource?PhoneTextNormalStyle}"/>??????????????<TextBlock?x:Name="PageTitle"?Text="頁面名稱"?Margin="9,-7,0,0"?Style="{StaticResource?PhoneTextTitle1Style}"/>??????????</StackPanel>??????????????????????<Grid?x:Name="ContentPanel"?Grid.Row="1"?Margin="12,0,12,0">??????????????<Grid.RowDefinitions>??????????????????<RowDefinition?Height="auto"/>??????????????????<RowDefinition?Height="*"/>??????????????</Grid.RowDefinitions>??????????????<Grid?Grid.Row="0">??????????????????<Grid.ColumnDefinitions>??????????????????????<ColumnDefinition?Width="Auto"?/>??????????????????????<ColumnDefinition?/>??????????????????????<ColumnDefinition?Width="Auto"?/>??????????????????</Grid.ColumnDefinitions>??????????????????<TextBlock?Grid.Column="0"?VerticalAlignment="Center"?Text="服務器IP:"?/>??????????????????<TextBox?Name="txtServerIP"?Grid.Column="1"/>??????????????????<Button?Grid.Column="2"?Content="連接"?Click="onConnect"/>??????????????</Grid>??????????????<StackPanel?Grid.Row="1">??????????????????<Button?Content="放播動畫"?Click="onPlay"/>??????????????????<Button?Content="暫停動畫"?Click="onPause"/>??????????????????<Button?Content="停止動畫"?Click="onStop"/>??????????????????<TextBlock?Name="txtbInfo"?Margin="3,18,3,0"/>??????????????</StackPanel>??????????</Grid>??????</Grid>???????????????<!--<phone:PhoneApplicationPage.ApplicationBar>??????????<shell:ApplicationBar?IsVisible="True"?IsMenuEnabled="True">??????????????<shell:ApplicationBarIconButton?IconUri="/Images/appbar_button1.png"?Text="按鈕?1"/>??????????????<shell:ApplicationBarIconButton?IconUri="/Images/appbar_button2.png"?Text="按鈕?2"/>??????????????<shell:ApplicationBar.MenuItems>??????????????????<shell:ApplicationBarMenuItem?Text="菜單項?1"/>??????????????????<shell:ApplicationBarMenuItem?Text="菜單項?2"/>??????????????</shell:ApplicationBar.MenuItems>??????????</shell:ApplicationBar>??????</phone:PhoneApplicationPage.ApplicationBar>-->????</phone:PhoneApplicationPage>??
3、打開MainPage.xaml.cs,輸入以下代碼。
[csharp]?view plaincopyprint?
using?System;??using?System.Collections.Generic;??using?System.Linq;??using?System.Net;??using?System.Windows;??using?System.Windows.Controls;??using?System.Windows.Documents;??using?System.Windows.Input;??using?System.Windows.Media;??using?System.Windows.Media.Animation;??using?System.Windows.Shapes;??using?Microsoft.Phone.Controls;????using?System.Net.Sockets;??using?System.IO;??using?System.Threading;????namespace?WPClient??{??????public?partial?class?MainPage?:?PhoneApplicationPage??????{??????????Socket?mySocket?=?null;??????????ManualResetEvent?MyEvent?=?null;????????????????????public?MainPage()??????????{??????????????InitializeComponent();??????????}????????????protected?override?void?OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs?e)??????????{??????????????base.OnNavigatedTo(e);????????????????if?(mySocket?==?null)??????????????{??????????????????mySocket?=?new?Socket(AddressFamily.InterNetwork,?SocketType.Stream,?ProtocolType.Tcp);??????????????}??????????????if?(MyEvent?==?null)??????????????{??????????????????MyEvent?=?new?ManualResetEvent(false);??????????????}??????????}????????????protected?override?void?OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs?e)??????????{??????????????if?(mySocket?!=?null)??????????????{??????????????????mySocket.Shutdown(SocketShutdown.Both);??????????????????mySocket.Close();??????????????}??????????????base.OnNavigatedFrom(e);??????????}????????????private?void?onConnect(object?sender,?RoutedEventArgs?e)??????????{??????????????if?(mySocket?!=?null)??????????????{??????????????????SocketAsyncEventArgs?connArg?=?new?SocketAsyncEventArgs();????????????????????????????????????connArg.RemoteEndPoint?=?new?DnsEndPoint(this.txtServerIP.Text,?1377);????????????????????????????????????connArg.Completed?+=?(sendObj,?arg)?=>??????????????????{??????????????????????if?(arg.SocketError?==?SocketError.Success)???????????????????????{??????????????????????????Dispatcher.BeginInvoke(()?=>?txtbInfo.Text?=?"連接成功。");??????????????????????}??????????????????????else??????????????????????{??????????????????????????Dispatcher.BeginInvoke(()?=>??????????????????????????{??????????????????????????????txtbInfo.Text?=?"連接失敗,錯誤:"?+?arg.SocketError.ToString();??????????????????????????});??????????????????????}????????????????????????????????????????????MyEvent.Set();??????????????????};????????????????????????????????????MyEvent.Reset();??????????????????txtbInfo.Text?=?"正在連接,請等候……";????????????????????????????????????mySocket.ConnectAsync(connArg);????????????????????????????????????MyEvent.WaitOne(6000);??????????????}??????????}????????????private?void?onPause(object?sender,?RoutedEventArgs?e)??????????{??????????????SendCommand("pause");??????????}????????????private?void?onStop(object?sender,?RoutedEventArgs?e)??????????{??????????????SendCommand("stop");??????????}????????????private?void?onPlay(object?sender,?RoutedEventArgs?e)??????????{??????????????SendCommand("play");??????????}??????????????private?void?SendCommand(string?txt)??????????{??????????????if?(mySocket?!=?null?&&?mySocket.Connected)??????????????{??????????????????SocketAsyncEventArgs?sendArg?=?new?SocketAsyncEventArgs();??????????????????byte[]?buffer?=?System.Text.Encoding.UTF8.GetBytes(txt);??????????????????sendArg.SetBuffer(buffer,?0,?buffer.Length);????????????????????????????????????sendArg.Completed?+=?(objSender,?mArg)?=>??????????????????????{????????????????????????????????????????????????????if?(mArg.SocketError?==?SocketError.Success)??????????????????????????{??????????????????????????????Dispatcher.BeginInvoke(()?=>?txtbInfo.Text?=?"發送成功。");??????????????????????????}??????????????????????????else??????????????????????????{??????????????????????????????Dispatcher.BeginInvoke(()?=>??????????????????????????????????{??????????????????????????????????????this.txtbInfo.Text?=?"發送失敗,錯誤:"?+?mArg.SocketError.ToString();??????????????????????????????????});??????????????????????????}????????????????????????????????????????????????????MyEvent.Set();??????????????????????};????????????????????????????????????MyEvent.Reset();??????????????????txtbInfo.Text?=?"正在發送,請等候……";????????????????????????????????????mySocket.SendAsync(sendArg);????????????????????????????????????MyEvent.WaitOne(6000);??????????????}??????????}??????}??}??
?
先運行服務器端,再在WP模擬器或真實手機上運行客戶端。
在手機客戶端中,輸入IP地址,點“連接”,連接成功后,就可以發送指令了。
?
?好的,就到這兒吧,示例的源碼我會上專到“資源”中,有需要的話,大家可以按標題下載。
轉載于:https://www.cnblogs.com/songtzu/archive/2012/07/24/2607192.html
總結
以上是生活随笔為你收集整理的Windows Phone开发(46):与Socket有个约会 转:http://blog.csdn.net/tcjiaan/article/details/7669315...的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。