2.2.3 基于TCP的端口共享
由于IIS只能接受基于HTTP的服务寄宿方式,对于采用TCP的服务,我们只能通过其他的寄宿方式。为了实现基于TCP的端口共享,在.NET Framework 3.0中,提供了一个特殊的Windows服务:Net.TCP端口共享服务(Net.TCP Port Sharing Service)。
Net.TCP端口共享服务
从功能上讲,Net.TCP端口共享服务实现了和HTTP.SYS相同的功能:请求的监听和分发。唯一不同是,HTTP.SYS运行在内核模式(Kernel Mode)下,而Net.TCP Port Sharing Service运行在用户模式(User Mode)下。
WCF对Net.TCP端口共享服务提供了原生的支持,其实现原理如图2-5所示:在Net.TCP端口共享服务开启的状态下,如果通过两个服务寄宿应用程序分别寄宿两个服务,Service1和Service2,并且它们共享一样的监听端口:8888。当ServiceHost的Open方法被执行的时候,WCF会将这两个地址net.tcp://artech.com:8888/service1和net.tcp://artech.com:8888/service2注册到Net.TCP端口共享服务中。而对于Net.TCP端口共享服务来说,在其内部维护着一个目的地址和进程的列表,在进行目的地址注册的时候,会将这两个地址和对应的服务寄宿地址的匹配关系添加到该列表之中。
图2-5 NET.TCP端口共享服务原理
若服务客户端proxy1和proxy2,分别调用Service1和Service2,当基于它们各自服务调用的socket连接请求抵达目标主机(artech.com)时,Net.TCP端口共享服务会截获请求消息,并获取目的地址。然后根据该目的地址,结合内部维护的目的地址和目标进程匹配列表,得到对应的目标应用程序,并将请求消息转发给真正的目标程序。
基于TCP端口共享的编程
由于WCF下基于TCP的端口共享是建立在Net.TCP Port Sharing Service Windows服务上的。所有安装有.NET Framework 3.0的操作系统都具有该Windows服务,但是在默认的情况下,该服务是不可用的。当你第一次使用Net.TCP Port Sharing Service,或者发现该服务被禁用时,须要手工启用该服务。
注:通过“开始”→“控制面板”→“管理工具”→“服务”,打开如图2-6所示的“服务对话框”,然后定位到Net.TCP Port Sharing Service。
图2-6 Windows Service Manager下的Net.TCP Port Sharing Service
在基于TCP的WCF通信中,NetTcpBinding实现了通信的所有细节,这些细节也包括端口的共享。在NetTcpBinding中,定义了一个特殊的属性,PortSharingEnabled,表明是否启动端口共享机制。如果需要启动端口共享,须要通过如下编程或配置的方式将NetTcpBinding的PortSharingEnabled属性设为true,代码如下所示。
public class NetTcpBinding : Binding, IBindingRuntimePreferences { //其他成员 public bool PortSharingEnabled { get; set; } }
using(ServiceHost serviceHost = new ServiceHost(typeof(Service1))) { NetTcpBinding binding = new NetTcpBinding(); binding.PortSharingEnabled = true; serviceHost.AddServiceEndpoint(typeof(IService1), binding,"net.tcp://127.0.0.1:9999/service1"); serviceHost.Open(); Console.Read(); }
<configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding name="portSharingBinding" portSharingEnabled="true" /> </netTcpBinding> </bindings>
<services> <service name="Artech.WcfServices.Services.CalculatorService"> <endpoint binding="netTcpBinding" bindingConfiguration="portSharingBinding" contract="Artech.WcfServices.Contracts.ICalculator" /> </service> </services> </system.serviceModel> </configuration>