4WCF的前世今生.docx
《4WCF的前世今生.docx》由会员分享,可在线阅读,更多相关《4WCF的前世今生.docx(58页珍藏版)》请在冰点文库上搜索。
4WCF的前世今生
WCF的前世今生
太极计算机股份有限公司
TaijiComputerCorporation,Ltd
2013年7月
文档修订记录
文档安全
版本编号
说明:
如形成文件、变更内容和变更范围
日期
执行人
审核日期
审核人
V1.0
创建
2012-4-19
宋文凯
2012-04-26
张宏伟
V1.1
更新LOGO
2013-7-10
宋文凯
2013-07-10
张红斌
目录
1MSMQ消息队列5
1.1.MSMQ工作原理5
1.2.队列引用说明6
1.3.消息队列的优缺点7
1.4.利用MSMQ开发分布式应用(demo)7
1.4.1.准备环境7
1.4.2.使用MSMQ开发分布式应用9
1.4.3.运行演示11
2WebService13
2.1.WebService基本概念13
2.2.WebService的运行机理14
2.3.XMLWebService的特点14
2.4.WebService开发demo16
2.4.1.创建一个最简单的demo17
2.4.2.创建一个简单带有功能的webservice19
3Socket编程(C#)21
3.1.什么是TCP/IP、UDP?
22
3.2..NetFramework中的网络编程结构24
3.3..Net中Socket编程的必备基础25
3.4.Socket类工作原理27
3.5.C#描述的Socket编程实例29
4WCF、Netremoting、Webservice概念及区别33
4.1.WCF33
4.2.WebService的运行机理34
4.3..netRemoting35
4.4.区别35
4.4.1.传输协议和主机进程36
4.4.2.安全性36
4.4.3.状态管理37
4.4.4.性能38
4.4.5.企业服务38
4.5.小结39
1MSMQ消息队列
MSMQ全称是MicrosoftMessageQueue——微软消息队列。
它是一种异步传输模式,可以在不同的应用之间实现相互通信,相互通信的应用可以分布在同一台机器上,也可以分布于相连的网络空间中的任一位置。
1.1.MSMQ工作原理
MSMQ的实现原理是:
消息的发送者把自己想要发送的信息放入一个容器,然后把它保存到一个系统公用空间的消息队列中,本地或异地的消息接收程序再从该队列中取出发给它的消息进行处理。
消息队列是一个公用存储空间,它可以存在于内存中或物理文件中,因此,消息以两种方式发送,即快递方式和可恢复模式。
它们的区别是消息存储位置的不同,快递方式,为了消息的快速传递,所以把消息放置在内存中,而不放在物理磁盘上,以获得较高的处理能力;而可恢复模式在传送过程的每一步骤中,都把消息写入物理磁盘上,这样当保存消息队列的机器发生故障而重新启动后,可以把发送的消息恢复到故障发送之前的状态,以获得更好的消息恢复能力。
消息队列可以放在发送方、接收方所在的机器上,也可以单独放置在另外一台机器上。
另外,采用消息队列机制,发送方不必要担心接收方是否启动,是否发生故障等因素,只要消息成功发送出去,就可以认为处理完成,而实际上对方可能甚至未开机,或者实际消息传递到对方可能在第二天。
MSMQ机制类似QQ消息传递机制。
下图演示了MSMQ的实现原理。
MSMQ中主要有两个概念。
1.一个是消息Message:
Message是通信双方需要传递的消息,它可以是文本、图片、视频等。
消息包含发送和接收者的标识,只有指定的用户才能取得消息。
2.一个是队列Queue:
用来保存消息的存储空间,MSMQ中主要包括以下几种队列类型:
•公共队列:
在整个消息队列网络中复制,有可能由网络连接的所有站点访问。
路径格式为:
机器名称\队列名称
•专用队列(或叫私有队列):
不在整个网络中发布,它们仅在所驻留的本地计算机上可用,专用队列只能由知道队列的完整路径名称或标签的应用程序访问。
路径格式为:
机器名称\Private$\队列名称
•日志队列:
包含确认在给定“消息队列中发送的消息回执消息”。
路径格式为:
机器名称\队列名称\Journal$
响应队列:
包含目标应用程序接收到消息时返回给发送应用程序的响应消息,包括机器日志队列、机器死信队列和机器事务死信队列。
a)•机器日志队列对应的格式为:
机器名称\Journal$;
b)•机器死信队列对应的格式为:
机器名称\Deadletter$;
c)•机器信道死信队列对应的格式为:
机器名称\XactDeadletter$。
1.2.队列引用说明
当创建了一个MessageQueue实例之后,就应指明和哪个队列进行通信,在.NET中有3种访问指定消息队列的方法:
•使用路径,消息队列的路径被机器名和队列名唯一确定,所以可以用消息队列路径来指明使用的消息队列。
•使用格式名(formatname),它是由MSMQ在消息队列创建时生成的唯一标识,格式名不由用户指定,而是由队列管理者自动生成的GUID。
•使用标识名(label),它是消息队列创建时由消息管理者指定的带有意义的名字。
1.3.消息队列的优缺点
采用消息队列的好处是:
由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代码,大大提高了处理的能力;在信息传递过程中,具有故障恢复能力;MSMQ的消息传递机制使得通信的双方具有不同的物理平台成为可能。
消息队列缺点是不适合Client需要Server端实时交互情况,大量请求时候,响应可能延迟。
1.4.利用MSMQ开发分布式应用(demo)
1.4.1.准备环境
要想在.NET平台进行MSMQ的开发,需要安装消息队列,你需要打开控制面板->程序->打开或关闭Windows功能,勾选消息队列服务所有选项,具体操作如下图所示:
勾选完之后点击确定之后,可以在我的电脑->管理->服务和应用程序->消息队列看到下面的图:
看到上面这个图代表你已经成功配置了MSMQ的开发环境,下面就可以使用VisualStudio进行开发。
注意,对特定类型队列的操作代码,一定要成功安装对应的队列类型。
1.4.2.使用MSMQ开发分布式应用
首先,实现服务器端。
创建一个控制台项目,添加System.Messaging引用,因为消息队列的类全部封装在System.Messaging.dll程序集里。
具体服务端的代码如下:
usingSystem;
usingSystem.Messaging;
namespaceMSMQServer
{
classProgram
{
staticvoidMain(string[]args)
{
//创建一个公共队列,公共队列只能创建在域环境里
//if(!
MessageQueue.Exists(@".\LearningHardMSMQ"))//判断此路径下是否已经有该队列
//{
//using(MessageQueuemq=MessageQueue.Create(@".\LearningHardMSMQ"))
//{
//mq.Label="LearningHardQueue";//设置队列标签
//Console.WriteLine("已经创建了一个公共队列");
//Console.WriteLine("路径为:
{0}",mq.Path);
//Console.WriteLine("队列名字为:
{0}",mq.QueueName);
//mq.Send("MSMQMessage","LeaningHard");//发送消息
//}
//}
//if(MessageQueue.Exists(@".\Private$\LearningHardMSMQ"))
//{
//删除消息队列
//MessageQueue.Delete(@".\Private$\LearningHardMSMQ");
//}
//创建一个私有消息队列
if(!
MessageQueue.Exists(@".\Private$\LearningHardMSMQ"))
{
using(MessageQueuemq=MessageQueue.Create(@".\Private$\LearningHardMSMQ"))
{
mq.Label="LearningHardPrivateQueue";
Console.WriteLine("已经创建了一个私有队列");
Console.WriteLine("路径为:
{0}",mq.Path);
Console.WriteLine("私有队列名字为:
{0}",mq.QueueName);
mq.Send("MSMQPrivateMessage","LeaningHard");//发送消息
}
}
//遍历所有的公共消息队列
//foreach(MessageQueuemqinMessageQueue.GetPublicQueues())
//{
//mq.Send("SendingMSMQpublicmessage"+DateTime.Now.ToLongDateString(),"LearningHard");
//Console.WriteLine("PublicMessageissentto{0}",mq.Path);
//}
if(MessageQueue.Exists(@".\Private$\LearningHardMSMQ"))
{
//获得私有消息队列
MessageQueuemq=newMessageQueue(@".\Private$\LearningHardMSMQ");
mq.Send("SendingMSMQprivatemessage"+DateTime.Now.ToLongDateString(),"LeaningHard");
Console.WriteLine("PrivateMessageissentto{0}",mq.Path);
}
Console.Read();
}
}
}
服务器端代码需要注意的是,公共队列只能在域环境中创建,由于我的个人电脑没有加入域环境,所以不能创建公共队列,从开始的消息队列的截图也可以看出,在图中并没有安装公共队列。
实现完服务器端之后,自然就是完成客户端。
MSMQ程序的原理主要是:
服务器端把消息发送到共享的消息队列中,然后,客户端从这个共享的消息队列中取出消息进行处理。
具体客户端的实现代码如下所示:
usingSystem;
usingSystem.Messaging;//需要添加System.Messaging引用
namespaceMSMQClient
{
classProgram
{
staticvoidMain(string[]args)
{
if(MessageQueue.Exists(@".\Private$\LearningHardMSMQ"))
{
//创建消息队列对象
using(MessageQueuemq=newMessageQueue(@".\Private$\LearningHardMSMQ"))
{
//设置消息队列的格式化器
mq.Formatter=newXmlMessageFormatter(newstring[]{"System.String"});
foreach(Messagemsginmq.GetAllMessages())
{
Console.WriteLine("ReceivedPrivateMessageis:
{0}",msg.Body);
}
Messagefirstmsg=mq.Receive();//获得消息队列中第一条消息
Console.WriteLine("ReceivedThefirstPrivateMessageis:
{0}",firstmsg.Body);
}
}
Console.Read();
}
}
}
1.4.3.运行演示
经过上面步骤,我们已经完成了MSMQ分布式程序的实现了,下面看看如何运行该程序来查看效果。
首先,自然要启动服务器,右键MSMQServer项目->调试->启动新实例来启动服务器,具体步骤如下图所示:
运行成功之后,你将到服务器发送消息成功的控制台界面,效果图如下所示:
接下来运行客户端来从消息队列中取得消息并显示在控制台中,看到客户端的效果如下图所示:
从上图可以看出,客户端确实成功地取得了消息队列中的消息。
以上MSMQ程序需要特别注意是:
MessageQueue.Receive()是取出消息队列中队列中的第一条消息,并从消息队列中移除它(MSDN中文翻译上是错误,MSDN写的是不移除,而英文原文是移除),而实际结果也是移除的,如果你再运行一次客户端时,你会发现消息队列中只有一条消息,具体运行效果如下图所示:
2.NETRemoting
2.1..NETRemoting简介
.NETREmoting与MSMQ不同,它不支持离线可得,另外只适合.NET平台的程序进行通信。
它提供了一种允许对象通过应用程序域与另一个对象进行交互的框架。
.NET应用程序都在一个主应用程序域中执行的,在一个应用程序域中的代码不能访问另一个应用程序域的数据,然而在某些情况下,我们需要跨应用程序域,与另外的应用程序域进行通信,这时候就可以采用.NETRemoting技术来实现与另一个程序域中的对象进行交互。
2.2..NETRemoting基本原理
.NETRemoting技术是通过通道来实现两个应用程序之间对象的通信的。
首先,客户端通过Remoting技术,访问通道来获得服务器端对象,再通过代理解析为客户端对象,也称作透明代理,此时获得客户端对象只是服务器对象的一个引用。
这既保证了客户端和服务端有关对象的松散耦合,同时优化了通信的性能。
在这个过程中,当客户端通过透明代理来调用远程对象的方法时,此时会将调用封装到一个消息对象中,该消息对象包括远程对象信息,被调用的方法名和参数,然后透明代理会将调用委托给真实代理(RealProxy对象)的Invoke方法来生成一个IMethodCallMessage,接着通过序列化把这个消息对象序列化成数据流发送到通道,通道会把数据流传送到服务器端。
当服务器接收到经过格式化的数据之后,首先从中通过反序列化来还原消息对象,之后在服务器端来激活远程对象,并调用对应的方法,而方法的返回结果过程则是按照之前的方法反向重复一遍,具体的实现原理图如下所示:
2.3..NETRemoting几个重要概念
上面简单介绍了下.NETRemoting实现分布式应用程序的基本原理,这里介绍下在.NETRemoting中涉及的几个重要概念。
1.远程对象:
是运行在服务器端的对象,客户端不能直接调用,由于.NETRemoting传递的对象是以引用的方式,因此所传递的远程对象必须继承MarshalByRefObject类,这个类可以使远程对象在.NETRemoting应用通信中使用,支持对象的跨域边界访问。
2.远程对象的激活方式:
在访问服务器端的一个对象实例之前,必须通过一个名为Activation的进程创建它并进行初始化。
这种客户端通过通道来创建远程对象的方式称为对象的激活。
在.NETRemoting中,远程对象的激活分为两大类:
服务器端激活和客户端激活。
•服务器端激活,又叫做WellKnow(知名对象)激活模式,为什么称为知名对象激活模式呢?
是因为服务应用程序在激活对象实例之前会在一个众所周知的统一资源标示符(URI)上发布这个类型,然后该服务器进行会为此类型配置一个WellKnow对象,并根据指定的端口或地址来发布对象。
.NETRemoting把服务器端激活又分为SingleTon模式和SingleCall模式两种。
SingleTon模式:
此为有状态模式。
如果设置为SingleTon激活模式,则.NETRemoting将为所有客户端建立同一个对象实例。
当对象处于活动状态时,SingleTon实例会处理所有后来的客户端访问请求,而不管它们是同一个客户端,还是其他客户端。
SingleTon实例将在方法调用中一直维护其状态,类似static成员的概念
SingleCall模式:
是一种无状态模式。
一旦设置为SingleCall模式,则当客户端调用远程对象的方法时,Remoting会为每一个客户端建立一个远程对象实例,对象实例的销毁则是由GC自动管理。
类似实例成员的概念。
•客户端激活:
与Wellknow模式不同,。
NETRemoting在激活每个对象实例的时候,会给每个客户端激活的类型指派一个URI。
客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用。
SingleCall模式与客户端激活模式的区别有:
首先,对象实例创建的时间不同。
客户端激活方式是客户一旦发出调用请求就实例化,而SingleCall则要等到调用对象方法时再创建。
其次,SingleCall模式激活的对象是无状态的,对象声明周期由GC管理,而客户端激活的对象是有状态的,其生命周期可自定义。
第三,两种激活模式在服务器端和客户端实现的方法不一样,尤其是在客户端,SingleCall模式由GetObject()来激活,它调用对象默认的构造函数,而客户端激活模式,则通过CreateInstance()来激活,它可以传递参数,所以可以调用自定义的构造函数来创建实例。
3.通道:
在.NETRemoting中时通过通道来实现两个应用程序域之间对象的通信。
.NETRemoting中包括4中通道类型:
1.TcpChannel:
Tcp通道使用Tcp协议来跨越.NetRemoting边界来传输序列化的消息流,TcpChannel默认使用二进制格式序列化消息对象,因此具有更高的传输性能,但不提供任何内置的安全功能。
2.HttpChannel:
Http通道使用Http协议在客户端和服务器之间发生消息,使其在Internet上穿越防火墙来传输序列化的消息流(这里准确讲不能说穿越,主要是因为防火墙都开放了80端口,所以使用Http协议可以穿过防火墙进行数据的传输,如果防火墙限制了80端口,Http协议也照样不能穿越防火墙)。
默认情况下,HttpChannel使用Soap格式序列化消息对象,因此它具有更好的互操作性,并且可以使用Http协议中的加密机制来对消息进行加密来保证安全性。
因此,通常在局域网内,我们更多地使用TcpChannel,如果要穿越防火墙,则使用HttpChannel。
3.IpcChannel:
进程间通信,只使用同一个系统进程之间的通信,不需要主机名和端口号。
而使用Http通道和Tcp通道都要指定主机名和端口号。
4.自定义通道:
自定义的传输通道可以使用任何基本的传输协议来进行通信,如UDP协议、SMTP协议等。
2.4.利用.NETRemoting技术开发分布式应用
前面详细介绍了.NETRemoting相关内容,下面具体看看如何使用.NETRemoting技术来开发分布式应用程序。
开发.NETRemoting应用分三步走。
第一步:
创建远程对象,该对象必须继承MarshalByRefObject对象。
具体的示例代码如下:
namespaceRemotingObject
{
//第一步:
创建远程对象
//创建远程对象——必须继承MarshalByRefObject,该类支持对象的跨域边界访问
publicclassMyRemotingObject:
MarshalByRefObject
{
//用来测试Tcp通道
publicintAddForTcpTest(inta,intb)
{
returna+b;
}
//用来测试Http通道
publicintMinusForHttpTest(inta,intb)
{
returna-b;
}
//用来测试IPC通道
publicintMultipleForIPCTest(inta,intb)
{
returna*b;
}
}
}
远程对象分别定义3个方法,目的是为了测试3中不同的通道方式的效果。
第二步:
创建服务器端,需要添加System.Runtime.Remoting.dll引用,具体实现代码如下所示:
usingSystem;
usingSystem.Runtime.Remoting;
usingSystem.Runtime.Remoting.Channels;
usingSystem.Runtime.Remoting.Channels.Http;
usingSystem.Runtime.Remoting.Channels.Ipc;
usingSystem.Runtime.Remoting.Channels.Tcp;
namespaceRemotingServerHost
{
//第二步:
创建宿主应用程序
classServer
{
staticvoidMain(string[]args)
{
//1.创建三种通道
//创建Tcp通道,端口号9001
TcpChanneltcpChannel=newTcpChannel(9001);
//创建Http通道,端口号9002
HttpChannelhttpChannel=newHttpChannel(9002);
//创建IPC通道,端口号9003
IpcChannelipcChannel=newIpcChannel("IpcTest");
//2.注册通道
ChannelServices.RegisterChannel(tcpChannel,false);
ChannelServices.RegisterChannel(httpChannel,false);
ChannelServices.RegisterChannel(ipcChannel,false);
//打印通道信息
//打印Tcp通道的名称
Console.WriteLine("ThenameoftheTcpChannelis{0}",tcpChannel.ChannelName);
//打印Tcp通道的优先级
Console.WriteLine("ThepriorityoftheTcpChannelis{0}",tcpChannel.C