虽然在目前项目开发中在使用WCF,但是一直没有系统的学习过。希望自己从现在开始能把WCF梳理一遍!希望和大家一起学习,一起进步。
1.概述
2.WCF契约设计--服务契约(Service Contracts)
3.WCF契约版本处理
4.异常与错误处理
5.绑定(Bingdings)
6.宿主(Hosting)
7.消息模式
8.实例模式
9.并发、吞吐量与限流
posted @ 2009-01-06 22:59 Tzot 阅读(53) 评论(0) 编辑
|
|||
|
虽然在目前项目开发中在使用WCF,但是一直没有系统的学习过。希望自己从现在开始能把WCF梳理一遍!希望和大家一起学习,一起进步。 1.概述 2.WCF契约设计--服务契约(Service Contracts) 3.WCF契约版本处理 4.异常与错误处理 5.绑定(Bingdings) 6.宿主(Hosting) 7.消息模式 8.实例模式 9.并发、吞吐量与限流 posted @ 2009-01-06 22:59 Tzot 阅读(53) 评论(0) 编辑 更新时间:2009-01-06 服务契约(Service Contracts) ServiceContract– 定义服务操作 应用于接口或者类中,并使用接口(或类)上的 ServiceContractAttribute 属性定义服务协定。 MSDN备注:使用 ServiceContractAttribute 修饰的接口或类还必须至少拥有一个用 OperationContractAttribute 属性标记的方法以公开任意功能。 • Name,指定 WSDL <portType> 元素中的协定名称。 • Namespace,指定 WSDL <portType> 元素中的命名空间。 • SessionMode,指定协定是否需要支持会话的绑定。 • ConfigurationName,指定要使用的配置文件中的服务元素的名称。 • CallbackContract,指定双向(双工)对话中的返回协定。 • HasProtectionLevel 和ProtectionLevel,指示是否所有支持协定的消息都具有一个显式 ProtectionLevel 值,如果有,处于什么级别。
-------------------------------------解决方案------------------------------------------------------
-------------------------------------服务契约------------------------------------------------------ /// <summary> /// 人员管理接口 /// </summary> // Namespace - 服务契约的命名空间,在WSDL中体现。 // Name - 服务契约的名称,在WSDL中体现。 // ConfigurationName - 服务契约在宿主中所配置的服务名称(默认情况下本例为类的全名“TZOT.WCF.Contract.IPersonManagerService”) [ServiceContract(Namespace="http://www.cnblogs.com/netlife", Name="PersonManager", ConfigurationName="PersonManagerConfig")] public interface IPersonManagerService { /// <summary> /// 获取某人的姓名 /// </summary> /// <param name="person">Person对象</param> /// <returns>对应的名字</returns> // Name - 操作契约的名称(会对应到相关的wsdl,默认情况下本例为方法名“GetName”) [OperationContract(Name = "GetPersonName")] string GetName(Person person); } -------------------------------------数据契约------------------------------------------------------ /// <summary> /// Person的实体类 /// </summary> // Name - 数据契约的名称(会对应到相关的wsdl,默认情况下本例为类名“Person”) [DataContract(Name = "PersonModel")] public class Person { /// <summary> /// Person的实体类的Age属性 /// </summary> // Name - 数据成员的名称(会对应到相关的wsdl,默认情况下本例为属性名“Age”) // IsRequired - 该值指示序列化引擎该成员在读取或反序列化时必须存在 // Order - 数据成员在相关的wsdl中的顺序 // EmitDefaultValue - 如果应该在序列化流中生成成员的默认值,则为 true,否则为 false,默认值为 true [DataMember(Name = "PersonAge", IsRequired = false, Order = 1)] public int Age { get; set; } /// <summary> /// Person的实体类的Name属性 /// </summary> // Name - 数据成员的名称(会对应到相关的wsdl,默认情况下本例为属性名“Name”) // IsRequired - 该值指示序列化引擎该成员在读取或反序列化时必须存在 // Order - 数据成员在相关的wsdl中的顺序 // EmitDefaultValue - 如果应该在序列化流中生成成员的默认值,则为 true,否则为 false,默认值为 true [DataMember(Name = "PersonName", IsRequired = false, Order = 0)] public string Name { get; set; } } -------------------------------------Hosting App.Config------------------------------------------------------ <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="serviceBehavior"> <serviceMetadata httpGetEnabled="true" httpGetUrl=""/> </behavior> </serviceBehaviors> </behaviors> <services> <service name="TZOT.WCF.BusinessServices.PersonManagerService" behaviorConfiguration="serviceBehavior"> <endpoint address="" contract="PersonManagerConfig" binding="basicHttpBinding"/> <!--contract= 是服务契约中配置的ConfigurationName “PersonManagerConfig”,为我们在服务契约中配置的代码。--> <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> <host> <baseAddresses> <add baseAddress="http://localhost:8000/PersonManagerService/" /> </baseAddresses> </host> </service> </services> </system.serviceModel> -------------------------------------启动服务------------------------------------------------------ class Program { static void Main(string[] args) { //提供服务的主机 ServiceHost personManagerServiceHosting = null; try { personManagerServiceHosting = new ServiceHost(typeof(PersonManagerService)); personManagerServiceHosting.Open(); Console.WriteLine(); Console.WriteLine("Press <ENTER> to terminate Host"); Console.ReadLine(); } finally { personManagerServiceHosting.Close(); } } } -------------------------------------客户端App.Config------------------------------------------------------ <client> <endpoint address="http://localhost:8000/PersonManagerService/" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_PersonManager" contract="PersonManagerSerivceRefrence.PersonManager" name="BasicHttpBinding_PersonManager" /> </client> -------------------------------------客户端添加服务自动生成的部分代码------------------------------------------------------ 可以发现自动生成的接口名字为“PersonManager ”,即在服务契约中Name="PersonManager"的体现。 可以发现自动生成的命名空间为Namespace=http://www.cnblogs.com/netlife。 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] [System.ServiceModel.ServiceContractAttribute(Namespace="http://www.cnblogs.com/netlife", ConfigurationName="PersonManagerSerivceRefrence.PersonManager")] public interface PersonManager { [System.ServiceModel.OperationContractAttribute(Action="http://www.cnblogs.com/netlife/PersonManager/GetPersonName", ReplyAction="http://www.cnblogs.com/netlife/PersonManager/GetPersonNameResponse")] string GetPersonName(TZOT.WCF.Client.PersonManagerSerivceRefrence.PersonModel person); } posted @ 2009-01-06 22:46 Tzot 阅读(422) 评论(0) 编辑 NAT 类型及检测方法
STUN协议是一个客户机/服务器协议,在公网上存在着大量的STUN服务器,用户可以通过在自己主机上运行STUN客户端远程连接STUN服务器来确认自身的网络状况. 客户端主机所在网络可以分为以下类型: 1, Opened: 即主机拥有公网IP,并且没有防火墙,可自由与外部通信. 2, Full Cone NAT: 主机前有NAT设备,NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,并且从任意外部地址发送到该NAT设备UDP端口B的包都会被转到主机端口A. 3, Restricted cone NAT: 主机前有NAT设备,NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,但只有从之前该主机发出包的目的IP发出到该NAT设备UDP端口B的包才会被转到主机端口A. 4, Port Restricted cone NAT: 主机前有NAT设备,NAT规则如下:从主机UDP端口A发出的数据包都会对应到NAT设备出口IP的端口B,但只有从之前该主机发出包的目的IP/PORT发出到该NAT设备UDP端口B的包才会被转到主机端口A. 5, Symmetric UDP Firewall: 主机出口处没有NAT设备,但有防火墙,且防火墙规则如下:从主机UDP端口A发出的数据包保持源地址,但只有从之前该主机发出包的目的IP/PORT发出到该主机端口A的包才能通过防火墙. 6, Symmetric NAT: 主机前有NAT设备,NAT规则如下:即使数据包都从主机UDP端A发出,但只要目的地址不同,NAT设备就会为之分配不同的出端口B. 7, Blocked: 防火墙限制UDP通信.
1 /// <summary>
2 /// Specifies UDP network type. 3 /// </summary> 4 public enum STUN_NetType 5 { 6 /// <summary> 7 /// UDP is always blocked. 8 /// </summary> 9 UdpBlocked, 10 11 /// <summary> 12 /// No NAT, public IP, no firewall. 13 /// </summary> 14 OpenInternet, 15 16 /// <summary> 17 /// No NAT, public IP, but symmetric UDP firewall. 18 /// </summary> 19 SymmetricUdpFirewall, 20 21 /// <summary> 22 /// A full cone NAT is one where all requests from the same internal IP address and port are 23 /// mapped to the same external IP address and port. Furthermore, any external host can send 24 /// a packet to the internal host, by sending a packet to the mapped external address. 25 /// </summary> 26 FullCone, 27 28 /// <summary> 29 /// A restricted cone NAT is one where all requests from the same internal IP address and 30 /// port are mapped to the same external IP address and port. Unlike a full cone NAT, an external 31 /// host (with IP address X) can send a packet to the internal host only if the internal host 32 /// had previously sent a packet to IP address X. 33 /// </summary> 34 RestrictedCone, 35 36 /// <summary> 37 /// A port restricted cone NAT is like a restricted cone NAT, but the restriction 38 /// includes port numbers. Specifically, an external host can send a packet, with source IP 39 /// address X and source port P, to the internal host only if the internal host had previously 40 /// sent a packet to IP address X and port P. 41 /// </summary> 42 PortRestrictedCone, 43 44 /// <summary> 45 /// A symmetric NAT is one where all requests from the same internal IP address and port, 46 /// to a specific destination IP address and port, are mapped to the same external IP address and 47 /// port. If the same host sends a packet with the same source address and port, but to 48 /// a different destination, a different mapping is used. Furthermore, only the external host that 49 /// receives a packet can send a UDP packet back to the internal host. 50 /// </summary> 51 Symmetric 52 }
测试过程 STUN服务器运行在UDP协议之上,它具有两个固定公网地址,能完成以下几个功能: 1. 告诉STUN客户端经NAT设备映射后的公网地址. 2. 根据STUN客户端的要求,从服务器的其他不同IP或端口向客户端回送包. 如何根据STUN服务器提供的功能来确认网络类型呢? rfc3489给出了如下图过程: 这个过程可概括如下: 1, STUN客户端向STUN服务器发送请求,要求得到自身经NAT映射后的地址: a,收不到服务器回复,则认为UDP被防火墙阻断,不能通信,网络类型:Blocked. b,收到服务器回复,对比本地地址,如果相同,则认为无NAT设备,进入第2步,否则认为有NAT设备,进入3步. 2, (已确认无NAT设备)STUN客户端向STUN服务器发送请求,要求服务器从其他IP和PORT向客户端回复包: a,收不到服务器从其他IP地址的回复,认为包被前置防火墙阻断,网络类型:Symmetric UDP Firewall. b,收到则认为客户端处在一个开放的网络上,网络类型:Opened. 3, (已确认存在NAT设备)STUN客户端向STUN服务器发送请求,要求服务器从其他IP和PORT向客户端回复包: a,收不到服务器从其他IP地址的回复,认为包被前置NAT设备阻断,进入第4步. b,收到则认为NAT设备类型为Full Cone,即网络类型:Full Cone NAT. 4, STUN客户端向STUN服务器的另外一个IP地址发送请求,要求得到自身经NAT映射后的地址,并对比之: a,地址不相同,则网络类型:Symmetric NAT. b,相同则认为是Restricted NAT,进入第5步,进一步确认类型. 5, (已确认Restricted NAT设备)STUN客户端向STUN服务器发送请求,要求服务器从相同IP的其他PORT向客户端回复包: a,收不到服务器从其他PORT地址的回复,认为包被前置NAT设备阻断,网络类型:Port Restricted cone NAT. b,收到则认为网络类型: Restricted cone NAT. posted @ 2008-10-10 16:29 Tzot 阅读(1741) 评论(1) 编辑 以下主要内容取之WebCast 从耦合关系谈起 耦合关系直接决定着软件面对变化时的行为 – 模块与模块之间的紧耦合使得软件面对变化时,相关的模块都要随之更改。 – 模块与模块之间的松耦合使得软件面对变化时,一些模块更容易被替换或者。 动机(Motivation) 意图(Intent) 结构(Structure)
Factory Method模式的几个要点 posted @ 2008-09-27 11:29 Tzot 阅读(146) 评论(0) 编辑 动机(Motivation) 在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。 意图(Intent) 抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象。 适用性 文献【GOF95】指出,在以下情况下应当考虑使用工厂模式: 结构(Structure) 代码实现
1
public abstract class ProductA2 {3 4 }5 ![]() 6 public class ProductA1 : ProductA7 {8 ![]() 9 }10 ![]() 11 public class ProductA2 : ProductA12 {13 ![]() 14 }15 ![]() 16 public abstract class ProductB17 {18 ![]() 19 }20 ![]() 21 public class ProductB1 : ProductB22 {23 ![]() 24 }25 ![]() 26 public class ProductB2 : ProductB27 {28 ![]() 29 }
1
public abstract class Creator2 {3 }4 ![]() 5 public abstract class ConcreteCreatorA : Creator6 {7 public ProductA FactoryA()8 {9 return new ProductA1();10 }11 ![]() 12 public ProductB FactoryB()13 {14 return new ProductB1();15 }16 }17 ![]() 18 public abstract class ConcreteCreatorB : Creator19 {20 public ProductA FactoryA()21 {22 return new ProductA2();23 }24 ![]() 25 public ProductB FactoryB()26 {27 return new ProductB2();28 }29 }
Abstract Factory模式的几个要点 posted @ 2008-09-15 17:57 Tzot 阅读(118) 评论(0) 编辑 原文地址:http://e2tox.cnblogs.com/archive/2006/07/13/449836.html UPNP的全称是 Universal plug-and-play( 通用即插即用).UPnP 是针对智能家电、无线设备以及各种外观尺寸的个人电脑的普遍对等(peer-to-peer)网络连接而设计的一种架构。它旨在为家庭、小型企业、公共场所中或连接到互联网的ad-hoc 网或未管理网络提供易于使用、灵活且基于标准的连接。(引自这里.) 我们这里用到的自动端口映射只是UPNP的一个小应用。按照UPNP的相关规范,UPNP网络的第0步是寻址(获得一个IP地址,在我要解决的问题中这不是一个问题。) M-SEARCH * HTTP/1.1 这个多播请求的含义如下:M-SEARCH SSDP协议定义的搜索请求方法。HOST必须是这个多播地址。MAN的值也必须是"ssdp:discover" 不可少了双引号。MX的含义是最长等待时间,可以自己设置。ST表示search target 搜索目标。我们在这里用找根设备。另外在编程中我们要在每一行后面加上"rn" 表示换行。(详见源码 UPNPNAT.discovery()). 第二步,如果你的网络存在一个UPNP设备的话,为了被找到,设备必须向发送查找请求的多播通道的源 IP 地址与端口发送响应信息。所以你可以从239.255.255.250:1900这个地址接收到响应消息。类似下面的消息。 HTTP/1.1 200 OK 接下来我们要从里面获得我们要的消息。首先,我们必须找到" 200 OK ",说明没有错误发生,否则一切免谈。接着,我们要找到LOCATION项,获得设备描述URL。(程序中的处理归根到底就是一个子字符的查找。) 到这里,我们的第一步“发现”完成。 GET path HTTP/1.1 的信息(第二行下要一个空行),并通过刚才的TCP 套接字,发送到路由器。(sprintf ,send 函数). 4.接收数据,我使用flag为 MSG_WAITALL的recv函数,函数一直阻塞直到数据全部读完。 数据最终保存在std::string description_info中。 我想通过浏览器下载这个文件的过程是类似的吧。 然后,解析这个XML文件。(请看源码 中UPNPNAT:: parser_description()函数) 我们找到"root"的"deviceType"是"urn:schemas-upnp-org:device:InternetGatewayDevice:1"的"device" childNode ,获得这个"device"的"deviceList",记为A。 找到A的"deviceType"是"urn:schemas-upnp-org:device:WANDevice:1"的"device" childNode ,获得这个"device"的"deviceList",记为B。 找到B的"deviceType"是"urn:schemas-upnp-org:device:WANConnectionDevice:1"的"device" childNode ,获得这个"device"的"serviceList",记为C。 找到C的"serviceType"是"urn:schemas-upnp-org:service:WANIPConnection:1" 或"urn:schemas-upnp-org:service:WANPPPConnection:1" 的"service" childNode ,记为D. 但是这里获得control_url一般为相对URL,所以要从"root"下面,找到"URLBase"的值,(如果是空,则用describe_url的"htpp://xxx.xxx.xxx.xxx:xxxx"部分代替.) 最后在相对的control_url前加上URLBasr 获得完整的control_url. 至此,第二步“获得控制URL”完成。 第3步是控制。通过第2步获得的控制URL,通过向其发送控制消息(同样用XML描述)来实现某些功能。对于自动端口映射来说就是查看、增加、删除等。
其中斜体部分需要在编程是填入的。ExternalPort 外部端口。InternalPort内部端口。这 两者一般就填映射的端口。Protocal 填TCP或UDP。InterClient 一般就是本地IP地址。PortMappingDescription 填写端口映射的描述,比如什么程序建立了这个端口。LeaseDuration 是映射的持续时间,用0表示不永久。PortMappingIndex 是端口映射索引,路由上第几个映射。 我们再来看下面这个XML文档结构。 "<?xml version="1.0" encoding="utf-8"?>rn" 我们在actionName 处填入"AddPortMapping" "DeletePortMapping" "GetGenericPortMappingEntry"。serviceType 处填入设备的服务类型。"urn:schemas-upnp-org:service:WANIPConnection:1"或"urn:schemas-upnp-org:service:WANPPPConnection:1"。actionParams 填入上面的各种控制信息。 最后在前面加上HTTP头。 "POST path HTTP/1.1rn" path host port 意思很明显。contentLength面那个XML文档的长度。 然后连接到host:port,发送到整个信息即可完成控制 第4步事件触发和第5步展示在自动端口映射没用用到。有兴趣可以自己看文档。 posted @ 2008-09-08 17:08 Tzot 阅读(396) 评论(0) 编辑 原文转自:http://blog.csdn.net/colinchan/archive/2006/05/08/712773.aspx 一:基本术语 防火墙 防火墙限制了私网与公网的通信,它主要是将(防火墙)认为未经授权的的包丢弃,防火墙只是检验包的数据,并不修改数据包中的IP地址和TCP/UDP端口信息。 网络地址转换(NAT) 当有数据包通过时,网络地址转换器不仅检查包的信息,还要将包头中的IP地址和端口信息进行修改。以使得处于NAT之后的机器共享几个仅有的公网IP地址(通常是一个)。网络地址转换器主要有两种类型. P2P应用程序 P2P应用程序是指,在已有的一个公共服务器的基础上,并分别利用自己的私有地址或者公有地址(或者两者兼备)来建立一个端到端的会话通信。 P2P防火墙 P2P防火墙是一个提供了防火墙的功能的P2P代理,但是不进行地址转换. P2P-NAT P2P-NAT 是一个 P2P代理,提供了NAT的功能,也提供了防火墙的功能,一个最简的P2P代理必须具有锥形NAT对Udp通信支持的功能,并允许应用程序利用Udp打洞技术建立强健的P2P连接。 回环转换 当NAT的私网内部机器想通过公共地址来访问同一台局域网内的机器的时,NAT设备等价于做了两次NAT的事情,在包到达目标机器之前,先将私有地址转换为公网地址,然后再将公网地址转换回私有地址。我们把具有上叙转换功能的NAT设备叫做“回环转换”设备。 二:NAT分类 可以分为基础NAT与网络地址和端口转换(NAPT)两大类 (一):基础NAT 基础NAT 将私网主机的私有IP地址转换成公网IP地址,但并不将TCP/UDP端口信息进行转换。基础NAT一般用在当NAT拥有很多公网IP地址的时候,它将公网IP地址与内部主机进行绑定,使得外部可以用公网IP地址访问内部主机。(实际上是只将IP转换,192.168.0.23 <-> 210.42.106.35,这与直接设置IP地址为公网IP还是有一定区别的,特别是对于企业来说,外部的信息都要经过统一防火墙才能到达内部,但是内部主机又可以使用公网IP) (二):网络地址和端口转换 (NAPT) 这是最普遍的情况,网络地址/端口转换器检查、修改包的IP地址和TCP/UDP端口信息,这样,更多的内部主机就可以同时使用一个公网IP地址。 请参考[RFC1631]和[RFC2993]及[RFC2663]这三个文档了解更多的NAT分类和术语信息。另外,关于NAPT的分类和术语,[RFC2663]做了更多的定义。当一个内部网主机通过NAT打开一个“外出”的TCP或UDP会话时,NAPT分配给这个会话一个公网IP和端口,用来接收外网的响应的数据包,并经过转换通知内部网的主机。这样做的效果是,NAPT在 [私有IP:私有端口] 和[公网IP:公网端口]之间建立了一个端口绑定。 端口绑定指定了NAPT将在这个会话的生存期内进行地址转换任务。这中间存在一个这样的问题,如果P2P应用程序从内部网络的一个[私有IP地址:端口]对同时发出多条会话给不同的外网主机,那么NAT会怎样处理呢?这又可以分为锥形NAT (CONE NAT)与对称NAT (SYMMTRIC NAT)两大类来考虑: A.锥形NAT (为什么叫做锥形呢?请看以下图形,终端和外部服务器,都通过NAT分派的这个绑定地址对来传送信息,就象一个漏斗一样,筛选并传递信息) 当建立了一个 [私有IP:端口]-[公网IP:端口] 端口绑定之后,对于来自同一个[私有IP:端口]会话,锥形NAT服务器允许发起会话的应用程序 重复使用这个端口绑定,一直到这个会话结束才解除(端口绑定)。 例如,假设 Client A(IP地址信息如上图所示)通过一个锥形NAT 同时发起两个外出的连接,它使用同一个内部端口(10.0.0.1:1234)给公网的两台不同的服务器,S1和S2。锥形NAT 只分配一个公网IP和端口(155.99.25.11:62000)给这个两个会话,通过地址转换可以确保 Client使用端口的“同一性”(即这个Client只使用这个端口)。而基础NATs和防火墙却不能修改经过的数据包端口号,它们可以看作是锥形NAT的精简版本。 进一步分析可以将CONE NAT受限制锥形NAT (RESTRICT CONE) 与端口受限锥形NAT (PORT RESTRICT CONE) 三大类,以下是详细论述: 分为全双工锥形NAT (FULL CONE) , 1.全双工锥形NAT 当内部主机发出一个“外出”的连接会话,就会创建了一个公网/私网 地址,一旦这个地址对被创建,全双工锥形NAT会接收随后任何外部端口传入这个公共端口地址的通信。因此,全双工锥形NAT有时候又被称为"混杂"NAT。 2.受限制锥形NAT 受限制的锥形NAT会对传入的数据包进行筛选,当内部主机发出“外出”的会话时,NAT会记录这个外部主机的IP地址信息,所以,也只有这些有记录的外部IP地址,能够将信息传入到NAT内部,受限制的锥形NAT 有效的给防火墙提炼了筛选包的原则——即限定只给那些已知的外部地址“传入”信息到NAT内部。 3.端口受限锥形NAT 端口受限制的锥形NAT,与受限制的锥形NAT不同的是:它同时记录了外部主机的IP地址和端口信息,端口受限制的锥形NAT给内部节点提供了同一级别的保护,在维持端口“同一性”过程中,将会丢弃对称NAT传回的信息。 B.对称NAT 对称NAT,与Cone NAT是大不相同的,并不对会话进行端口绑定,而是分配一个全新的公网端口 给每一个新的会话。 还是上面那个例子:如果 Client A (10.0.0.1:1234)同时发起两个 "外出" 会话,分别发往S1和S2。对称Nat会分配公共地址155.99.25.11:62000给Session1,然后分配另一个不同的公共地址155.99.25.11:62001给Session2。对称Nat能够区别两个不同的会话并进行地址转换,因为在 Session1 和 Session2中的外部地址是不同的,正是因为这样,Client端的应用程序就迷失在这个地址转换边界线了,因为这个应用程序每发出一个会话都会使用一个新的端口,无法保障只使用同一个端口了。 在TCP和UDP通信中,(到底是使用同一个端口,还是分配不同的端口给同一个应用程序),锥形NAT和对称NAT各有各的理由。当然锥形NAT在根据如何公平地将NAT接受的连接直达一个已创建的地址对上有更多的分类。这个分类一般应用在Udp通信(而不是Tcp通信上),因为NATs和防火墙阻止了试图无条件传入的TCP连接,除非明确设置NAT不这样做。 三:NAT对session的处理 以下分析NAPT是依据什么策略来判断是否要为一个请求发出的UDP数据包建立Session的.主要有一下几个策略: A. 源地址(内网IP地址)不同,忽略其它因素, 在NAPT上肯定对应不同的Session B. 源地址(内网IP地址)相同,源端口不同,忽略其它的因素,则在NAPT上也肯定对应不同的Session C. 源地址(内网IP地址)相同,源端口相同,目的地址(公网IP地址)相同,目的端口不同,则在NAPT上肯定对应同一个Session D. 源地址(内网IP地址)相同,源端口相同,目的地址(公网IP地址)不同,忽略目的端口,则在NAPT上是如何处理Session的呢? A,B,C三种情况的都是比较简单的,可以很容易的实现.而D的情况就比较复杂了.所以D情况才是我们要重点关心和讨论的问题。 四:完全解决方案 以下针对四种SESSION与四种NAT的完全解决方案,为了方便将使用以下缩写形式: C代表 CONE NAT S代表SYMMETRIC NAT, FC代表 FULL CONE NAT, RC代表 RESTRICT CONE NAT, PC 代表 PORT RESTRICT CONE NAT. 首先依据CLIENT (客户)端在NAT后 的个数不同可以分为两大类: TYPE ONE :一个在NAT后 + 一个在公网中. 这种情况下可以分为两大类: A. S VS 公网:此种情况下,由于公网的地址在一个SESSION内是不变的,所以可以打洞是可以成功的. B. C VS 公网: 与上面类似,这种情口下打洞是可以成功的. TYPE TWO:两个客户都在NAT后面. 这种情况下也可以细分为两大类: A. 其中一个NAT 是 S(SYMMETRIC NAT) 型的,既:S VS C或者是S VS S . 下面论证这种情口下按照常规打洞是行不通的,在常规打洞中,所有的客户首先登陆到一个服务器上去.服务器记录下每个客户的[公网IP:端口],然后在打洞过程中就使用这个记录的值,然而对于S型的NAT来说,它并不绑定[私网IP:端口]和[公网IP:端口]的映射.所以在不同的SESSION中,NAT将会重新分配一对[公网IP:端口].这样一来对于S型的NAT来说打洞的[公网IP:端口]与登记在服务器上的[公网IP:端口]是不同的.而且也没有办法将打洞的[公网IP:端口]通知到另一个位于NAT下的客户端, 所以打洞是不会成功的.然而如果另一个客户端是在公网时,打洞是可以的.前面已经论证了这种情况. 这种情况下的解决方案是只能通过端口预测来进行打洞,具体解决方法如下:例如(以两个都是S型的为例) NAT A 分配了它自己的UDP端口62000,用来保持 客户端A 与服务器S的通信会话, NAT B 也分配了31000端口,用来保持客户端B与服务器S 的通信会话。通过与 服务器S的对话,客户端A 和 客户端B都相互知道了对方所映射的真实IP和端口。 客户端A发送一条UDP消息到138.76.29.7:31001(请注意到端口号的增加),同时客户端B发送一条UDP消息到155.99.25.11:62001。如果NAT A 和NAT B继续分配端口给新的会话,并且从A-S和B-S的会话时间消耗得并不多的话,那么一条处于客户端A和客户端B之间的双向会话通道就建立了。 客户端A发出的消息送达B导致了NAT A打开了一个新的会话,并且我们希望NAT A将会指派62001端口给这个新的会话,因为62001是继62000后,NAT会自动指派给 从服务器S到客户端A之间的新会话的端口号;类似的,客户端B发出的消息送达A导致了 NAT B打开了一个新的会话,并且我们希望 NAT B将会指派31001这个端口给新的会话;如果两个客户端都正确的猜测到了对方新会话被指派的端口号,那么这个 客户端A-客户端B的双向连接就被打通了。其结果如下图所示: 明显的,有许多因素会导致这个方法失败:如果这个预言的新端口(62001和31001) 恰好已经被一个不相关的会话所使用,那么NAT就会跳过这个端口号,这个连接就会宣告失败;如果两个NAT有时或者总是不按照顺序来生成新的端口号,那么这个方法也是行不通的。 如果隐藏在NATA后的一个不同的客户端X(或者在NAT B后)打开了一个新的“外出”UDP 连接,并且无论这个连接的目的如何;只要这个动作发生在客户端A 建立了与服务器S的连接之后,客户端A 与 客户端B 建立连接之前;那么这个无关的客户端X 就会趁人不备地“偷” 到这个我们渴望分配的端口。所以,这个方法变得如此脆弱而且不堪一击,只要任何一个NAT方包含以上碰到的问题,这个方法都不会奏效。 在处于 cone NAT 系列的网络环境中这个方法还是实用的;如果有一方为 cone NAT 而另外一方为 symmetric NAT,那么应用程序就应该预先发现另外一方的 NAT 是什么类型,再做出正确的行为来处理通信,这样就增大了算法的复杂度,并且降低了在真实网络环境中的普适性。 最后,如果P2P的一方处在两级或者两级以上的NAT下面,并且这些NATS 接近这个客户端是SYMMETRIC NAT的话,端口号预言是无效的! 因此,并不推荐使用这个方法来写新的P2P应用程序,这也是历史的经验和教训! B. 两个都是CONE NAT型的. 这种情况下可以分为六大类型: A: FC + FC B: FC + RC C: FC + PC D: PC + RC E: PC + PC F: RC + RC 虽然有这么多种情况,但是由于CONE NAT 的特性,所以还是很好办的,因为对于CONE NAT 来说,在同一个SESSION中它会绑定一对[私网IP:端口]和[公网IP:端口]的映射,所以它们打洞用的[公网IP:端口]与登记在服务器上的[公网IP:端口]是一致的,所以打洞是可以行的通的. 综上所述,就已经完全的概括了所有类型的NAT之间的可能的通信情况了.并且都提供了可行的解决方案. 五:对前一阶段的总结 1.前一阶段使用的打洞方法是有缺陷的,它只适应于两个都是FULL CONE NAT的类型的CLIENT(客户端).以下论证它不适应于两个都是CONE NAT的类型中的 B: FC + RC C: FC + PC D: PC + RC E: PC + PC F: RC + RC 这五种情况. 因为对于受限的NAT它登记了外出包的[IP地址&端口],它仅仅接受这些已登记地址发过来的包,所以它们报告服务器的端口只能接受来自服务器的包.不能接受来自另一客户端的包.所以前一阶段的打洞方法是不可行的. 六: 存在的问题 按照理论.NAT将在一定时间后关闭UDP的一个映射,所以为了保持与服务器能够一直通信,服务器必须要发送UDP心跳包,来保持映射不被关闭.这就需要一个合适的时间值. posted @ 2008-09-08 15:19 Tzot 阅读(634) 评论(0) 编辑 摘要: 定义: 作为对象的创建模式[GOF95], Singleton模式确保其一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单态类。单态类有以下几个特点: 单态类只能有一个实例。 单态类必须自己创建自己的这个实例。 单态类必须给所有其他对象提供这个实例。 以下是单态模式的几个实现方法:1 无线程安全。[代码]上面这个写法是没有线程安全,当有两个线程同时走到if (instance...阅读全文 posted @ 2008-09-01 15:31 Tzot 阅读(275) 评论(3) 编辑 摘要: 第一次翻译文章,错误在所难免。让大家见笑了!还希望高手多指点。。 Windows Form应用程序在内存使用方面显得非常臃肿。主要是因为.NET应用程序在启动的时候有大量的footprint被JIT编译器加载,并且所有的链代码和WinForms引擎在启动时候被编译,并加载到程序的进程。这一过程占用了处理器时间片的同时也占用了大量的内存。JIT在确定哪些代码应该被编译已经做的非常好了,大部分其编译的...阅读全文 posted @ 2008-08-28 16:27 Tzot 阅读(816) 评论(1) 编辑 |
|||