程序分四个部分:
1、原理
使用WCF的nettcp绑定。nettcp绑定类似原来的RPC,即.net remoting,只是在WCF提供统一协定,同一服务可以拥有多种客户端。
2、代码展示
代码部分分为契约、服务、服务端UI、客户端四个部分。
2.1、契约部分
定义服务的接口,一个提供服务,另一个提供回调。
服务端接口定义:
[ServiceContract( Name = "SampleDuplexHello", Namespace = "http://microsoft.wcf.documentation", CallbackContract = typeof(IHelloCallbackContract), SessionMode = SessionMode.Required )] public interface IDuplexHello { /// <summary> /// 往服务端发送消息 /// </summary> /// <param name="greeting"></param> [OperationContract(IsOneWay = true)] void Hello(string greeting); /// <summary> /// 让服务端缓存客户端 /// </summary> [OperationContract] void Registor(); }
服务端回调接口定义:
/// <summary> /// 回调接口 /// </summary> public interface IHelloCallbackContract { /// <summary> /// 向客户端推送消息 /// </summary> /// <param name="responseToGreeting"></param> [OperationContract(IsOneWay = true)] void Reply(string responseToGreeting); }
2.2、服务实现部分
代码部分:
public class DuplexHelloImpl : IDuplexHello, IBrocaster { private ConcurrentBag<IHelloCallbackContract> clients = new ConcurrentBag<IHelloCallbackContract>(); 。。。 public void Hello(string greeting) { if (ServerInstance != null) { ServerInstance.Update(greeting); } } public void Registor() { IHelloCallbackContract callerProxy = OperationContext.Current.GetCallbackChannel<IHelloCallbackContract>(); if (!clients.Contains(callerProxy)) { clients.Add(callerProxy); } } }
配置部分:
<system.serviceModel> <bindings> <netTcpBinding> <binding name="NewBinding0"> <security mode="None"/> </binding> </netTcpBinding> </bindings> <services> <service name="WindowsFormsServer.DuplexHelloImpl"> <endpoint address="net.tcp://localhost:909/hello" bindingConfiguration="NewBinding0" binding="netTcpBinding" contract="Contracts.IDuplexHello"/> </service> </services> </system.serviceModel>
启动部分:
static void Main() { ServiceHost host = new ServiceHost(typeof(DuplexHelloImpl)); host.Open(); 。。。 }
2.3、服务端界面
public partial class ServerForm : Form, IUpdater { public static IBrocaster ServiceInstance { get; set; } public ServerForm() { InitializeComponent(); } public void Update(string content) { this.Invoke(new Action(() => { this.textBox2.AppendText(content); this.textBox2.AppendText(" "); })); } private void button1_Click(object sender, EventArgs e) { if (!string.IsNullOrWhiteSpace(textBox1.Text)) { if (ServiceInstance == null) { MessageBox.Show("服务启动中,稍后再发!"); return; } ServiceInstance.Brocast(textBox1.Text); textBox1.Text = ""; } else MessageBox.Show("回复内容不能为空!"); } private void ServerForm_Load(object sender, EventArgs e) { //Service与主窗体非同步,因而需要等待 Task.Run(() => { while (ServiceInstance == null) { Thread.Sleep(50); } ServiceInstance.ServerInstance = this; }); } }
2.4、客户端界面
public partial class ClientForm : Form, IHelloCallbackContract { /// <summary> /// 定义为字段,以供重用。 /// </summary> IDuplexHello client; public ClientForm() { InitializeComponent(); } public void Reply(string responseToGreeting) { this.textBox2.AppendText(responseToGreeting); this.textBox2.AppendText(" "); } private void button1_Click(object sender, EventArgs e) { if (!string.IsNullOrWhiteSpace(textBox1.Text)) { client.Hello(textBox1.Text); textBox1.Text = ""; } else MessageBox.Show("回复内容不能为空!"); } private void ClientForm_Load(object sender, EventArgs e) { //创建连接 InstanceContext cxt = new InstanceContext(this); NetTcpBinding binding = new NetTcpBinding(); binding.Security.Mode = SecurityMode.None; string url = "net.tcp://localhost:909/hello"; DuplexChannelFactory<IDuplexHello> factory = new DuplexChannelFactory<IDuplexHello>(cxt, binding, url); client = factory.CreateChannel(); client.Registor(); } }