博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一起谈.NET技术,模拟IIS向Silverlight输出策略文件
阅读量:6272 次
发布时间:2019-06-22

本文共 5547 字,大约阅读时间需要 18 分钟。

  问题

  最近的Silverlight开发中,由于部分需求对实时性和数据量下载速度有要求,部分WCF服务配置成了netTcpBinding,这种方式跟普通的service.svc寄宿IIS不同的是,Silverlight需要的策略文件需要放置在本机IIS的根下,也就是wwwroot文件夹下,以满足Silverlight在以TCP协议调用本机WCF服务时请求策略文件。(注:Silverlight通过TCP协议调用WCF服务时,会以http方式请求主机的一个策略文件,地址是http://localhost/clientaccesspolicy.xml)

  这其实是个不太好的选择,程序运行的所需的环境被分成了两部分,同事的机器上并未安装IIS,为了大家开发简便,不用在额外安装IIS,也为了让程序更加独立,我就想能不能写代码监控80端口模拟IIS向Silverlight输出这个策略文件。

  解决方法

  有了这个想法之后,首先想到的是通过Socket进行监听,因为此前在MSDN上看到过这种方式,但很无奈,将代码转移过来之后,并未成功。相信做过Silverlight在Socket方面应用的朋友对下面这个PolicyServer类很熟悉吧。

 
using
System;
using
System.IO;
using
System.Net;
using
System.Net.Sockets;
namespace
PolicyServer
{
//
Encapsulate and manage state for a single connection from a client
class
PolicyConnection
{
private
Socket m_connection;
//
buffer to receive the request from the client
private
byte
[] m_buffer;
private
int
m_received;
//
the policy to return to the client
private
byte
[] m_policy;
//
the request that we're expecting from the client
private
static
string
s_policyRequestString
=
"
<policy-file-request/>
"
;
public
PolicyConnection(Socket client,
byte
[] policy)
{
m_connection
=
client;
m_policy
=
policy;
m_buffer
=
new
byte
[s_policyRequestString.Length];
m_received
=
0
;
try
{
//
receive the request from the client
m_connection.BeginReceive(m_buffer,
0
, s_policyRequestString.Length, SocketFlags.None,
new
AsyncCallback(OnReceive),
null
);
}
catch
(SocketException)
{
m_connection.Close();
}
}
//
Called when we receive data from the client
private
void
OnReceive(IAsyncResult res)
{
try
{
m_received
+=
m_connection.EndReceive(res);
//
if we haven't gotten enough for a full request yet, receive again
if
(m_received
<
s_policyRequestString.Length)
{
m_connection.BeginReceive(m_buffer, m_received, s_policyRequestString.Length
-
m_received, SocketFlags.None,
new
AsyncCallback(OnReceive),
null
);
return
;
}
//
make sure the request is valid
string
request
=
System.Text.Encoding.UTF8.GetString(m_buffer,
0
, m_received);
if
(StringComparer.InvariantCultureIgnoreCase.Compare(request, s_policyRequestString)
!=
0
)
{
m_connection.Close();
return
;
}
//
send the policy
m_connection.BeginSend(m_policy,
0
, m_policy.Length, SocketFlags.None,
new
AsyncCallback(OnSend),
null
);
}
catch
(SocketException)
{
m_connection.Close();
}
}
//
called after sending the policy to the client; close the connection.
public
void
OnSend(IAsyncResult res)
{
try
{
m_connection.EndSend(res);
}
finally
{
m_connection.Close();
}
}
}
//
Listens for connections on port 943 and dispatches requests to a PolicyConnection
class
PolicyServer
{
private
Socket m_listener;
private
byte
[] m_policy;
//
pass in the path of an XML file containing the socket policy
public
PolicyServer(
string
policyFile)
{
//
Load the policy file
FileStream policyStream
=
new
FileStream(policyFile, FileMode.Open);
m_policy
=
new
byte
[policyStream.Length];
policyStream.Read(m_policy,
0
, m_policy.Length);
policyStream.Close();
m_listener
=
new
Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
m_listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)
27
,
0
);
m_listener.Bind(
new
IPEndPoint(IPAddress.IPv6Any,
943
));
m_listener.Listen(
10
);
m_listener.BeginAccept(
new
AsyncCallback(OnConnection),
null
);
}
public
void
OnConnection(IAsyncResult res)
{
Socket client
=
null
;
try
{
client
=
m_listener.EndAccept(res);
}
catch
(SocketException)
{
return
;
}
//
handle this policy request with a PolicyConnection
PolicyConnection pc
=
new
PolicyConnection(client, m_policy);
//
look for more connections
m_listener.BeginAccept(
new
AsyncCallback(OnConnection),
null
);
}
public
void
Close()
{
m_listener.Close();
}
}
public
class
Program
{
static
void
Main(
string
[] args)
{
if
(args.Length
==
0
)
{
Console.WriteLine(
"
usage: PolicyServer.exe PolicyFile.xml
"
);
return
;
}
PolicyServer ps
=
new
PolicyServer(args[
0
]);
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
}
}

  此路不通之后,又想起使用HttpListener类,看看是否能够监听http请求,果然能够截获HTTP的请求。

 
