博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
wcf 双工通讯
阅读量:4955 次
发布时间:2019-06-12

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

介绍  

 

但在双向操作模式中,不但客户端可以向服务器发送请求,服务器也可以主动向客户端广播消息(也就是回调客户端中的方法)。在WCF中,不是所有的绑定都可 以实现双向操作模式的,比如http协议,它本身就是基于请求-回复的传输模式,所以本质上是实现不了双向操作的。但WCF提供了 WSDualHttpBinding协议让我们在http上实现了双向操作。其实WSDualHttpBinding并没有违反http单向传输的本质, 它实际上是创建两个了通道,一个用于客户端向服务器请求,一个用于服务器向客户端广播,间接实现了双向操作。但《WCF服务编程》书上有 说,WSDualHttpBinding无法穿越客户端与服务器的重重障碍,所以不赞成使用WSDualHttpBinding来实现双向操作。

 

第一步

新建一个windows应用程序,取名Host 

 

第2步:建立接口,IMessageService

using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;namespace Host{    //和单向操作相比,我们会发现服务契约上多了一行代码:[ServiceContract(CallbackContract = typeof(ICallBack))]    [ServiceContract(CallbackContract = typeof(ICallBack))]    public interface IMessageService    {        [OperationContract]        void RegisterMes();        [OperationContract]        int SendToAll(string name, string msg);        ///         /// 文件上传        ///         /// 字节数组        /// 文件后缀名        /// 
[OperationContract] int SentFile(byte[] data, string suffix); } public interface ICallBack { [OperationContract(IsOneWay = true)] void SendMessage(string name, string msg); [OperationContract(IsOneWay = true)] void Show(); }}

 

这时候引用 wcf组件

 

第 3步 建立 实现 MessageService

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading.Tasks;namespace Host{    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]    public class MessageService : IMessageService, IDisposable    {        public static List
CallBackList { get; set; } public MessageService() { CallBackList = new List
(); } public void RegisterMes() { var callback = OperationContext.Current.GetCallbackChannel
(); string sessionid = OperationContext.Current.SessionId; Form1.fm1.listLine.Items.Add(sessionid);//服务端显示客户端的SessionId //OperationContext.Current.Channel.Closing += // delegate // { // lock (CallBackList) // { // CallBackList.Remove(callback); // } // }; OperationContext.Current.Channel.Closing += new EventHandler(Channel_Closing); CallBackList.Add(callback); } void Channel_Closing(object sender, EventArgs e) { lock (CallBackList) { CallBackList.Remove((ICallBack)sender); } } public void Dispose() { CallBackList.Clear(); } public int SendToAll(string name, string msg) { var list = Host.MessageService.CallBackList; if (list == null || list.Count == 0) return 0; lock (list) { Task.Factory.StartNew(new Action(() => { foreach (var client in list) { client.SendMessage(name, msg); } })); } return 1; } ///
/// 文件上传 /// ///
字节数组 ///
文件后缀名 ///
public int SentFile(byte[] data, string suffix) { DateTime dt = DateTime.Now; string filename = string.Format("{0:yyyyMMddHHmmssffff}", dt); File.WriteAllBytes(filename+suffix, data); return 0; } }}

 

第4步 配置 Appconfig

右键Appconfig 点击编辑wcf配置 进入元素浏览器(我把这个理解成 可视化配置),这样免去程序员手敲代码的麻烦。

上几张图

 

 

 

看到3张图没,新建了一个服务,添加了2个终结点

app.config生产代码

 这个说下wcf 之 abc

  • Address: 每一个WCF的Service都有一个唯一的地址。这个地址给出了Service的地址和传输协议(Transport Protocol)
  • Binding:通信(Communication)的方式很多,同步的request/reply模式,非同步的fire-and- forget模式。消息可以单向或者双向的发送接收,可以立即发送或者把它放入到某一个队列中再处理。所供选择的传输协议也有Http, Tcp,P2P,IPC等。当要考虑Client/Server如何进行通讯的时候,除了考虑以上提到的几点之外,还有其它很多需要考虑的因素,如安全, 性能等。因此,简单来说,Binding只不过是微软提供的一组考虑比较周全、常用的封装好的通信方式。
  • Contract:Contract描述了Service能提供的各种服务。Contract有四种,包括Service Contract, Data Contract, Fault Contract和Message Contract

 

 

第5步 建立客户端 取名 Client 添加 System.ServiceModel引用,添加wcf引用

这里强调一下wcf引用 怎么加入项目里,打开wcf服务端生成的bin文件,运行Host.exe文件

 

 

这时候  http://192.168.2.23:9998/Host 就可以访问了,取名叫WcfSvc

引用wcf服务 的时候 你发现 客户端 app.config配置文件已经生成了

 

 

