Develop every application as an art using the most suitable technologies!
2007.10-2008.9: Solutions Architect
2008.10-2009.9: Connected System
本blog原创文字(标明[原创]字样)只代表本人某一时间内的观点或结论,与本人所在公司没有任何关系。第三方若用于商业用途的转载,须取得本人授权。一般的引用、转载请标明出处!
一、Sample
为了使大家对在WCF如何实现双向通信(Bidirectional Communication)有一个直观的理解,我们先来看一个简单的Sample。我们照例采用下面的4层结构和Calculator的例子:
1.Contract:Artech.DuplexWCF.Contract. ICalculator
由于模拟的是通过Callback来显示Add方法计算的结果,我把Add Operation设置成One-way。在Service Contract中设置了Callback Contract,Callback Contract定义在Interface Artech.DuplexWCF.Contract. ICallback中:
2.Service: Artech.DuplexWCF.Service. CalculatorService
在Service端,通过OperationContext.Current.GetCallbackChannel来获得Ciient指定的CallbackContext instance,进而调用Client的Operation。
3.Hosting:
Configuration:
我们通过netTcpBinding来模拟基于TCP的双向通信。
Program:
4.Client:
Callback:Artech.DuplexWCF.Client. CalculatorCallback
Callback的操作-显示计算结果,实现在Artech.DuplexWCF.Client. CalculatorCallback中,他实现了在Contract中定义的Callback Contract:Artech.DuplexWCF.Contract. ICallback。
在创建DuplexChannelFactory< ICalculator>中,指定了Callback Context Instance: 一个实现了Callback Contract的CalculatorCallback 对象。该对象在Service中通过OperationContext.Current.GetCallbackChannel<ICallback>()获得。
通过运行程序:
2. 基于Http的双向通讯V.S.基于TCP的双向通讯
由于Http和TCP在各自协议上的差异,他们实现双向通信的发式是不同的。
Http是一个应用层的协议,它的主要特征就是无连接和无状态(connectless & stateless )。它采用传统的Request/Reply的方式进行通信,Client发送Http Request请求Server的某个资源,Server端接收到该Http Request, 回发对应的Http Response。当Client端接收到对应的Response,该Connection会关闭。也就是说Client和Server的Connection仅仅维持在发送Request到接收到Response这一段时间内。同时,每次基于Http的 connection是相互独立,互不相干的,当前connection无法获得上一次connection的状态。为了保存调用的的状态信息,ASP.NET通过把状态信息保存在Server端的方式实现了对Session的支持,具体的做法是:ASP.NET为每个Session创建一个Unique ID,与之关联一个HttpSessionState对象,并把状态信息保存在内存中或者持久的存储介质(比如SQL Server)中。而WCF则采用另外的方式实现对Session的支持:每个Session关联到某个Service Instance上。
回到我们WCF双向通信的问题上,当Client调用Service之前,会有一个Endpoint在Client端被创建,用于监听Service端对它的Request。Client对Service的调用会建立一个Client到Server的Connection,当Service在执行操作过程中需要Callback对应的Client,实际上会建立另一个Service到Client的Http connection。虽然我们时候说WCF为支持双向通信提供Duplex Channel,实际上这个Duplex channel是由两个Request/Reply Channel组成的。
而对于TCP/IP簇中的传输层协议TCP,它则是一个基于Connection的协议,在正式进行数据传输的之前,必须要在Client和Server之后建立一个Connection,Connection的建立通过经典的“3次握手”来实现。TCP天生就具有Duplex的特性,也就是说当Connection被创建之后,从Client到Sever,和从Server到Client的数据传递都可以利用同一个Connection来实现。对于WCF中的双向通信,Client调用Service,Service Callback Client使用的都是同一个Connection、同一个Channel。所以基于TCP的Duplex Channel才是真正意义上的Duplex Channel。WCF相关内容:[原创]我的WCF之旅(1):创建一个简单的WCF程序[原创]我的WCF之旅(2):Endpoint Overview[原创]我的WCF之旅(3):在WCF中实现双向通信(Bi-directional Communication)[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II [原创]我的WCF之旅(5):Service Contract中的重载(Overloading)[原创]我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案[原创]我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承 [原创]我的WCF之旅(8):WCF中的Session和Instancing Management [原创]我的WCF之旅(9):如何在WCF中使用tcpTrace来进行Soap Trace[原创]我的WCF之旅(10): 如何在WCF进行Exception Handling [原创]我的WCF之旅(11):再谈WCF的双向通讯-基于Http的双向通讯 V.S. 基于TCP的双向通讯 [原创]我的WCF之旅(12):使用MSMQ进行Reliable Messaging[原创]我的WCF之旅(13):创建基于MSMQ的Responsive Service
posted on 2007-06-18 18:32 Artech 阅读(7340) 评论(67) 编辑 收藏 网摘
这个系列真的不过,LZ花了很多心思呀,希望首页多出现这样的文章。望LZ再接再厉。 回复 引用
@路人甲 真是不错! 回复 引用
@路人甲 @路人乙 感谢两位路人的关注,我会继续这个系列。 回复 引用 查看
没错,这个问题是要注意的。 因为在http中使用duplex时会使用两个连接所以会产生安全方面的问题,而tcp就不存在了。 回复 引用
@idior呵呵,很久没见你冒头了:) 回复 引用 查看
公司上cnblogs速度很慢,而且最近在翻译,所以很少冒泡了 :P 回复 引用
相当不错,收藏你的Blog了,除了WCF,还有其他东东也可以看 回复 引用
@Rexzhou:) 回复 引用 查看
请问一下写的WCF客户端为什么夸了一个网络以后会 提示“服务器已拒绝客户端的凭据~~” 回复 引用
@大坏蛋我想是因为Authentication方面的原因,在默认的情况下,采用的是Windows Authentication(kerberos),一种基于Ticket的认证方式,只要用于Intranet。如果需要跨网络,你可能需要选择另外一种认证方式。不过具体原因,不是太确定。 回复 引用 查看
能说一个大概的方法吗!配置文件怎样写呢?能给个代码看一下吗?谢谢 回复 引用
@大坏蛋你可以参阅http://msdn2.microsoft.com/en-us/library/ms733836.aspx" target="_new">Selecting a Credential Type 回复 引用 查看
跨网络可以使用x509或WS-Trust+SAML Tokenhttp://www.cnblogs.com/idior/archive/2006/05/16/354066.html 回复 引用
嗯,kerberos还必须用到AD 回复 引用 查看
准备借着你的系列, 也玩玩WCF,专注与关注中。。。 回复 引用 查看
@idior @Jeffrey Zhao 谢谢两位的建议! 回复 引用 查看
@Anytao Welcome to the world of WCF! 呵呵 回复 引用 查看
请问一个问题,我在客户端传一个contract类别的参数在server调用,但是却出错,是不是不能这样使用呢?例如: [DataContract] Class AContract { int aData; [DataMember] public int AData {get;set;} } Server: ... [OperationContract] public void Add( AContract aContract ) { //doSomething(); } Client: ... AContract aContract = new AContract(); aContract.AData = 2; server.Add( aContract );//error.... 回复 引用
@demohunter DataContract是这样定义的,不知道你的具体出错信息是什么? 回复 引用 查看
在我的代码里面提示的是这样: There was an error while trying to serialize parameter http://tempuri.org/:ob. The InnerException message was 'Type 'Observe_WPF_WCF_Charroom.IObserver.Observer' with data contract name 'Observer:http://schemas.datacontract.org/2004/07/Observe_WPF_WCF_Charroom.IObserver' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details 回复 引用
代码如下: Client: public partial class Window1 : Window { Service1Client server = new Service1Client();//代理类 public Window1() { try { InitializeComponent(); IObserver.IObserver ob = new IObserver.Observer();//一个Contract server.Join("aaa", ob); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } public interface IObserver { [OperationContract] void Update(string msg); } [DataContract] public class Observer: IObserver { string text; [DataMember] public string Text { get { return this.text; } set { this.text = value; } } string name; [DataMember] public string Name { get { return this.name; } set { this.name = value; } } int type; [DataMember] public int Type { get { return this.type; } set { this.type = value; } } public void Update(string msg) { if (this.type == 0) { this.text = this.name + "enter" + System.Environment.NewLine; } else if (this.type == 1) { this.text = this.name + " say :" + msg + System.Environment.NewLine; } else if (this.type == 2) { } else if (this.type == 3) { this.text = this.name + "logout" + System.Environment.NewLine; } } [ServiceContract(SessionMode = SessionMode.Required)] [ServiceKnownType(typeof(IObserver.IObserver))] public interface IService1 { [OperationContract] string[] Join(string name, Observe_WPF_WCF_Charroom.IObserver.IObserver ob); [OperationContract] void Say(string msg); [OperationContract] void Whisper(string to,string msg); [OperationContract] void Leave(string name); } public class Service1 : IService1 { static Dictionary<string, IObserver.IObserver> list = new Dictionary<string, IObserver.IObserver>(); public Observe_WPF_WCF_Charroom.IObserver.IObserver Test() { Observer ob = new Observer(); ob.Text = "Test"; return ob; } public int Add() { IObserver.IObserver ob = new Observer(); (ob as Observer).Type = 2; (ob as Observer).Type++; return (ob as Observer).Type; } public string[] Join(string name, IObserver.IObserver ob) { list.Add(name, ob); foreach (var ob1 in list) { (ob1.Value as IObserver.IObserver).Update(name + "Enter"); } string[] list1 = new string[list.Count]; list.Keys.CopyTo(list1, 0); return null; } public void Say(string msg) { //foreach (var ob in list) //{ // (ob.Value as Observe_WPF_WCF_Charroom.IObserver.IObserver).Update(msg); //} } public void Whisper(string to, string msg) { //list[to].Update(msg); } public void Leave(string name) { //list.Remove(name); //foreach (var ob in list) //{ // (ob.Value as Observe_WPF_WCF_Charroom.IObserver.IObserver).Update(""); //} } } 回复 引用
@Anytao @Artech 正在看你们二位的大做呢。 Anytao的[你必须知道的.NET]系列也是我非常喜欢的啊。 回复 引用 查看
@demohunter [ServiceKnownType(typeof(IObserver.IObserver))] 改成[ServiceKnownType(typeof(Observer))] 试试看。 回复 引用 查看
@妖居 AnyTao的文章写得很深入,是学习的好素材。 回复 引用 查看
@Artech 确实,你们二人一个是最新的技术研究,一个是深入的内核探索,确实让我受益匪浅啊。你是不是从国外的网站上学的WCF技术啊?我的E文不好,看那些技术文章一篇,头就大了。#_#而且此前看WPF的一些文章,MS自己写的很多都前后矛盾,或者不能运行。看来螃蟹还是很不容易吃的啊…… 回复 引用 查看
@妖居 其实我不是一个新技术的狂热地追随者,我和AnyTao一样也喜欢研究CLR。现在WCF的中文资料很少,只有通过英文站点,MSDN是我学习资料的主要来源 回复 引用 查看
@Artech 确实,现在WPF的资料还多一点,WCF就很少了,毕竟现在用.Net做企业及架构的就不是很多(至少没有Java多,我感觉。),用上WCF的就更少了。 其实当年.Net刚出的时候,也没有什么中文资料,M$给的资料少得可怜。 另外,方便的话,能不能加我MSN呢。我的地址是 farrio%vip.163.com。 回复 引用 查看
To demohunter: [DataMember]属性加到field上而不是property上 这里的话加到aData上去。 回复 引用
@Bird @demohunter DataMemberAttribute既可以用到Field也可以用到Property上,@demohunter得问题是DataContractAttribute是用到Observer而不是用到IObserver,所以[ServiceKnownType(typeof(IObserver.IObserver))] 要改成[ServiceKnownType(typeof(Observer))] 回复 引用 查看
@Bird [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited=false, AllowMultiple=false)] public sealed class DataMemberAttribute : Attribute 回复 引用 查看
Hi, Artech: 谢谢你的这个系列作品,获益匪浅啊。 如果可以的话,能不能写一篇关于采用MSMQ的Pub/Sub的文章。如果能有订阅管理控制的就更好了。 回复 引用 查看
@Leox 真的很巧,我现在正在准备“在WCF中使用MSMQ进行Reliable Messaging”的文章。 回复 引用 查看
这个哥哥写的太棒了,技术太好了,长的太帅了,太招人喜欢了,实在是米有太好的词了 回复 引用 查看
@winnie00 熟归熟,你这样夸我我还是会脸红的:) 回复 引用 查看
@Artech 期待你的<<在WCF中使用MSMQ进行Reliable Messaging>>. 加油啊。 回复 引用
问问题的来了: 1.每个Session关联到某个Service Instance上,如果是一个用户一个Session,每个Session一个Service Instance,普通的服务器能承载多少个Service Instance。 2.WCF中,服务端是否是并发处理客户的请求(不论是TCP还是HTTP模式)? 3.多客户端(超过1000个)的应用程序,WCF服务器端应如何设计。 因为要设计的软件同时在线的人数可能超过1000人,而我是首次接触WCF和客户端-服务器端程序,MSDN也看了不少,但是还是理不出头绪,希望博主和各位大侠给点参考资料,链接就成。 回复 引用 查看
@cY2007.nET1. 你的第一个问题,我确实没有一个量化的概念。2. 多个客户请求可以并发操作,你可以通过设置ConcurrencyMode进行相关的设置。3. 象你的说得这种同时处理多客户端的情况,个人觉得不用使用Session,最好使用PerCall的Instancing方式。 回复 引用 查看
请教高手,我做了的wcf 应用是host 到iis 上的,在做的一个服务方法,更形数据;在调用方法的数据量比较少时没有问题;eg 6列30几条数据没问题;6列360条就有问题了包的错误是 The remote server returned an unexpected response: (400 ) Bad Request. 先感谢先;我的邮箱congch_qm@faw.com.cn 回复 引用
@虫子congch_qm@faw.com.cn该不会你的Response Soap太大了,超出Soap允许的范围吧。 回复 引用 查看
感谢上天赐于我们这么多好人 回复 引用
@路人丙^_^ 回复 引用 查看
看了这系列的教程,真是受益非浅啊 感谢博主! 回复 引用
非常期待楼主关于wcf security方面的文章 回复 引用
从楼主的文章开始入手WCF的,看后获益匪浅,多谢楼主;我安装楼主提供的代码允许部署后,在另一台机器上却访问不了,我用的不是IIS托管; 感觉是权限的问题,因为本机访问是完全没有问题的,其他机器上能看到有这个服务 但是Channel连接失败;还望楼主不吝赐教;有解决代码就更好了,麻烦发我一份;我的邮箱kingxiekang@163.com 回复 引用
很好的文章 回复 引用 查看
回调接口是否支持继承? public interface ICallback:IUpDataCallBack { ........ } [ServiceContract(CallbackContract = typeof(ICallback))] 回复 引用 查看
局域网内 net:tcp 连接失败是什么原因 回复 引用
@安德尔斯 这个问题就不好回答了,可能是网络问题, 比如Firewall, 防毒软件, ... 回复 引用 查看
@阿滨 [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, Inherited=false, AllowMultiple=false)] public sealed class ServiceContractAttribute : Attribute ServiceContractAttribute 不能被继承。 回复 引用 查看
基于dualtcp等,是否能实现“反向调用”?即:内网client连接公网server,server调用client的服务。注意此时client若公开终结点,server通过回调是连接不上它的,因为client的ip是内网的(这样理解有没有错?)如果理解没有错的话,如何实现该反向调用?谢谢! 回复 引用
@Victor.WooDuplex一般应用于局域网,不太适合Internet。主要是防火墙的问题。 回复 引用 查看
楼主,你好,我现在用silverlight和wcf做一个聊天程序,程序启动没问题,开始可以聊天,但是如果我过几分钟不去管他,然后在开始进行聊天,就会出现 “通信对象 System.ServiceModel.Channels.ClientPollingDuplexSessionChannel 无法用于通信 因为其处于出错状态”.不知道为什么? 回复 引用 查看
--引用-------------------------------------------------- Artech: @Victor.Woo Duplex一般应用于局域网,不太适合Internet。主要是防火墙的问题。 -------------------------------------------------------- 请问在Internet上面,进行双工通信怎么实现呢? 回复 引用
@双工Internet上 基本上不会使用双工通信 回复 引用 查看
谢谢LZ的辛勤劳动,实在是太用帮助! 请教一个问题,讨论基于HTTP和TCP的双向通讯的差异能否举例说一下在实际中的应用呢? 回复 引用
再请问一下,要安装什么才在新建项目web下有WCF Service Application模板呢?我的只有WCF Service Library? 回复 引用
@WCFLearning [原创]WCF后续之旅(9):通过WCF的双向通信实现Session管理 回复 引用 查看
--引用--------------------------------------------------goldenlily: 再请问一下,要安装什么才在新建项目web下有WCF Service Application模板呢?我的只有WCF Service Library?--------------------------------------------------------VS2008默认就有, 2005好像没有见着! 回复 引用 查看
回复真及时,感谢您的帮助!继续学习中! 回复 引用
博主好,我是新手。想请教一下,BS架构下可以实现WCF的双向通信吗?可以的话怎么做呢?有参考文章或示例吗?谢谢! 回复 引用
非常好的文章 回复 引用
该系列文章真是不错! 回复 引用
昵称: [登录] [注册]
主页:
邮箱:(仅博主可见)
验证码: 看不清,换一个
评论内容:
登录 注册
[使用Ctrl+Enter键快速提交评论]
Powered by: 博客园 Copyright © Artech