且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Silverlight实用窍门系列:67.Silverlight下的Socket通讯

更新时间:2022-10-05 07:44:45

<p>  在Silverlight中进行通讯,只能使用4502-4534之间的端口进行数据传输,另外Silverlight客户端会自动向943端口的服务器端发送一个&ldquo;&lt;policy-file-request/&gt;&rdquo;的语句请求,然后服务器端943端口回发以下文件以许可Socket通讯。</p>
<div class="cnblogs_code">
<pre>&lt;?xml version=<span style="color: #800000;">"</span><span style="color: #800000;">1.0</span><span style="color: #800000;">"</span> encoding=<span style="color: #800000;">"</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">"</span> ?&gt;
&lt;access-policy&gt;
  &lt;cross-domain-access&gt;
    &lt;policy&gt;
      &lt;allow-<span style="color: #0000ff;">from</span>&gt;
        &lt;domain uri=<span style="color: #800000;">"</span><span style="color: #800000;">*</span><span style="color: #800000;">"</span>/&gt;
      &lt;/allow-<span style="color: #0000ff;">from</span>&gt;
      &lt;grant-to&gt;
        &lt;socket-resource port=<span style="color: #800000;">"</span><span style="color: #800000;">4502-4534</span><span style="color: #800000;">"</span> protocol=<span style="color: #800000;">"</span><span style="color: #800000;">tcp</span><span style="color: #800000;">"</span>/&gt;
      &lt;/grant-to&gt;
    &lt;/policy&gt;
  &lt;/cross-domain-access&gt;