在Client工程里新建 MyCallBack 类回调 服务端方法

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace Client{    public class MyCallBack : WcfSvc.IMessageServiceCallback    {        public long count = 0;        public void SendMessage(string name, string msg)        {            System.Threading.Interlocked.Increment(ref count);            Form1.f.listMessage.Items.Add(string.Format("{0}:{1}:{2}", name, msg, count));            Form1.f.txtreceiving.Invoke(new Action(() =>            {                Form1.f.txtreceiving.Text = count.ToString();            }));        }        public void Show()        {            Form1.f.listMessage.Invoke(new Action(() =>            {                Form1.f.listMessage.Items.Add("show方法调用了");            }));        }    }}

 

这时候双工通讯搭建完毕,再来设计UI页面

 

这里设置ui控件有个技巧:默认控件是 私有属性,我把上线 这边文本框 改成 public,让他接受外面访问。

 

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.ServiceModel;using System.Text;using System.Windows.Forms;namespace Host{    public partial class Form1 : Form    {        public static Form1 fm1;        private ServiceHost _host = null;        public Form1()        {            InitializeComponent();            //构造函数初始化加载            fm1 =this;            CheckForIllegalCrossThreadCalls = false;            BindHost();        }        private void btnStart_Click(object sender, EventArgs e)        {            BindHost();        }        void BindHost()        {            try            {                _host = new ServiceHost(typeof(Host.MessageService));                _host.Open();                lbService.Text = string.Format("服务开启:{0}", DateTime.Now.ToString());            }            catch (Exception ex)            {                ShowMessage(ex.Message);            }        }        private void btnsend_Click(object sender, EventArgs e)        {
//发送内容 #region 备用 if (fm1 != null) { lock (MessageService.CallBackList) { foreach (ICallBack callback in MessageService.CallBackList) { callback.SendMessage("服务器发送: ", txtMsg.Text); } } } #endregion } /// /// (公用的)信息显示 /// /// 消息内容 private void ShowMessage(string msg) { this.lbMessage.Text = msg; this.lbMessage.Visible = true; } }}

 

画客户端页面

 

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.ServiceModel;using System.Threading.Tasks;using System.IO;namespace Client{    public partial class Form1 : Form    {        public static Form1 f;        public Form1()        {            InitializeComponent();            f = this;            CheckForIllegalCrossThreadCalls = false;                   }        WcfSvc.MessageServiceClient svc;        private void Form1_Load(object sender, EventArgs e)        {
//页面初始化 //Online(); var client = new MyCallBack(); var ctx = new InstanceContext(client); svc = new WcfSvc.MessageServiceClient(ctx); svc.RegisterMes(); } private void button1_Click(object sender, EventArgs e) {
//停止 isRun = false; } void ShowMessage(string msg) { this.lbError.Text = msg; this.lbError.Visible = true; } Task t; int sleeptime = 100; bool isRun = true; private void btnSend_Click(object sender, EventArgs e) {
//发送 isRun = true; sleeptime = int.Parse(txtNum.Text); t = Task.Factory.StartNew(delegate { while (true) { if (isRun) { svc.SendToAll(txtUserName.Text, txtSendMessage.Text); System.Threading.Thread.Sleep(sleeptime); } else { break; } } }); } private void btnclear_Click(object sender, EventArgs e) {
//清屏 this.listMessage.Items.Clear(); } private void btnUpload_Click(object sender, EventArgs e) {
//文件上传 using (OpenFileDialog ofd = new OpenFileDialog()) { if (ofd.ShowDialog() == DialogResult.OK) { //FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read); byte[] data = File.ReadAllBytes(ofd.FileName); int r = svc.SentFile(data, Path.GetExtension(ofd.FileName)); if (r == 0) { MessageBox.Show("发送完毕"); } } } } }}

 

上几张双工效果图,服务实现 “有图有真相”。

服务端 向客户端发送请求。

 

客户端向客户端发送请求

 

分享一下我的源码,有什么建议的朋友可以留言给我,相互讨论,相互学习。

大家可以把 双工通讯 理解成 “礼上往来”的通讯。

 

转载于:https://www.cnblogs.com/suntanyong88/p/4224058.html

你可能感兴趣的文章
AngularJs表单验证
查看>>
静态方法是否属于线程安全
查看>>
fegin 调用源码分析
查看>>
Linux的基本命令
查看>>
02号团队-团队任务3:每日立会(2018-12-05)
查看>>
SQLite移植手记1
查看>>
C# windows程序应用与JavaScript 程序交互实现例子
查看>>
HashMap详解
查看>>
js05-DOM对象二
查看>>
mariadb BINLOG_FORMAT = STATEMENT 异常
查看>>
C3P0 WARN: Establishing SSL connection without server's identity verification is not recommended
查看>>
iPhone在日本最牛,在中国输得最慘
查看>>
动态方法决议 和 消息转发
查看>>
WPF自定义搜索框代码分享
查看>>
js 基础拓展
查看>>
SpringBoot访问html访问不了的问题
查看>>
{width=200px;height=300px;overflow:hidden}
查看>>
C#生成随机数
查看>>
CSS基础学习 20.CSS媒体查询
查看>>
2019春季第十一周作业
查看>>