天天看點

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異步事件參數的運作執行個體屬性  

            socksocketEventArg.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("出錯了"  

                //關閉連接配接清理資源  

                if (e.UserToken != null)  

                    Socket sock = e.UserToken as Socket;  

                    sock.Shutdown(SocketShutdown.Both);  

                    sock.Close();  

            //檢查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);  

                        );  

                        //開始接收伺服器端的消息  

                        bool completesAsynchronously = sock.ReceiveAsync(e);   

                    }  

                //如果是最後的一個操作時接收,那麼顯示接收到的消息内容,并清理資源。  

                case SocketAsyncOperation.Receive:  

                        //擷取接收到的消息,并轉化為字元串  

                        string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);  

                        //将接收到的消息内容綁定到listBox1控件中  

                        Dispatcher.BeginInvoke(() => 

                            listBox1.Items.Add("伺服器端" + DateTime.Now.ToShortTimeString() + "傳過來的消息:" + dataFromServer);  

                        });  

                    break;   

    }  

(2) Socket伺服器端的實作,使用Windows的控制台程式。

using System.Linq;  

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);  

                //綁定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,  

,  

                StateObject.BufferSize,  

                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);  

        /// 傳回用戶端資料  

        /// <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)  

                Socket handler = (Socket)ar.AsyncState;  

                // 完成發送消息到Windows Phone用戶端  

                int bytesSent = handler.EndSend(ar);  

                if (bytesSent > 0)  

                    Console.WriteLine("發送成功!");  

    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;  

本文轉自linzheng 51CTO部落格,原文連結:http://blog.51cto.com/linzheng/1078573

繼續閱讀