&lt;/access-policy&gt;</pre>
</div>
<p>  A.现在我们首先来看服务器端的代码,主要分为策略响应步骤和服务响应步骤。</p>
<p>  <strong>策略步骤一</strong>:启动监听943端口是否有需要安全策略文件请求</p>
<p>  <strong>策略步骤二</strong>:如果客户端请求是&lt;policy-file-request/&gt;,则将安全策略文件作为bytes发送给客户端</p>
<p>  <strong>服务步骤一</strong>:启动服务器端,监听4525端口,是否有Socket对话请求</p>
<p>  <strong>服务步骤二</strong>:如果有客户端请求的连接,则发送消息告知客户端</p>
<p>  代码如下:</p>
<div class="cnblogs_code">
<pre>    <span style="color: #0000ff;">class</span><span style="color: #000000;"> Program
    {
        </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Main(<span style="color: #0000ff;">string</span><span style="color: #000000;">[] args)
        {
            </span><span style="color: #008000;">//</span><span style="color: #008000;">策略步骤一:启动监听943端口是否有需要安全策略文件请求</span>
            Thread access = <span style="color: #0000ff;">new</span> Thread(<span style="color: #0000ff;">new</span><span style="color: #000000;"> ThreadStart(accessThread));
            access.Start();

            </span><span style="color: #008000;">//</span><span style="color: #008000;">服务步骤一:启动服务器端,监听4525端口,是否有Socket对话请求</span>
            Thread server = <span style="color: #0000ff;">new</span> Thread(<span style="color: #0000ff;">new</span><span style="color: #000000;"> ThreadStart(ServerThread));
            server.Start();
        }
        </span><span style="color: #008000;">//</span><span style="color: #008000;">策略请求监听</span>
        <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> accessThread()
        {
            </span><span style="color: #008000;">//</span><span style="color: #008000;">获取943端口监听的Socket服务端</span>
            Socket socket = GetSocketServer(<span style="color: #800080;">943</span><span style="color: #000000;">);
            </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">)
            {
                Socket new_access </span>=<span style="color: #000000;"> socket.Accept();
                </span><span style="color: #0000ff;">string</span> clientPolicyString = <span style="color: #800000;">"</span><span style="color: #800000;">&lt;policy-file-request/&gt;</span><span style="color: #800000;">"</span><span style="color: #000000;">;
                </span><span style="color: #0000ff;">byte</span>[] requestbytes = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span><span style="color: #000000;">[clientPolicyString.Length];
                new_access.Receive(requestbytes);
                </span><span style="color: #0000ff;">string</span> requeststring = System.Text.Encoding.UTF8.GetString(requestbytes, <span style="color: #800080;">0</span><span style="color: #000000;">, requestbytes.Length);

                </span><span style="color: #0000ff;">if</span> (requeststring ==<span style="color: #000000;"> clientPolicyString)
                {
                    </span><span style="color: #008000;">//</span><span style="color: #008000;">策略步骤二:如果客户端请求是&lt;policy-file-request/&gt;,则将安全策略文件作为bytes发送给客户端</span>
                    <span style="color: #0000ff;">byte</span>[] accessbytes =<span style="color: #000000;"> GetPolicyToClient();
                    new_access.Send(accessbytes, accessbytes.Length, SocketFlags.None);
                    new_access.Close();
                }
                Thread.Sleep(</span><span style="color: #800080;">100</span><span style="color: #000000;">);
            }
        }

        </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> ServerThread()
        {
            </span><span style="color: #008000;">//</span><span style="color: #008000;">获取4525端口监听的Socket服务端</span>
            Socket socket = GetSocketServer(<span style="color: #800080;">4525</span><span style="color: #000000;">);
            </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">)
            {
                Socket _socket </span>=<span style="color: #000000;"> socket.Accept();
                </span><span style="color: #008000;">//</span><span style="color: #008000;">服务步骤二:如果有客户端请求的连接,则发送消息告知客户端</span>
                <span style="color: #0000ff;">byte</span>[] b2 = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span>[<span style="color: #800080;">1024</span><span style="color: #000000;">];
                _socket.Receive(b2);
                Console.WriteLine(Encoding.UTF8.GetString(b2).Replace(</span><span style="color: #800000;">"</span><span style="color: #800000;">\0</span><span style="color: #800000;">"</span>, <span style="color: #800000;">""</span><span style="color: #000000;">));
                </span><span style="color: #0000ff;">string</span> recString = <span style="color: #800000;">"</span><span style="color: #800000;">我已经收到消息了</span><span style="color: #800000;">"</span><span style="color: #000000;">;
                _socket.Send(Encoding.UTF8.GetBytes(recString));
                _socket.Close();
                Thread.Sleep(</span><span style="color: #800080;">100</span><span style="color: #000000;">);
            }
        }
        </span><span style="color: #008000;">//</span><span style="color: #008000;">根据端口建立Socket服务器端</span>
        <span style="color: #0000ff;">static</span> Socket GetSocketServer(<span style="color: #0000ff;">int</span><span style="color: #000000;"> serverPort)
        {
            Socket socket </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IPEndPoint(IPAddress.Any, serverPort));
            socket.Listen(</span><span style="color: #800080;">40</span><span style="color: #000000;">);
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> socket;
        }
        </span><span style="color: #008000;">//</span><span style="color: #008000;">获取安全策略文件的byte[]</span>
        <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">byte</span><span style="color: #000000;">[] GetPolicyToClient()
        {
            </span><span style="color: #0000ff;">string</span> path = Environment.CurrentDirectory.Replace(<span style="color: #800000;">"</span><span style="color: #800000;">\\bin\\Debug</span><span style="color: #800000;">"</span>,<span style="color: #800000;">""</span><span style="color: #000000;">);
            FileStream fs </span>= <span style="color: #0000ff;">new</span> FileStream(path+ <span style="color: #800000;">@"</span><span style="color: #800000;">\clientaccesspolicy.xml</span><span style="color: #800000;">"</span><span style="color: #000000;">, FileMode.Open);
            </span><span style="color: #0000ff;">int</span> length = (<span style="color: #0000ff;">int</span><span style="color: #000000;">)fs.Length;
            </span><span style="color: #0000ff;">byte</span>[] bytes = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span><span style="color: #000000;">[length];
            fs.Read(bytes, </span><span style="color: #800080;">0</span><span style="color: #000000;">, length);
            fs.Close();
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> bytes;
        }

    }</span></pre>
</div>
<p>  B.其次我们来看客户端操作,分为以下几个步骤:</p>
<p>  <strong>客户端步骤一</strong>:发起服务器连接请求。</p>
<p>  <strong>客户端步骤二</strong>:连接服务器成功,将需要发送的数据放入缓冲区中,然后异步向服务器发送消息请求</p>
<p>  <strong>客户端步骤三</strong>:消息发送成功,此时设置一个新的缓冲区实例,并且发起异步接收服务器返回的消息</p>
<p>  <strong>客户端步骤四</strong>:获取到服务器返回的消息,关闭Socket </p>
<p>  客户端cs代码如下:</p>
<div class="cnblogs_code">
<pre>    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">partial</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> MainPage : UserControl
    {
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> MainPage()
        {
            InitializeComponent();
        }
        System.Net.Sockets.Socket socket;

        </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span><span style="color: #000000;"> sender, RoutedEventArgs e)
        {
            </span><span style="color: #0000ff;">byte</span>[] userbytes = Encoding.UTF8.GetBytes(<span style="color: #0000ff;">this</span><span style="color: #000000;">.tbInput.Text);
            socket </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SocketAsyncEventArgs socketArgs </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> SocketAsyncEventArgs();
            socketArgs.RemoteEndPoint </span>= <span style="color: #0000ff;">new</span> DnsEndPoint(<span style="color: #800000;">"</span><span style="color: #800000;">127.0.0.1</span><span style="color: #800000;">"</span>, <span style="color: #800080;">4525</span><span style="color: #000000;">);
            </span><span style="color: #008000;">//</span><span style="color: #008000;">将需要发送的内容转为byte[],保存到UserToken属性中</span>
            socketArgs.UserToken =<span style="color: #000000;"> userbytes;
            socketArgs.Completed </span>+= <span style="color: #0000ff;">new</span> EventHandler&lt;SocketAsyncEventArgs&gt;<span style="color: #000000;">(socketArgs_Completed);
            </span><span style="color: #008000;">//</span><span style="color: #008000;">客户端步骤一:发起服务器连接请求。</span>
<span style="color: #000000;">            socket.ConnectAsync(socketArgs);
        }
        </span><span style="color: #008000;">//</span><span style="color: #008000;">每发生一个Socket操作都讲激活此方法,操作包括(Connect/Send/Receive/None)</span>
        <span style="color: #0000ff;">void</span> socketArgs_Completed(<span style="color: #0000ff;">object</span><span style="color: #000000;"> sender, SocketAsyncEventArgs e)
        {
            </span><span style="color: #0000ff;">if</span> (e.LastOperation ==<span style="color: #000000;"> SocketAsyncOperation.Connect)
            {
                </span><span style="color: #008000;">//</span><span style="color: #008000;">客户端步骤二:连接服务器成功,将需要发送的数据放入缓冲区中,然后异步向服务器发送消息请求</span>
                <span style="color: #0000ff;">byte</span>[] userbytes = (<span style="color: #0000ff;">byte</span><span style="color: #000000;">[])e.UserToken;
                e.SetBuffer(userbytes, </span><span style="color: #800080;">0</span><span style="color: #000000;">, userbytes.Length);
                socket.SendAsync(e);
            }
            </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (e.LastOperation ==<span style="color: #000000;"> SocketAsyncOperation.Send)
            {
                </span><span style="color: #008000;">//</span><span style="color: #008000;">客户端步骤三:消息发送成功,此时设置一个新的缓冲区实例,并且发起异步接收服务器返回的消息</span>
                <span style="color: #0000ff;">byte</span>[] userbytes = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span>[<span style="color: #800080;">1024</span><span style="color: #000000;">];
                e.SetBuffer(userbytes, </span><span style="color: #800080;">0</span><span style="color: #000000;">, userbytes.Length);
                socket.ReceiveAsync(e);
            }
            </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (e.LastOperation ==<span style="color: #000000;"> SocketAsyncOperation.Receive)
            {
                </span><span style="color: #008000;">//</span><span style="color: #008000;">客户端步骤四:获取到服务器返回的消息,关闭Socket</span>
                <span style="color: #0000ff;">string</span> RecevieStr = Encoding.UTF8.GetString(e.Buffer, <span style="color: #800080;">0</span>, e.Buffer.Length).Replace(<span style="color: #800000;">"</span><span style="color: #800000;">\0</span><span style="color: #800000;">"</span>, <span style="color: #800000;">""</span><span style="color: #000000;">);
                </span><span style="color: #008000;">//</span><span style="color: #008000;">因为是异步Socket请求,所以需要使用UI线程更新lbShowMessage的显示效果</span>
                <span style="color: #0000ff;">this</span>.lbShowMessage.Dispatcher.BeginInvoke(<span style="color: #0000ff;">new</span><span style="color: #000000;"> DoThingDele(DoThing), RecevieStr);
                socket.Close();
            }
        }
        </span><span style="color: #008000;">//</span><span style="color: #008000;">更新UI</span>
        <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> DoThing(<span style="color: #0000ff;">string</span><span style="color: #000000;"> arg)
        {
            </span><span style="color: #0000ff;">this</span>.lbShowMessage.Content = <span style="color: #0000ff;">this</span>.lbShowMessage.Content + <span style="color: #800000;">"</span><span style="color: #800000;">-&gt;</span><span style="color: #800000;">"</span> +<span style="color: #000000;"> arg;
        }
        </span><span style="color: #008000;">//</span><span style="color: #008000;">声明的一个DoThing方法委托</span>
        <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">delegate</span> <span style="color: #0000ff;">void</span> DoThingDele(<span style="color: #0000ff;">string</span><span style="color: #000000;"> arg);
    }</span></pre>
</div>
<p>  客户端Xaml前台代码如下:</p>
<div class="cnblogs_code">
<pre>    &lt;Grid x:Name=<span style="color: #800000;">"</span><span style="color: #800000;">LayoutRoot</span><span style="color: #800000;">"</span> Background=<span style="color: #800000;">"</span><span style="color: #800000;">White</span><span style="color: #800000;">"</span> ShowGridLines=<span style="color: #800000;">"</span><span style="color: #800000;">True</span><span style="color: #800000;">"</span>&gt;
        &lt;TextBox Height=<span style="color: #800000;">"</span><span style="color: #800000;">23</span><span style="color: #800000;">"</span> HorizontalAlignment=<span style="color: #800000;">"</span><span style="color: #800000;">Left</span><span style="color: #800000;">"</span> Margin=<span style="color: #800000;">"</span><span style="color: #800000;">20,20,0,0</span><span style="color: #800000;">"</span><span style="color: #000000;"> 
                 Name</span>=<span style="color: #800000;">"</span><span style="color: #800000;">tbInput</span><span style="color: #800000;">"</span> VerticalAlignment=<span style="color: #800000;">"</span><span style="color: #800000;">Top</span><span style="color: #800000;">"</span> Width=<span style="color: #800000;">"</span><span style="color: #800000;">243</span><span style="color: #800000;">"</span> /&gt;
        &lt;Button Content=<span style="color: #800000;">"</span><span style="color: #800000;">发 送</span><span style="color: #800000;">"</span> Height=<span style="color: #800000;">"</span><span style="color: #800000;">23</span><span style="color: #800000;">"</span> HorizontalAlignment=<span style="color: #800000;">"</span><span style="color: #800000;">Left</span><span style="color: #800000;">"</span><span style="color: #000000;"> 
                Margin</span>=<span style="color: #800000;">"</span><span style="color: #800000;">279,20,0,0</span><span style="color: #800000;">"</span> Name=<span style="color: #800000;">"</span><span style="color: #800000;">button1</span><span style="color: #800000;">"</span> VerticalAlignment=<span style="color: #800000;">"</span><span style="color: #800000;">Top</span><span style="color: #800000;">"</span><span style="color: #000000;"> 
                Width</span>=<span style="color: #800000;">"</span><span style="color: #800000;">75</span><span style="color: #800000;">"</span> Click=<span style="color: #800000;">"</span><span style="color: #800000;">button1_Click</span><span style="color: #800000;">"</span> /&gt;
        &lt;sdk:Label Height=<span style="color: #800000;">"</span><span style="color: #800000;">28</span><span style="color: #800000;">"</span> HorizontalAlignment=<span style="color: #800000;">"</span><span style="color: #800000;">Left</span><span style="color: #800000;">"</span> Margin=<span style="color: #800000;">"</span><span style="color: #800000;">20,57,0,0</span><span style="color: #800000;">"</span><span style="color: #000000;">
                   Name</span>=<span style="color: #800000;">"</span><span style="color: #800000;">lbShowMessage</span><span style="color: #800000;">"</span> VerticalAlignment=<span style="color: #800000;">"</span><span style="color: #800000;">Top</span><span style="color: #800000;">"</span> Width=<span style="color: #800000;">"</span><span style="color: #800000;">358</span><span style="color: #800000;">"</span> /&gt;
    &lt;/Grid&gt;</pre>
</div>
<p>  最后效果如下,如需源码请点击 <a href="http://files.cnblogs.com/chengxingliang/SLSocket.zip">SLSocket.zip</a> 下载,本文演示的是最简单通讯效果:</p>
<p><img src="http://pic002.cnblogs.com/images/2012/140041/2012052317265429.png" alt="" /></p>
<p>&nbsp;</p>
<p><img src="http://pic002.cnblogs.com/images/2012/140041/2012052317263654.png" alt="" /></p>



本文转自程兴亮 51CTO博客,原文链接:http://blog.51cto.com/chengxingliang/875576