與眾不同 windows phone (46) - 8.0 通信: Socket, 其它
作者:webabcd
介紹
與眾不同 windows phone 8.0 之 通信
- Socket Demo
- 獲取當前連接的信息
- http rss odata socket bluetooth nfc voip winsock
示例
1、演示 socket tcp 的應用(本例既做服務端又做客戶端)
Communication/SocketDemo.xaml
<phone:PhoneApplicationPage x:Class="Demo.Communication.SocketDemo" 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" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" shell:SystemTray.IsVisible="True"> <Grid Background="Transparent"> <StackPanel Orientation="Vertical"> <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" TextWrapping="Wrap" Margin="20 0 0 0" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
Communication/SocketDemo.xaml.cs
/* * 演示 socket tcp 的應用(本例既做服務端又做客戶端) * * 通過 StreamSocketListener 實現 tcp 通信的服務端的 socket 監聽 * 通過 StreamSocket 實現 tcp 通信的客戶端 socket * * 注:需要在 manifest 中增加配置 <Capability Name="ID_CAP_NETWORKING" /> * * * 另: * 本例完全摘自之前寫的 win8 socket demo */ using System; using System.Windows; using Microsoft.Phone.Controls; using Windows.Networking.Sockets; using Windows.Storage.Streams; using Windows.Networking; namespace Demo.Communication { public partial class SocketDemo : PhoneApplicationPage { /// <summary> /// 服務端 socket /// </summary> private StreamSocketListener _listener; /// <summary> /// 客戶端 socket /// </summary> private StreamSocket _client; /// <summary> /// 客戶端向服務端發送數據時的 DataWriter /// </summary> private DataWriter _writer; public SocketDemo() { 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); this.Dispatcher.BeginInvoke(delegate() { 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; } this.Dispatcher.BeginInvoke(delegate() { // 顯示客戶端發送過來的數據 lblMsg.Text += "接收到數據: " + reader.ReadString(actualStringLength); lblMsg.Text += Environment.NewLine; }); } } catch (Exception ex) { this.Dispatcher.BeginInvoke(delegate() { 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、演示如何獲取當前連接的信息
Communication/ConnectionProfileDemo.xaml.cs
/* * 演示如何獲取當前連接的信息 * * * 注: * 關於數據成本的判斷參見:http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/jj207005 */ using System; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Windows.Networking.Connectivity; namespace Demo.Communication { public partial class ConnectionProfileDemo : PhoneApplicationPage { public ConnectionProfileDemo() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 獲取當前的 Internet 連接信息 ConnectionProfile connectionProfile = NetworkInformation.GetInternetConnectionProfile(); /* * 獲取由 IANA(Internet Assigned Names Authority - Internet 編號分配管理機構) 定義的接口類型 * 1 - 其他類型的網絡接口 * 6 - 以太網網絡接口 * 9 - 標記環網絡接口 * 23 - PPP 網絡接口 * 24 - 軟件環回網絡接口 * 37 - ATM 網絡接口 * 71 - IEEE 802.11 無線網絡接口 * 131 - 隧道類型封裝網絡接口 * 144 - IEEE 1394 (Firewire) 高性能串行總線網絡接口 */ uint ianaInterfaceType = connectionProfile.NetworkAdapter.IanaInterfaceType; lblMsg.Text = "接口類型: " + ianaInterfaceType; lblMsg.Text += Environment.NewLine; ConnectionCost connectionCost = connectionProfile.GetConnectionCost(); // 網絡成本的類型: Unknown, Unrestricted(無限制), Fixed, Variable NetworkCostType networkCostType = connectionCost.NetworkCostType; lblMsg.Text += "網絡成本的類型: " + networkCostType.ToString(); lblMsg.Text += Environment.NewLine; lblMsg.Text += "是否接近了數據限制的閾值: " + connectionCost.ApproachingDataLimit; lblMsg.Text += Environment.NewLine; lblMsg.Text += "是否超過了數據限制的閾值: " + connectionCost.OverDataLimit; lblMsg.Text += Environment.NewLine; lblMsg.Text += "是否處於漫游網絡(即本地提供商以外的網絡): " + connectionCost.Roaming; base.OnNavigatedTo(e); } } }
3、其它(http rss odata socket bluetooth nfc voip winsock)
Communication/Other.xaml
<phone:PhoneApplicationPage x:Class="Demo.Communication.Other" 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" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" shell:SystemTray.IsVisible="True"> <Grid Background="Transparent"> <StackPanel Orientation="Vertical"> <TextBlock Name="lblMsg" TextWrapping="Wrap"> <Run>1、序列化, http, rss, socket 參見之前寫的 win8 相關的文章即可</Run> <LineBreak /> <Run>2、OData:參見:http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/gg521146</Run> <LineBreak /> <Run>3、藍牙:參見:http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/jj207007</Run> <LineBreak /> <Run>4、NFC:參見:http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/jj207060</Run> <LineBreak /> <Run>5、VoIP:參見:http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/jj206983, http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/jj207046, http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/jj553780</Run> <LineBreak /> <Run>6、支持 Winsock API(socket 的本地 api),關於 wp8 支持的 Win32 API 參見:http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/jj662956</Run> <LineBreak /> </TextBlock> </StackPanel> </Grid> </phone:PhoneApplicationPage>
OK
[源碼下載]