Silverlight Working with Sockets
Silverlight和服务端进行通信前会向服务端请求一个安全策略文件,在Silverlight 3.0中这个请求端口为943、Silverlight 4.0也可以是80。请求的模式取决于你的应用程序中SocketAsyncEventArgs.SocketClientAccessPolicyProtocol所指的值为Http或Tcp。如果是Http,需要在IIS中为80的站点添加net.tcp类型的绑定,并指明端口(4502 - 4530)。Tcp则需要一个应用程序负责监听943端口,当请求为时返回你的策略文件内容。策略文件的格式可以如下:
<?xml version="1.0" encoding="utf-8"?> <access-policy> <cross-domain-access> <policy> <allow-from http-request-headers="*"> <domain uri="*" /> </allow-from> <grant-to> <socket-resource port="4530" protocol="tcp" /> </grant-to> </policy> </cross-domain-access> </access-policy>
详细的内容可以参考Network Security Access Restrictions in Silverlight这篇文章:
http://msdn.microsoft.com/en-us/library/cc645032(v=VS.95).aspx
如果你编写的服务端需要和Silverlight进行Tcp通信,请准备一个策略服务端监听943端口。当Silverlight应用创建和服务端连接时,它会先请求你的PolicyServer并获取允许使用的端口。
关于WCF NET.TCP请参考WCF NET.TCP Protocol in Silverlight这篇文章:
http://www.silverlightshow.net/items/WCF-NET.TCP-Protocol-in-Silverlight-4.aspx
1 using System; 2 using System.IO; 3 using System.Net; 4 using System.Net.Sockets; 5 using System.Text; 6 using System.Threading; 7 8 namespace SLPolicyServer 9 { 10 class Program 11 { 12 /// <summary> 13 /// 主程序入口 14 /// </summary> 15 /// <param name="args">参数</param> 16 static void Main(String[] args) 17 { 18 String policyFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "clientaccesspolicy.xml"); 19 20 if (args.Length == 1) 21 { 22 policyFile = args[0]; 23 24 Console.WriteLine(args[0]); 25 } 26 27 new Thread(() => 28 { 29 new PolicyServer(policyFile); 30 Thread.Sleep(Timeout.Infinite); 31 }).Start(); 32 33 Console.ReadKey(); 34 } 35 } 36 37 /// <summary> 38 /// 策略连接 39 /// </summary> 40 class PolicyConnection 41 { 42 /// <summary> 43 /// 策略请求字符串 44 /// </summary> 45 private static readonly String PolicyRequestString = "<policy-file-request/>"; 46 47 private Socket m_connection; 48 private Byte[] m_buffer; 49 private Byte[] m_policy; 50 private Int32 m_received; 51 52 /// <summary> 53 /// 构造函数 54 /// </summary> 55 /// <param name="client">客户端套接字</param> 56 /// <param name="policy">策略数据</param> 57 public PolicyConnection(Socket client, Byte[] policy) 58 { 59 m_connection = client; 60 m_policy = policy; 61 m_buffer = new Byte[PolicyRequestString.Length]; 62 m_received = 0; 63 64 try 65 { 66 m_connection.BeginReceive(m_buffer, 0, PolicyRequestString.Length, SocketFlags.None, new AsyncCallback(OnReceive), null); 67 } 68 catch (SocketException) 69 { 70 m_connection.Close(); 71 } 72 } 73 74 /// <summary> 75 /// 接收数据 76 /// </summary> 77 /// <param name="ar">异步结果</param> 78 private void OnReceive(IAsyncResult ar) 79 { 80 try 81 { 82 m_received += m_connection.EndReceive(ar); 83 84 // 发送字符不足则继续接收 85 if (m_received < PolicyRequestString.Length) 86 { 87 m_connection.BeginReceive(m_buffer, m_received, PolicyRequestString.Length - m_received, SocketFlags.None, new AsyncCallback(OnReceive), null); 88 89 return; 90 } 91 92 String request = Encoding.UTF8.GetString(m_buffer, 0, m_received); 93 94 if (StringComparer.InvariantCultureIgnoreCase.Compare(request, PolicyRequestString) != 0) 95 { 96 m_connection.Close(); 97 98 return; 99 } 100 101 // 发送策略文件 102 m_connection.BeginSend(m_policy, 0, m_policy.Length, SocketFlags.None, new AsyncCallback(OnSend), null); 103 } 104 catch (SocketException) 105 { 106 m_connection.Close(); 107 } 108 } 109 110 /// <summary> 111 /// 发送数据 112 /// </summary> 113 /// <param name="ar">异步结果</param> 114 private void OnSend(IAsyncResult ar) 115 { 116 try 117 { 118 m_connection.EndSend(ar); 119 } 120 finally 121 { 122 m_connection.Close(); 123 } 124 } 125 } 126 127 /// <summary> 128 /// 策略服务 129 /// </summary> 130 class PolicyServer 131 { 132 private Socket m_listener; 133 private Byte[] m_policy; 134 135 /// <summary> 136 /// 构造函数 137 /// </summary> 138 /// <param name="policyFile">策略文件</param> 139 public PolicyServer(String policyFile) 140 { 141 // 读取策略文件 142 FileStream policyStream = new FileStream(policyFile, FileMode.Open); 143 m_policy = new byte[policyStream.Length]; 144 145 policyStream.Read(m_policy, 0, m_policy.Length); 146 policyStream.Close(); 147 148 // 监听943端口 149 m_listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); 150 m_listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, 0); 151 m_listener.Bind(new IPEndPoint(IPAddress.IPv6Any, 943)); 152 m_listener.Listen(10); 153 m_listener.BeginAccept(new AsyncCallback(OnConnection), null); 154 } 155 156 /// <summary> 157 /// 关闭 158 /// </summary> 159 public void Close() 160 { 161 m_listener.Close(); 162 } 163 164 /// <summary> 165 /// 连接 166 /// </summary> 167 /// <param name="ar">异步结果</param> 168 private void OnConnection(IAsyncResult ar) 169 { 170 Socket client = null; 171 172 try 173 { 174 client = m_listener.EndAccept(ar); 175 } 176 catch (SocketException) 177 { 178 return; 179 } 180 181 // 建立策略连接 182 PolicyConnection pc = new PolicyConnection(client, m_policy); 183 184 m_listener.BeginAccept(new AsyncCallback(OnConnection), null); 185 } 186 } 187 }