none
求助高人帮我解释一下这句话 RRS feed

  • 问题

  • 每一个请求到服务器端的新的Socket连接会话Silverlight都会先悄悄的用另一个Socket去请求策略文件,这是很多刚接触Silverlight Socket的人感到郁闷的地方,请求策略时,Silverlight会自己发送一个字符串<policy-file-request/>到服务器的943端口,然后你必须在服务器程序里接收该请求,分析是否是策略请求后,发送一个策略文件的字符串给客户端,客户端接收到策略文件后自己分析完后再发送程序员自己写的数据请求。


    红色部分说的 在服务器端接收客户端发来请求是否是策略 这个策略是什么啊 或者这个请求是什么啊 在客户端代码中没有发送给服务器端策略的地方啊~  我是这么理解的:是不是要下载一份那个记录着端口号的.xml文件到本地 然后不管放在哪里sl会自动的找到这个.xml然后发送给服务器端啊
    2010年4月17日 0:39

答案

  •  

    策略文件就是:clientaccesspolicy.xml

    格式如下:

    <?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>

    发送的代码如下:

    class Program
      {
    
        static void Main(string[] args)
        {
    
          Console.WriteLine("================Socket服务开启======================");
          //建立一个子线程,用于创建Socket来监听策略请求和发送。
          ThreadStart pcts = new ThreadStart(PolicyThread);
          Thread policythread = new Thread(pcts);
          policythread.Start();
          //建立一个子线程,用于创建Socket来监听信息请求和发送。
          ThreadStart infots = new ThreadStart(InfoThread);
          Thread infothread = new Thread(infots);
          infothread.Start();
    
        }
    
    
    
        //监听策略请求和发送策略请求方法
    
        static void PolicyThread()
        {
          //创建一个Socket用来监听943(固定的)端口的策略请求    
          Socket policy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          policy.Bind(new IPEndPoint(IPAddress.Any, 943));
          policy.Listen(10);
          //无限循环监听
          
          while (true)
          {
            if (policy.Blocking)//如果Socket是阻止模式的(这个东西实际上可以用不)
            {
              //创建Socket,用来获取监听Socket的第一个Socket链接
    
              Socket _policy = policy.Accept();
              //定义一个字符串,该字符串与Silverlight发送过来的请求字符串一样。
              string policyRequestString = "<policy-file-request/>";
              //定义一个字节数组
              byte[] b = new byte[policyRequestString.Length];
    
              //将客户端发送过来,服务器接收到的字节数组存入b中
              _policy.Receive(b);
              //将接收到的字节数组转换成字符串
              string requeststring = System.Text.Encoding.UTF8.GetString(b, 0, b.Length);
              //显示客户端发送的字符串
    
              Console.WriteLine(requeststring);
              //比对客户端发送过来的字符串是否和之前定义的额定好的策略请求字符串相同,如果相同,说明该请求是一个策略请求。
    
              if (requeststring == policyRequestString)
              {
                //如果客户端发送的是一个策略请求,服务器发送策略文件到客户端
                SendPolicy(_policy);
                Console.WriteLine("Policy File have sended");
                //关闭当前连接Socket
    
                //_policy.Close();
    
              }
    
              else// 否则,显示错误
              {
    
                Console.WriteLine("not a sure request string!");
    
              }
            }
          }
        }
    
    
    
        //监听信息请求和发送信息方法
    
        static void InfoThread()
        {
    
          //创建一个Socket用于监听4502端口,获取接收客户端发送过来的信息
    
          Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
          socket.Bind(new IPEndPoint(IPAddress.Any, 4502));
    
          socket.Listen(10);
    
          //无线循环监听
          // Socket _socket = null;
          while (true)
          {
            ////创建Socket,用来获取监听Socket的第一个Socket链接
            //Socket _socket = socket.Accept();
            //创建Socket,用来获取监听Socket的第一个Socket链接
            Socket _socket = socket.Accept();
            //创建一个空字节数组
    
            byte[] b2 = new byte[1024];
            //将接受到的字节数组存入到之前定义的b2字节数组中。
    
            _socket.Receive(b2);
            //显示接收到的信息
    
            Console.WriteLine(Encoding.UTF8.GetString(b2));
            //发回一个信息给客户端,该信息是字节数组,所以我们将信息字符串转换成字节数组
    
            _socket.Send(Encoding.UTF8.GetBytes("This Send Over!!"));
    
    
            //关闭当前Socket连接
            // _socket.Close();
            
            
    
          }
          
        }
    
    
    
    
    
        //发送策略文件的方法
    
        //参数是传递进来的Socket连接
    
        static void SendPolicy(Socket socket)
        {
    
          //创建一个文件流,该文件留指定代开一个策略文件,至于策略文件的格式,MS的Silverlight有详细说明和配置方法
    
          FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + @"\clientaccesspolicy.xml", FileMode.Open);
          int length = (int)fs.Length;
    
          byte[] bytes = new byte[length];
    
          //将策略文件流读到上面定义的字节数组中
    
          fs.Read(bytes, 0, length);
          //关闭文件流
    
          fs.Close();
    
    
    
          //其策略文件的字节数组发送给客户端
    
          socket.Send(bytes, length, SocketFlags.None);
    
        }
    
    
    
      }// end for class

    接收代码如下:

    public partial class Page : UserControl
      {
        public Page()
        {
          InitializeComponent();
        }
        //定义一个可在全局使用的Socket
        Socket socket;
        //定义一个同步上下文类,用来将子线程的操作调度到主线程上以可控制UI属性。
        SynchronizationContext syn;
        //发送信息按钮的单击事件
        void OnSend(object sender, EventArgs args)
        {
          //定义一个字节数组,并将文本框的的类容转换为字节数组后存入
          byte[] bytes = Encoding.UTF8.GetBytes(txtToSend.Text);
          //显示信息,可不要。
          txtToSend.Text += "\r\nDnsSafeHost:" + Application.Current.Host.Source.DnsSafeHost;
          //将同步上下文设置在当前上下文(线程,主线程,可控制UI的)
          syn = SynchronizationContext.Current;
          //为socket创建示例,并设置相关属性。
          socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          //定义并实例一个Socket参数
          SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs();
          //设置到远程终节点属性(4502端口,为什么是4502,MS的SL通信安全上有)
          socketArgs.RemoteEndPoint = new DnsEndPoint(Application.Current.Host.Source.DnsSafeHost, 4502);
    
    
    
          //设置好当Socket任何一个动作完成时的回调函数。
          socketArgs.Completed += new EventHandler<SocketAsyncEventArgs>(socketArgs_Completed);
          //Socket参数的用户标识,实际上就是一个可以传递的OBJECT参数。
          socketArgs.UserToken = bytes;
          //执行连接。
          socket.ConnectAsync(socketArgs);
        }
    
    
    
        void socketArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
    
          //当任何一个Socket动作完成,都回调该函数,然后对LastOperation进行判断后继续执行相应的部分
    
          switch (e.LastOperation)
          {
    
            case SocketAsyncOperation.Connect:
    
              ProcessConnect(e);
    
              break;
    
            case SocketAsyncOperation.Receive:
    
              ProcessReceive(e);
    
              break;
    
            case SocketAsyncOperation.Send:
    
              ProcessSend(e);
    
              break;
    
          }
    
        }
    
    
    
        //将数据放入buffer并进行异步发送
    
        void ProcessConnect(SocketAsyncEventArgs e)
        {
          //当连接成功后,获取Socket参数 e传递过来的用户标识(也就是本示例中用户输入的字符串转换的Byte字节数组)
          byte[] bytes = (byte[])e.UserToken;
          //设置Socket参数的缓冲区参数,将我们的字节数组设置为Socket的缓冲区。
          e.SetBuffer(bytes, 0, bytes.Length);
          //同步一下上下文,显示一下当前的状态信息。
          syn.Post(GetText, "States:" + e.SocketError.ToString() + "," + e.LastOperation.ToString());
          //发送数据
          socket.SendAsync(e);
        }
    
    
    
        //发送完成后,执行等待接收服务器发回的数据
    
        void ProcessSend(SocketAsyncEventArgs e)
        {
    
          //定义个空的字节数组,设置好其大小
    
          byte[] bytes = new byte[1024];
    
          //将前面定义字节数组设置成缓冲区
    
          e.SetBuffer(bytes, 0, bytes.Length);
    
          //执行异步接收
    
          socket.ReceiveAsync(e);
    
        }
    
    
    
        //当接收完成后
    
        void ProcessReceive(SocketAsyncEventArgs e)
        {
    
          //在执行好接收后,本地SOCKET的缓冲区就会被服务器发送的数据填充。
    
          //显示下信息,当然也是用同步上下文的方式,在显示信息的时候,就直接将缓冲区的字节数组转换成字符串。
    
          syn.Post(GetText, Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length) + " and Received");
    
          //关闭Socket连接
    
          socket.Close();
    
          //最后显示下,Socket关闭。
    
          syn.Post(GetText, "Socket Closed");
    
        }
    
        //同步上下文调用的方法。
    
        void GetText(object str)
        {
          txtToSend.Text += "\r\n" + str.ToString();
    
        }
    
        
    
      
    
    
      }
    如果还是不太清楚,可以在上班时间外加我的QQ. QQ:283440946.
    努力!完成了js解析器,还差一个svg插件,一个绘图程序,做好自己,呵呵~!
    2010年4月18日 7:55
    版主

