Windows Phone 7 網路程式設計之使用Socket
阿新 • • 發佈:2020-10-26
芒果更新的Windows Phone 7.1版本的API提供了Socket程式設計的介面,這給Windows Phone 7的網路開發又添加了一把利器,對於Windows Phone 7上的聊天軟體開發是一件非常happy的事情。下面用一個小例子來演示一下Windows Phone 7上的Socket程式設計。用Windows Phone 7上的客戶端程式作為Socket客戶端,Windows控制檯程式作為伺服器端,ip取你電腦本機的ip,埠號用8888,實現了Windows Phone 7客戶端向伺服器端傳送訊息和接收訊息的功能。
先來看看演示的效果
(1) Windows Phone 7客戶端客戶端的實現。
MainPage.xaml
<phone:PhoneApplicationPage x:Class="SocketTest.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="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="Socket測試" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock FontSize="30" Text="主機IP:" Margin="12,23,0,540" HorizontalAlignment="Left" Width="99" /> <TextBox x:Name="Host" InputScope="Digits" HorizontalAlignment="Stretch" Text="192.168.1.102" Margin="110,6,0,523" /> <TextBlock FontSize="30" Text="埠號:" Margin="9,102,345,451" /> <TextBox x:Name="Port" InputScope="Digits" HorizontalAlignment="Stretch" Text="8888" Margin="110,90,0,433" /> <TextBlock FontSize="30" Text="傳送的訊息內容:" Margin="6,180,157,374" /> <TextBox x:Name="Message" HorizontalAlignment="Stretch" Margin="-6,226,6,300" /> <Button x:Name="SendButton" Content="傳送" Click="SendButton_Click" Margin="0,509,12,6" /> <ListBox Height="190" HorizontalAlignment="Left" Margin="-4,313,0,0" Name="listBox1" VerticalAlignment="Top" Width="460" /> </Grid> </Grid></phone:PhoneApplicationPage>
cs頁面
using System;using System.Net;using System.Windows;using Microsoft.Phone.Controls;using System.Text;using System.Net.Sockets;namespace SocketTest{ public partial class MainPage : PhoneApplicationPage { public MainPage() { InitializeComponent(); } private void SendButton_Click(object sender, RoutedEventArgs e) { // 判斷是否已經輸入了IP地址和埠 if (string.IsNullOrEmpty(Host.Text) || string.IsNullOrEmpty(Port.Text)) { MessageBox.Show("麻煩輸入以下主機IP和埠號,謝謝!"); return; } //主機IP地址 string host = Host.Text.Trim(); //埠號 int port = Convert.ToInt32(Port.Text.Trim()); //建立一個終結點對像 DnsEndPoint hostEntry = new DnsEndPoint(host, port); //建立一個Socket物件 Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //建立一個Socket非同步事件引數 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs(); //將訊息內容轉化為傳送的byte[]格式 byte[] buffer = Encoding.UTF8.GetBytes(Message.Text); //將傳送內容的資訊存放進Socket非同步事件引數中 socketEventArg.SetBuffer(buffer, 0, buffer.Length); //註冊Socket完成事件 socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(SocketAsyncEventArgs_Completed); //設定Socket非同步事件引數的Socket遠端終結點 socketEventArg.RemoteEndPoint = hostEntry; //將定義好的Socket物件賦值給Socket非同步事件引數的執行例項屬性 socketEventArg.UserToken = sock; try { //執行Socket sock.ConnectAsync(socketEventArg); } catch (SocketException ex) { throw new SocketException((int)ex.ErrorCode); } } private void SocketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e) { // 檢查是否傳送出錯 if (e.SocketError != SocketError.Success) { if (e.SocketError == SocketError.ConnectionAborted) { Dispatcher.BeginInvoke(() => MessageBox.Show("連線超時請重試! " + e.SocketError)); } else if (e.SocketError == SocketError.ConnectionRefused) { Dispatcher.BeginInvoke(() => MessageBox.Show("伺服器端問啟動" + e.SocketError)); } else { Dispatcher.BeginInvoke(() => MessageBox.Show("出錯了" + e.SocketError)); } //關閉連線清理資源 if (e.UserToken != null) { Socket sock = e.UserToken as Socket; sock.Shutdown(SocketShutdown.Both); sock.Close(); } return; } //檢查Socket的當前最後的一個操作 switch (e.LastOperation) { //如果最後的一個操作是連線,那麼下一步處理就是傳送訊息。 case SocketAsyncOperation.Connect: if (e.UserToken != null) { //獲取執行中的Socket物件 Socket sock = e.UserToken as Socket; //開始傳送 bool completesAsynchronously = sock.SendAsync(e); //檢查socket傳送是否被掛起,如果被掛起將繼續進行處理 if (!completesAsynchronously) { SocketAsyncEventArgs_Completed(e.UserToken, e); } }; break; //如果最後的一個操作是傳送,那麼顯示剛才傳送成功的訊息,然後開始下一步處理就是接收訊息。 case SocketAsyncOperation.Send: //將已成功傳送的訊息內容繫結到listBox1控制元件中 Dispatcher.BeginInvoke(() => { listBox1.Items.Add("客戶端" + DateTime.Now.ToShortTimeString() + "傳送的訊息 :" + Message.Text); } ); if (e.UserToken != null) { //獲取執行中的Socket物件 Socket sock = e.UserToken as Socket; //開始接收伺服器端的訊息 bool completesAsynchronously = sock.ReceiveAsync(e); //檢查socket傳送是否被掛起,如果被掛起將繼續進行處理 if (!completesAsynchronously) { SocketAsyncEventArgs_Completed(e.UserToken, e); } } break; //如果是最後的一個操作時接收,那麼顯示接收到的訊息內容,並清理資源。 case SocketAsyncOperation.Receive: if (e.UserToken != null) { //獲取接收到的訊息,並轉化為字串 string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred); //獲取執行中的Socket物件 Socket sock = e.UserToken as Socket; //將接收到的訊息內容繫結到listBox1控制元件中 Dispatcher.BeginInvoke(() => { listBox1.Items.Add("伺服器端" + DateTime.Now.ToShortTimeString() + "傳過來的訊息:" + dataFromServer); }); } break; } } }}
(2) Socket伺服器端的實現,使用Windows的控制檯程式。
using System;using System.Linq;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;namespace SocketServer{ static class Program { private static AutoResetEvent _flipFlop = new AutoResetEvent(false); static void Main(string[] args) { //建立socket,使用的是TCP協議,如果用UDP協議,則要用SocketType.Dgram型別的Socket Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //建立終結點EndPoint 取當前主機的ip IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); //把ip和埠轉化為IPEndpoint例項,埠號取8888 IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList.First(), 8888); Console.WriteLine("本地的IP地址和埠是 : {0}", localEP); try { //繫結EndPoint對像(8888埠和ip地址) listener.Bind(localEP); //開始監聽 listener.Listen(10); //一直迴圈接收客戶端的訊息 while (true) { Console.WriteLine("等待Windows Phone客戶端的連線..."); //開始接收下一個連線 listener.BeginAccept(AcceptCallback, listener); //開始執行緒等待 _flipFlop.WaitOne(); } } catch (Exception e) { Console.WriteLine(e.ToString()); } } /// <summary> /// 接收返回事件處理 /// </summary> /// <param name="ar"></param> private static void AcceptCallback(IAsyncResult ar) { Socket listener = (Socket)ar.AsyncState; Socket socket = listener.EndAccept(ar); Console.WriteLine("連線到Windows Phone客戶端。"); _flipFlop.Set(); //開始接收,傳遞StateObject物件過去 var state = new StateObject(); state.Socket = socket; socket.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, ReceiveCallback, state); } private static void ReceiveCallback(IAsyncResult ar) { StateObject state = (StateObject)ar.AsyncState; Socket socket = state.Socket; // 讀取客戶端socket傳送過來的資料 int read = socket.EndReceive(ar); // 如果成功讀取了客戶端socket傳送過來的資料 if (read > 0) { //獲取客戶端的訊息,轉化為字串格式 string chunk = Encoding.UTF8.GetString(state.Buffer, 0, read); state.StringBuilder.Append(chunk); if (state.StringBuilder.Length > 0) { string result = state.StringBuilder.ToString(); Console.WriteLine("收到客戶端傳過來的訊息: {0}", result); //傳送資料資訊給客戶端 Send(socket, result); } } } /// <summary> /// 返回客戶端資料 /// </summary> /// <param name="handler"></param> /// <param name="data"></param> private static void Send(Socket handler, String data) { //將訊息內容轉化為傳送的byte[]格式 byte[] byteData = Encoding.UTF8.GetBytes(data); //傳送訊息到Windows Phone客戶端 handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler); } private static void SendCallback(IAsyncResult ar) { try { Socket handler = (Socket)ar.AsyncState; // 完成傳送訊息到Windows Phone客戶端 int bytesSent = handler.EndSend(ar); if (bytesSent > 0) { Console.WriteLine("傳送成功!"); } } catch (Exception e) { Console.WriteLine(e.ToString()); } } } public class StateObject { public Socket Socket; public StringBuilder StringBuilder = new StringBuilder(); public const int BufferSize = 10; public byte[] Buffer = new byte[BufferSize]; public int TotalSize; }}
ok了