HttpListener listener
=
new
HttpListener();
listener.Prefixes.Add(http:
//
localhost/);
listener.Start();Console.WriteLine(
"
开始监听…
"
);
HttpListenerContext context
=
listener.GetContext();
HttpListenerRequest request
=
context.Request;
HttpListenerResponse response
=
context.Response;

  但是这种方式有个明显的缺点,就是线程是阻塞的。于是,又想到使用线程池。

 
System.Threading.ThreadPool.QueueUserWorkItem(
new
System.Threading.WaitCallback(Listen));
private
static
void
Listen(
object
state)
{
while
(httpListener.IsListening)
{
httpListener.BeginGetContext(
new
AsyncCallback(ListenerCallback), httpListener);
listenForNextRequest.WaitOne();
}
}

  这样的话,每接收一个请求便会异步处理这个请求。在请求的处理上,接收请求后需要向外输出策略文件流,供silverlight端接收验证。

 
using
(System.Net.HttpListenerResponse response
=
context.Response)
{
System.Threading.Thread.Sleep(
1000
);
string
responseString
=
"
<?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=\
"
4502
-
4534
\
"
protocol=\
"
tcp\
"
/>
"
+
"
</grant-to>
"
+
"
</policy>
"
+
"
</cross-domain-access>
"
+
"
</access-policy>
"
;
byte
[] buffer
=
System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64
=
buffer.LongLength;
response.OutputStream.Write(buffer,
0
, buffer.Length);
}

  启动这个模拟服务,将clientaccesspolicy从wwwroot中移除后再运行一下程序,OK,我们不再需要将策略文件放到IIS下了。

  提醒 

  如果你的机器装了IIS,请还是放一个策略文件到wwwroot吧,否则就停掉IIS再使用这个类,因为IIS和这个类只能有一方监听80端口。

  本文中的这个类参考了:

转载地址:http://xdlpa.baihongyu.com/

你可能感兴趣的文章
Redis常用命令速查 <第二篇>
查看>>
CSS规范
查看>>
使用FastDateFormat来代替JDK自带的DateFormat
查看>>
Python爬虫从入门到放弃(十六)之 Scrapy框架中Item Pipeline用法
查看>>
Android源代码解析之(三)--&gt;异步任务AsyncTask
查看>>
(zhuan) 自然语言处理中的Attention Model:是什么及为什么
查看>>
C#中使用RabbitMQ收发队列消息
查看>>
Hadoop1.2.1 全然分布式集群搭建实操笔记
查看>>
第三百二十七节,web爬虫讲解2—urllib库爬虫—基础使用—超时设置—自动模拟http请求...
查看>>
MVC总结--MVC简单介绍以及和WebForm差别
查看>>
tiny4412 裸机程序 五、控制icache【转】
查看>>
VB.NET多线程入门
查看>>
国外物联网平台初探(二) ——微软Azure IoT
查看>>
findlibrary returned null产生的联想,Android ndk开发打包时我们应该怎样注意平台的兼容(x86,arm,arm-v7a)...
查看>>
Android事件分发机制源代码分析
查看>>
《设计模式》结构型模式
查看>>
[javase学习笔记]-8.3 statickeyword使用的注意细节
查看>>
Spring集成RabbitMQ-使用RabbitMQ更方便
查看>>
Nginx 设置域名转向配置
查看>>
.net core 实现简单爬虫—抓取博客园的博文列表
查看>>