在WCF中有三种消息交换模式(Message Exchange Pattern,MEP),包括单向通信模式、双工通信模式、请求-响应通信模式,其通过5种不同的信道来实现,其中不是每一种绑定都能支持这些信道,具体可以通过程序进行检测,可参考之前的检测结果。从其中可以看出对於单向通信模式的(IInputChannel和IOutputChannel)只有MsmqIntegrationBinding、NetMsmqBinding和NetPeerTcpBinding三种绑定在定制的基础上支持。本文介绍在VS2010 .NET 4.0.30319环境下,利用NetPeerTcpBinding这种定制的绑定模拟单向通信模式的实现。
其中建立两个控制台应用程序,具体的结构如下图所示:
其中InputOutputServer是服务端,同时提供p2p名字解析的服务,负责侦听客户端请求,并用IInputChannel接收消息;InputOutputClient是客户端,通过IOutputChannel发送消息至服务端。其中需要额外引入几个程序库,图中已有标注。
InputOutputServer端的Program.cs文件为:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
using System.ServiceModel.Security;
using System.Net.PeerToPeer;
using System.ServiceModel.PeerResolvers;
namespace InputOutputServer
{
class Program
{
static void Main(string[] args)
{
//启动p2p对等网络的名称解析服务
CustomPeerResolverService cprs = new CustomPeerResolverService();
cprs.RefreshInterval = TimeSpan.FromSeconds(5);
ServiceHost host = new ServiceHost(cprs);
cprs.ControlShape = true;
cprs.Open();
host.Open(TimeSpan.MaxValue);
Console.WriteLine("p2p名称解析服务成功启动……,其地址为:"+host.Description.Endpoints[0].Address.ToString());
//定义p2p对等网络的监听地址
Uri listenUri = new Uri("net.p2p://localhost/first");
NetPeerTcpBinding binding = new NetPeerTcpBinding();
binding.Resolver.Custom.Address = new EndpointAddress("net.tcp://localhost/Resolver");//定义p2p的名称解析服务所在的地址
//定义获取p2p服务的绑定并设置
NetTcpBinding tcpBinding = new NetTcpBinding();
tcpBinding.Security.Mode = SecurityMode.None;
binding.Resolver.Custom.Binding = tcpBinding;
//NetPeerTcpBinding默认是采用安全传输方式,设置其为不采用
binding.Security.Mode = SecurityMode.None;
//设置并开通监听端口
IChannelListener<IInputChannel> listenChannel = binding.BuildChannelListener<IInputChannel>(listenUri);
listenChannel.Open();
//建立消息接收通道
IInputChannel channel = listenChannel.AcceptChannel(TimeSpan.MaxValue);
channel.Open();
//接收消息
Message rc = channel.Receive(TimeSpan.MaxValue);
Console.WriteLine("接收到以下消息:");
Console.WriteLine(rc);
Console.WriteLine("按任意键结束……");
Console.Read();
host.Close();
cprs.Close();
}
}
}
InputOutputServer的App.config文件为:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="System.ServiceModel.PeerResolvers.CustomPeerResolverService">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost/"/>
</baseAddresses>
</host>
<endpoint address="Resolver" binding="netTcpBinding" bindingConfiguration="TcpConfig" contract="System.ServiceModel.PeerResolvers.IPeerResolverContract">
</endpoint>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="TcpConfig">
<security mode="None"></security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
InputOutputClient端的Program.cs文件为:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
namespace InputOutputClient
{
class Program
{
static void Main(string[] args)
{
NetPeerTcpBinding binding = new NetPeerTcpBinding();
binding.Security.Mode = SecurityMode.None;
binding.Resolver.Custom.Address = new EndpointAddress("net.tcp://localhost/Resolver");
NetTcpBinding tcpBinding = new NetTcpBinding();
tcpBinding.Security.Mode = SecurityMode.None;
binding.Resolver.Custom.Binding = tcpBinding;
//建立输出的信道工厂
IChannelFactory<IOutputChannel> outChannel = binding.BuildChannelFactory<IOutputChannel>();
outChannel.Open();
//建立输出信道,必须指出信道目的服务的地址
IOutputChannel channel = outChannel.CreateChannel(new EndpointAddress("net.p2p://localhost/first"));
channel.Open();
//生成输出的消息并发出消息
Message test = Message.CreateMessage(binding.MessageVersion, "test", "这是从客户端发送到net.p2p://localhost/first的消息");
channel.Send(test);
test.Close();
Console.WriteLine("信息已经发送至(net.p2p://localhost/first)。");
Console.WriteLine("按任意键结束……");
Console.Read();
}
}
}
先运行InputOutputServer端,然后运行InputOutputClient端,其运行结果为:
服务端
客户端
此种模式若存在错误很难进行跟踪。