为WCF增加UDP绑定(实践篇)
这两天忙着系统其它功能的开发,没顾上写日志。本篇所述皆围绕为WCF增加UDP绑定(储备篇)中讲到的微软示例,该示例我已上传到网盘。
上篇说道,绑定是由若干绑定元素有序组成,为WCF增加UDP绑定其实就是为绑定增加UDP传输绑定元素,最终目的是在信道栈中生成UDP传输信道。因此我们定义一个类UdpTransportBindingElement,它继承自TransportBindingElement表明这是传输相关的绑定元素。示例中该类还实现了IPolicyExportExtension和IWsdlExportExtension接口,关于这两个接口,我知道它们的作用,但看到代码却是一头雾水,我认为要能理解这块内容首先要对WSDL相关的各种规范做一详细了解,目前我先不考虑。对这有兴趣的朋友可阅读蒋大牛的元数据架构体系全景展现。以前总觉得WCF不外如是,不成想这水也太特码深了(WCF相关的概念有很多,包括ChannelDispatcher、ListenerHandler、ChannelHandler等,这些和消息传输关系不大)。
UdpTransportBindingElement主要负责绑定管理类的创建工作,服务器端和客户端分别创建的是UdpChannelListener和UdpChannelFactory。UdpChannelFactory的实现比较简单,我们重点看UdpChannelListener实现。网上资料都有类似这么一段描述:ChannelListener负责监听消息,一旦消息抵达则使用对应的Channel接收消息。在UDP解决方案中,消息监听依赖System.Net.Sockets.Socket类,示例中调用该类的BeginReceiveFrom方法进行异步监听。
1 void StartReceiving(object state) 2 { 3 Socket listenSocket = (Socket)state; 4 IAsyncResult result = null; 5 6 try 7 { 8 lock (ThisLock) 9 {10 if (base.State == CommunicationState.Opened)11 {12 EndPoint dummy = CreateDummyEndPoint(listenSocket);13 byte[] buffer = this.bufferManager.TakeBuffer(maxMessageSize);14 result = listenSocket.BeginReceiveFrom(buffer, 0, buffer.Length,15 SocketFlags.None, ref dummy, this.onReceive, new SocketReceiveState(listenSocket, buffer));16 }17 }18 19 if (result != null && result.CompletedSynchronously)20 {21 ContinueReceiving(result, listenSocket);22 }23 }24 catch (Exception e)25 {26 Debug.WriteLine("Error in receiving from the socket.");27 Debug.WriteLine(e.ToString());28 }29 }
需要关注Socket.BeginReceiveFrom方法,MSDN有一段描述:当应用程序调用 BeginReceiveFrom 时,系统将会使用单独的线程来执行指定的回调方法,并将在 EndReceiveFrom 上一直阻塞到 Socket 读取数据或引发异常为止。但示例中有判断该方法是否同步执行的代码,因此我认为该方法并不会每次都用异步的方式来进行数据的接收,具体请看我的另一篇文章关于IAsyncResult接口的CompletedSynchronously属性。
不出意外,当数据抵达后采用Socket.EndReceiveFrom获取。我看到这里的时候觉得有点不对劲,不是说“ChannelListener负责监听消息,一旦消息抵达则使用对应的Channel接收消息”吗?既然ChannelListener都把数据接收完成了,还要Channel何用。此处似乎Channel真的只是走个过场,它存在的意义只是因为WCF框架需要它。所以我们还是需要将已接收的消息从ChannelListener传递给Channel,于是我翻看代码,希望找到一个event,在消息接收完毕后触发,以便Channel能实时得到消息可用的信号,结果没找到哪怕一个event的声明,于是我苦恼了。
1 public interface IInputChannel : IChannel, ICommunicationObject 2 { 3 EndpointAddress LocalAddress { get; } 4 5 IAsyncResult BeginReceive(AsyncCallback callback, object state); 6 IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state); 7 IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state); 8 IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state); 9 Message EndReceive(IAsyncResult result);10 bool EndTryReceive(IAsyncResult result, out Message message);11 bool EndWaitForMessage(IAsyncResult result);12 Message Receive();13 Message Receive(TimeSpan timeout);14 bool TryReceive(TimeSpan timeout, out Message message);15 bool WaitForMessage(TimeSpan timeout);16 }
从IInputChannel的定义可以看到,什么时候接收消息,什么时候等待,是不可控的,因为这些方法可以外部调用(一般是WCF框架自己调用)。简单地说,就是IInputChannel本身获取消息采用的是拉模式,而非推模式。为什么WCF框架不使用event模式(推模式)呢,我没有深入研究过,有知道的朋友还望赐教。这些方法调用时间不知,但若有可用消息时,不论何时调用Receive方法,我们都应该返回正确的Message,换句话说,从消息抵达到获取消息,可能有个时间差,这段时间内,消息数据不能丢失,于是我们应该有个临时存储消息数据的地方。考虑到消息数量和处理顺序,先入先出队列是个不错的选择。不出所料,示例中有个InputQueue类,该类相当复杂,不过万变不离其宗,UdpChannelListener将接收到的消息存入InputQueue,UdpInputChannel从InuptQueue中Receive消息。弄清楚这个,我便释然了。
上述模式只是实现消息从ChannelListener到Channel传递的其中一种方式,只要按规范实现WCF框架提供的关键接口,我们可以使用能想到的任何方式,比如使用event将消息接收工作转移到Channel类(更符合WCF对Channel的职责说明),当然接收到的消息仍旧需要用Receive方法去某个地方读取,因此消息的临时存储仍然必不可少。
由于最近比较忙,就先写到这里吧。示例中最核心的就是ChannelListener、InputQueue和AsyncResult类,AsyncResult类的作用也在关于IAsyncResult接口的CompletedSynchronously属性中有过阐述。若是全面铺开就太多了,有兴趣的朋友可以下载代码自己研究,有什么心得体会欢迎一起讨论。
转载请注明本文出处:http://www.cnblogs.com/newton/archive/2012/11/29/2793931.html
为WCF增加UDP绑定(实践篇)的更多相关文章
- 我的服装DRP之即时通讯——为WCF增加UDP绑定(应用篇)
发个牢骚,博客园发博文竟然不能写副标题.这篇既为我的服装DRP系列第二篇,也给为WCF增加UDP绑定系列收个尾.原本我打算记录开发过程中遇到的一些问题和个人见解,不过写到一半发现要写的东西实在太多,有 ...
- 为WCF增加UDP绑定(储备篇)
日前我开发的服装DRP需要用到即时通信方面的技术,比如当下级店铺开出零售单时上级机构能实时收到XX店铺XX时XX分卖出XX款衣服X件之类的信息,当然在上级发货时,店铺里也能收到已经发货的提醒.即时通信 ...
- WCF系统内置绑定列表与系统绑定所支持的功能
WCF系统内置绑定列表 绑定 配置元素 说明 传输协议 编码格式 BasicHttpBinding <basicHttpBnding> 一个绑定,适用于与符合 WS-Basic Pro ...
- WCF 通讯标准绑定
WCF 通讯标准绑定 一.预定义标准绑定 标准绑定 说明 BasicHttpBinding BasicHttpBinding 绑定用于最广泛的互交操作,针对第一代Web服务,所使用的传输协议是HTTP ...
- udp绑定信息
1. udp网络程序-端口问题 会变的端口号 重新运行多次脚本,然后在“网络调试助手”中,看到的现象如下: 说明: 每重新运行一次网络程序,上图中红圈中的数字,不一样的原因在于,这个数字标识这个网络程 ...
- [WCF编程]6.绑定行为
一.绑定行为概述 为了支持服务端的其它本地特性,WCF定义了行为的概念.行为就是服务的本地特性,不会影响服务的通信模式.客户端并不知道服务端行为,所以行为不会出现在服务的绑定和发布的元数据中.说下WC ...
- [WCF编程]5.绑定概述
一.绑定概述 WCF提供了一个编程框架,可以抽象化服务创建的复杂过程.绑定允许开发人员将精力集中在问题本身上,而无需考虑如何创建允许系统运行的架构,因为WCF已经创建了架构. 绑定类型是开发人员控制W ...
- TCP、UDP绑定同一端口通信的解释
昨日突然讨论起TCP与UDP是否可以在同一端口进行绑定,通信. 在印象当中我记得是可以的,今日google了相关资料, 确定以及肯定的: TCP.UDP可以绑定同一端口来进行通信: 网络中可以被命名和 ...
- WCF学习-协议绑定
文章:无废话WCF入门教程三[WCF的宿主] 讲了net.tcp协议的wcf绑定.
随机推荐
- solr +zookeeper+Jetty 集群搭建
solr版本:4.10.4 这里使用solr自带的jetty内置服务器 zk集群的 安装参照上篇文章: 在节点1example下上启动solr服务: java -DzkHost=192.168.0.1 ...
- 可读性 vs 效率
哪个重要. 应用层代码来说,实际上说任意一个重要都不为过, 但是到了内核里面之后,哪个重要. 肯定是效率阿,内核跑得慢,上面还有得玩么.
- Java oop第08章_JDBC01(入门)
一. JDBC的概念: JDBC(Java Database Connectivity)java数据库链接,是SUN公司为了方便我们Java程序员使用Java程序操作各种数据库管理系统制定的一套标准( ...
- java内存模型和垃圾回收
摘抄并用于自查 JVM内存模型 1. Java程序具体执行的过程: Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀) 由JVM中的类加载器加载各个类的字节码文 ...
- 【hihocoder】Demo Day
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 You work as an intern at a robotics startup. Today is your co ...
- mysql Slave 启动失败
报错日志 Slave failed to initialize relay log info structure java程序访问日志显示事物查询失败,排查mysql 发现其中一台slave 启动状态 ...
- 【JZOJ6346】ZYB和售货机
description analysis 其实这个连出来的东西叫基环内向树 先考虑很多森林的情况,也就是树根连回自己 明显树根物品是可以被取完的,那么买树根的价钱要是儿子中价钱最小的那个 或者把那个叫 ...
- SpringBoot集成Redis 一 分布式锁 与 缓存
1.添加依赖及配置(application.yml) <!-- 引入redis依赖 --> <dependency> <groupId>org.springfram ...
- thinkphp 跳转和重定向
页面跳转 在应用开发中,经常会遇到一些带有提示信息的跳转页面,例如操作成功或者操作错误页面,并且自动跳转到另外一个目标页面.系统的\Think\Controller类内置了两个跳转方法success和 ...
- Eclipse MyBatis generator 1.3.7插件的核心包(中文注释)
一.最近刚搭建一个项目框架,使用springboot + mybatis,但是在使用Eclipse开发时发现开发mybatis的Dao.mapper.xml和entity时特别不方便,手工去写肯定是不 ...