1. 程式人生 > 實用技巧 >Windows Phone 7 網路程式設計之使用Socket

Windows Phone 7 網路程式設計之使用Socket

芒果更新的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了