Silverlight下的Socket通訊

在Silverlight中進行通訊,只能使用4502-4534之間的端口進行數據傳輸,另外Silverlight客戶端會自動向943端口的服務器端發送一個“<policy-file-request/>”的語句請求,然後服務器端943端口回發以下文件以許可Socket通訊。

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from>
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <socket-resource port="4502-4534" protocol="tcp"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

  A.現在我們首先來看服務器端的代碼,主要分爲策略響應步驟和服務響應步驟。

  策略步驟一:啓動監聽943端口是否有需要安全策略文件請求

  策略步驟二:如果客戶端請求是<policy-file-request/>,則將安全策略文件作爲bytes發送給客戶端

  服務步驟一:啓動服務器端,監聽4525端口,是否有Socket對話請求

  服務步驟二:如果有客戶端請求的連接,則發送消息告知客戶端

  代碼如下:

    class Program
    {
        static void Main(string[] args)
        {
            //策略步驟一:啓動監聽943端口是否有需要安全策略文件請求
            Thread access = new Thread(new ThreadStart(accessThread));
            access.Start();

            //服務步驟一:啓動服務器端,監聽4525端口,是否有Socket對話請求
            Thread server = new Thread(new ThreadStart(ServerThread));
            server.Start();
        }
        //策略請求監聽
        static void accessThread()
        {
            //獲取943端口監聽的Socket服務端
            Socket socket = GetSocketServer(943);
            while (true)
            {
                Socket new_access = socket.Accept();
                string clientPolicyString = "<policy-file-request/>";
                byte[] requestbytes = new byte[clientPolicyString.Length];
                new_access.Receive(requestbytes);
                string requeststring = System.Text.Encoding.UTF8.GetString(requestbytes, 0, requestbytes.Length);

                if (requeststring == clientPolicyString)
                {
                    //策略步驟二:如果客戶端請求是<policy-file-request/>,則將安全策略文件作爲bytes發送給客戶端
                    byte[] accessbytes = GetPolicyToClient();
                    new_access.Send(accessbytes, accessbytes.Length, SocketFlags.None);
                    new_access.Close();
                }
                Thread.Sleep(100);
            }
        }

        static void ServerThread()
        {
            //獲取4525端口監聽的Socket服務端
            Socket socket = GetSocketServer(4525);
            while (true)
            {
                Socket _socket = socket.Accept();
                //服務步驟二:如果有客戶端請求的連接,則發送消息告知客戶端
                byte[] b2 = new byte[1024];
                _socket.Receive(b2);
                Console.WriteLine(Encoding.UTF8.GetString(b2).Replace("\0", ""));
                string recString = "我已經收到消息了";
                _socket.Send(Encoding.UTF8.GetBytes(recString));
                _socket.Close();
                Thread.Sleep(100);
            }
        }
        //根據端口建立Socket服務器端
        static Socket GetSocketServer(int serverPort)
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(new IPEndPoint(IPAddress.Any, serverPort));
            socket.Listen(40);
            return socket;
        }
        //獲取安全策略文件的byte[]
        static byte[] GetPolicyToClient()
        {
            string path = Environment.CurrentDirectory.Replace("\\bin\\Debug","");
            FileStream fs = new FileStream(path+ @"\clientaccesspolicy.xml", FileMode.Open);
            int length = (int)fs.Length;
            byte[] bytes = new byte[length];
            fs.Read(bytes, 0, length);
            fs.Close();
            return bytes;
        }

    }

  B.其次我們來看客戶端操作,分爲以下幾個步驟:

  客戶端步驟一:發起服務器連接請求。

  客戶端步驟二:連接服務器成功,將需要發送的數據放入緩衝區中,然後異步向服務器發送消息請求

  客戶端步驟三:消息發送成功,此時設置一個新的緩衝區實例,並且發起異步接收服務器返回的消息

  客戶端步驟四:獲取到服務器返回的消息,關閉Socket 

  客戶端cs代碼如下:

    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
        System.Net.Sockets.Socket socket;

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            byte[] userbytes = Encoding.UTF8.GetBytes(this.tbInput.Text);
            socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs();
            socketArgs.RemoteEndPoint = new DnsEndPoint("127.0.0.1", 4525);
            //將需要發送的內容轉爲byte[],保存到UserToken屬性中
            socketArgs.UserToken = userbytes;
            socketArgs.Completed += new EventHandler<SocketAsyncEventArgs>(socketArgs_Completed);
            //客戶端步驟一:發起服務器連接請求。
            socket.ConnectAsync(socketArgs);
        }
        //每發生一個Socket操作都講激活此方法,操作包括(Connect/Send/Receive/None)
        void socketArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.LastOperation == SocketAsyncOperation.Connect)
            {
                //客戶端步驟二:連接服務器成功,將需要發送的數據放入緩衝區中,然後異步向服務器發送消息請求
                byte[] userbytes = (byte[])e.UserToken;
                e.SetBuffer(userbytes, 0, userbytes.Length);
                socket.SendAsync(e);
            }
            else if (e.LastOperation == SocketAsyncOperation.Send)
            {
                //客戶端步驟三:消息發送成功,此時設置一個新的緩衝區實例,並且發起異步接收服務器返回的消息
                byte[] userbytes = new byte[1024];
                e.SetBuffer(userbytes, 0, userbytes.Length);
                socket.ReceiveAsync(e);
            }
            else if (e.LastOperation == SocketAsyncOperation.Receive)
            {
                //客戶端步驟四:獲取到服務器返回的消息,關閉Socket
                string RecevieStr = Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length).Replace("\0", "");
                //因爲是異步Socket請求,所以需要使用UI線程更新lbShowMessage的顯示效果
                this.lbShowMessage.Dispatcher.BeginInvoke(new DoThingDele(DoThing), RecevieStr);
                socket.Close();
            }
        }
        //更新UI
        public void DoThing(string arg)
        {
            this.lbShowMessage.Content = this.lbShowMessage.Content + "->" + arg;
        }
        //聲明的一個DoThing方法委託
        public delegate void DoThingDele(string arg);
    }

  客戶端Xaml前臺代碼如下:

    <Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
        <TextBox Height="23" HorizontalAlignment="Left" Margin="20,20,0,0" 
                 Name="tbInput" VerticalAlignment="Top" Width="243" />
        <Button Content="發 送" Height="23" HorizontalAlignment="Left" 
                Margin="279,20,0,0" Name="button1" VerticalAlignment="Top" 
                Width="75" Click="button1_Click" />
        <sdk:Label Height="28" HorizontalAlignment="Left" Margin="20,57,0,0"
                   Name="lbShowMessage" VerticalAlignment="Top" Width="358" />
    </Grid>

  最後效果如下,如需源碼請點擊 SLSocket.zip 下載,本文演示的是最簡單通訊效果:

 

發佈了166 篇原創文章 · 獲贊 7 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章