这两天忙着系统其它功能的开发,没顾上写日志。本篇所述皆围绕为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绑定(实践篇)的更多相关文章

  1. 我的服装DRP之即时通讯——为WCF增加UDP绑定(应用篇)

    发个牢骚,博客园发博文竟然不能写副标题.这篇既为我的服装DRP系列第二篇,也给为WCF增加UDP绑定系列收个尾.原本我打算记录开发过程中遇到的一些问题和个人见解,不过写到一半发现要写的东西实在太多,有 ...

  2. 为WCF增加UDP绑定(储备篇)

    日前我开发的服装DRP需要用到即时通信方面的技术,比如当下级店铺开出零售单时上级机构能实时收到XX店铺XX时XX分卖出XX款衣服X件之类的信息,当然在上级发货时,店铺里也能收到已经发货的提醒.即时通信 ...

  3. WCF系统内置绑定列表与系统绑定所支持的功能

      WCF系统内置绑定列表 绑定 配置元素 说明 传输协议 编码格式 BasicHttpBinding <basicHttpBnding> 一个绑定,适用于与符合 WS-Basic Pro ...

  4. WCF 通讯标准绑定

    WCF 通讯标准绑定 一.预定义标准绑定 标准绑定 说明 BasicHttpBinding BasicHttpBinding 绑定用于最广泛的互交操作,针对第一代Web服务,所使用的传输协议是HTTP ...

  5. udp绑定信息

    1. udp网络程序-端口问题 会变的端口号 重新运行多次脚本,然后在“网络调试助手”中,看到的现象如下: 说明: 每重新运行一次网络程序,上图中红圈中的数字,不一样的原因在于,这个数字标识这个网络程 ...

  6. [WCF编程]6.绑定行为

    一.绑定行为概述 为了支持服务端的其它本地特性,WCF定义了行为的概念.行为就是服务的本地特性,不会影响服务的通信模式.客户端并不知道服务端行为,所以行为不会出现在服务的绑定和发布的元数据中.说下WC ...

  7. [WCF编程]5.绑定概述

    一.绑定概述 WCF提供了一个编程框架,可以抽象化服务创建的复杂过程.绑定允许开发人员将精力集中在问题本身上,而无需考虑如何创建允许系统运行的架构,因为WCF已经创建了架构. 绑定类型是开发人员控制W ...

  8. TCP、UDP绑定同一端口通信的解释

    昨日突然讨论起TCP与UDP是否可以在同一端口进行绑定,通信. 在印象当中我记得是可以的,今日google了相关资料, 确定以及肯定的: TCP.UDP可以绑定同一端口来进行通信: 网络中可以被命名和 ...

  9. WCF学习-协议绑定

    文章:无废话WCF入门教程三[WCF的宿主] 讲了net.tcp协议的wcf绑定.

随机推荐

  1. java中的反射机制和javaBean

    反射 反射:就是通过一个类加载进方法区时加载到栈内存中的Class字节码文件对这个类进行解剖 通过反射可以获取到一个类的构造方法,成员方法,成员变量 反射将一个类的各个部分映射成相应的类 反射获取构造 ...

  2. 普通用户授予root权限

    开始用linux的时候会遇到用户权限问题,比如安装软件的时候经常会提示权限不足,下面介绍给普通用户授予root权限. 找到  cd /etc/sudoers可以看到用户的权限是:只有读取的权限(以下操 ...

  3. identityserver4 对接钉钉

    参考了https://www.cnblogs.com/sheldon-lou/p/10643267.html

  4. NPE问题

    “防止 NPE,是程序员的基本修养.”NPE(Null Pointer Exception) 参考: https://www.jianshu.com/p/9915f2e34a13

  5. WebApi 路由机制剖析

    阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...

  6. java Twain 直接打印/界面打印

    这两天,在搞归档系统.需要用到Twain协议来驱动扫描仪. 找了两天,java的twain操作资料真的不多.而且我还是要找直接打印的功能. 后来只能静下心来看类库和源码.最后搞定他. 打印方式分为3种 ...

  7. centos lamp笔记

    cron and crontab are missing in docker image of ubuntu 16.04 在鏡像中沒有 cron 命令 How to install php-redis ...

  8. leetcode-227-基本计算器②

    题目描述: 方法一:中缀转后缀 #!_*_coding:utf-8_*_ class Solution: def calculate(self, s: str) -> int: def in_t ...

  9. Kunbernetes从私有仓库nexus拉取镜像

    1.docker登陆认证 [root@master ~]# vim /etc/docker/daemon.json { "insecure-registries": [" ...

  10. django-filter 实现过滤时查询是否包含在数组的方法,in数组的实现

    查了半天无解,还是在官网找到的,记录一下 使用 BaseInFilter 官网地址:https://django-filter.readthedocs.io/en/master/ref/filters ...