在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端,其運行結果爲:
服務端
客戶端
此種模式若存在錯誤很難進行跟蹤。