全部回复

  • 这是属于安全上的限制,设计了通过安全策略配置来限制某些访问,是否允许或拒绝。这个是RIA技术都拥有和应该存在的一种特性或叫限制。Adobe的flash也存在着安全策略配置 。

     通常这种配置是在不同域中,如果是同一个域默认为是允许的。比如你在www.yousite.com中去访问一个www.othersite.com中提供的服务接口,这就存在跨域访问。

     


    BLOG:http://beniao.cnblogs.com MSN:beniao@live.cn
    2010年4月17日 13:36
  •  

    策略文件就是:clientaccesspolicy.xml

    格式如下:

    <?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>

    发送的代码如下:

    class Program
      {
    
        static void Main(string[] args)
        {
    
          Console.WriteLine("================Socket服务开启======================");
          //建立一个子线程,用于创建Socket来监听策略请求和发送。
          ThreadStart pcts = new ThreadStart(PolicyThread);
          Thread policythread = new Thread(pcts);
          policythread.Start();
          //建立一个子线程,用于创建Socket来监听信息请求和发送。
          ThreadStart infots = new ThreadStart(InfoThread);
          Thread infothread = new Thread(infots);
          infothread.Start();
    
        }
    
    
    
        //监听策略请求和发送策略请求方法
    
        static void PolicyThread()
        {
          //创建一个Socket用来监听943(固定的)端口的策略请求    
          Socket policy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          policy.Bind(new IPEndPoint(IPAddress.Any, 943));
          policy.Listen(10);
          //无限循环监听
          
          while (true)
          {
            if (policy.Blocking)//如果Socket是阻止模式的(这个东西实际上可以用不)
            {
              //创建Socket,用来获取监听Socket的第一个Socket链接
    
              Socket _policy = policy.Accept();
              //定义一个字符串,该字符串与Silverlight发送过来的请求字符串一样。
              string policyRequestString = "<policy-file-request/>";
              //定义一个字节数组
              byte[] b = new byte[policyRequestString.Length];
    
              //将客户端发送过来,服务器接收到的字节数组存入b中
              _policy.Receive(b);
              //将接收到的字节数组转换成字符串
              string requeststring = System.Text.Encoding.UTF8.GetString(b, 0, b.Length);
              //显示客户端发送的字符串
    
              Console.WriteLine(requeststring);
              //比对客户端发送过来的字符串是否和之前定义的额定好的策略请求字符串相同,如果相同,说明该请求是一个策略请求。
    
              if (requeststring == policyRequestString)
              {
                //如果客户端发送的是一个策略请求,服务器发送策略文件到客户端
                SendPolicy(_policy);
                Console.WriteLine("Policy File have sended");
                //关闭当前连接Socket
    
                //_policy.Close();
    
              }
    
              else// 否则,显示错误
              {
    
                Console.WriteLine("not a sure request string!");
    
              }
            }
          }
        }
    
    
    
        //监听信息请求和发送信息方法
    
        static void InfoThread()
        {
    
          //创建一个Socket用于监听4502端口,获取接收客户端发送过来的信息
    
          Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
          socket.Bind(new IPEndPoint(IPAddress.Any, 4502));
    
          socket.Listen(10);
    
          //无线循环监听
          // Socket _socket = null;
          while (true)
          {
            ////创建Socket,用来获取监听Socket的第一个Socket链接
            //Socket _socket = socket.Accept();
            //创建Socket,用来获取监听Socket的第一个Socket链接
            Socket _socket = socket.Accept();
            //创建一个空字节数组
    
            byte[] b2 = new byte[1024];
            //将接受到的字节数组存入到之前定义的b2字节数组中。
    
            _socket.Receive(b2);
            //显示接收到的信息
    
            Console.WriteLine(Encoding.UTF8.GetString(b2));
            //发回一个信息给客户端,该信息是字节数组,所以我们将信息字符串转换成字节数组
    
            _socket.Send(Encoding.UTF8.GetBytes("This Send Over!!"));
    
    
            //关闭当前Socket连接
            // _socket.Close();
            
            
    
          }
          
        }
    
    
    
    
    
        //发送策略文件的方法
    
        //参数是传递进来的Socket连接
    
        static void SendPolicy(Socket socket)
        {
    
          //创建一个文件流,该文件留指定代开一个策略文件,至于策略文件的格式,MS的Silverlight有详细说明和配置方法
    
          FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + @"\clientaccesspolicy.xml", FileMode.Open);
          int length = (int)fs.Length;
    
          byte[] bytes = new byte[length];
    
          //将策略文件流读到上面定义的字节数组中
    
          fs.Read(bytes, 0, length);
          //关闭文件流
    
          fs.Close();
    
    
    
          //其策略文件的字节数组发送给客户端
    
          socket.Send(bytes, length, SocketFlags.None);
    
        }
    
    
    
      }// end for class

    接收代码如下:

    public partial class Page : UserControl
      {
        public Page()
        {
          InitializeComponent();
        }
        //定义一个可在全局使用的Socket
        Socket socket;
        //定义一个同步上下文类,用来将子线程的操作调度到主线程上以可控制UI属性。
        SynchronizationContext syn;
        //发送信息按钮的单击事件
        void OnSend(object sender, EventArgs args)
        {
          //定义一个字节数组,并将文本框的的类容转换为字节数组后存入
          byte[] bytes = Encoding.UTF8.GetBytes(txtToSend.Text);
          //显示信息,可不要。
          txtToSend.Text += "\r\nDnsSafeHost:" + Application.Current.Host.Source.DnsSafeHost;
          //将同步上下文设置在当前上下文(线程,主线程,可控制UI的)
          syn = SynchronizationContext.Current;
          //为socket创建示例,并设置相关属性。
          socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          //定义并实例一个Socket参数
          SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs();
          //设置到远程终节点属性(4502端口,为什么是4502,MS的SL通信安全上有)
          socketArgs.RemoteEndPoint = new DnsEndPoint(Application.Current.Host.Source.DnsSafeHost, 4502);
    
    
    
          //设置好当Socket任何一个动作完成时的回调函数。
          socketArgs.Completed += new EventHandler<SocketAsyncEventArgs>(socketArgs_Completed);
          //Socket参数的用户标识,实际上就是一个可以传递的OBJECT参数。
          socketArgs.UserToken = bytes;
          //执行连接。
          socket.ConnectAsync(socketArgs);
        }
    
    
    
        void socketArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
    
          //当任何一个Socket动作完成,都回调该函数,然后对LastOperation进行判断后继续执行相应的部分
    
          switch (e.LastOperation)
          {
    
            case SocketAsyncOperation.Connect:
    
              ProcessConnect(e);
    
              break;
    
            case SocketAsyncOperation.Receive:
    
              ProcessReceive(e);
    
              break;
    
            case SocketAsyncOperation.Send:
    
              ProcessSend(e);
    
              break;
    
          }
    
        }
    
    
    
        //将数据放入buffer并进行异步发送
    
        void ProcessConnect(SocketAsyncEventArgs e)
        {
          //当连接成功后,获取Socket参数 e传递过来的用户标识(也就是本示例中用户输入的字符串转换的Byte字节数组)
          byte[] bytes = (byte[])e.UserToken;
          //设置Socket参数的缓冲区参数,将我们的字节数组设置为Socket的缓冲区。
          e.SetBuffer(bytes, 0, bytes.Length);
          //同步一下上下文,显示一下当前的状态信息。
          syn.Post(GetText, "States:" + e.SocketError.ToString() + "," + e.LastOperation.ToString());
          //发送数据
          socket.SendAsync(e);
        }
    
    
    
        //发送完成后,执行等待接收服务器发回的数据
    
        void ProcessSend(SocketAsyncEventArgs e)
        {
    
          //定义个空的字节数组,设置好其大小
    
          byte[] bytes = new byte[1024];
    
          //将前面定义字节数组设置成缓冲区
    
          e.SetBuffer(bytes, 0, bytes.Length);
    
          //执行异步接收
    
          socket.ReceiveAsync(e);
    
        }
    
    
    
        //当接收完成后
    
        void ProcessReceive(SocketAsyncEventArgs e)
        {
    
          //在执行好接收后,本地SOCKET的缓冲区就会被服务器发送的数据填充。
    
          //显示下信息,当然也是用同步上下文的方式,在显示信息的时候,就直接将缓冲区的字节数组转换成字符串。
    
          syn.Post(GetText, Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length) + " and Received");
    
          //关闭Socket连接
    
          socket.Close();
    
          //最后显示下,Socket关闭。
    
          syn.Post(GetText, "Socket Closed");
    
        }
    
        //同步上下文调用的方法。
    
        void GetText(object str)
        {
          txtToSend.Text += "\r\n" + str.ToString();
    
        }
    
        
    
      
    
    
      }
    如果还是不太清楚,可以在上班时间外加我的QQ. QQ:283440946.
    努力!完成了js解析器,还差一个svg插件,一个绘图程序,做好自己,呵呵~!
    2010年4月18日 7:55
    版主