2007年01月18日

怎么改善现有网站

我们大部分的设计师依旧在采用传统的表格布局、表现与结构混杂在一起的方式来建立网站。学习使用XHTML+CSS的方法需要一个过程,使现有网站符合网站标准也不可能一步到位。最好的方法是循序渐进,分阶段来逐步达到完全符合网站标准的目标。如果你是新手,或者对代码不是很熟悉,也可以采用遵循标准的编辑工具,例如Dreamweaver MX 2004,它是目前支持CSS标准最完善的工具。

1.初级改善

  • 为页面添加正确的DOCTYPE

很多设计师和开发者都不知道什么是DOCTYPE,DOCTYPE有什么用。DOCTYPE是document type的简写。主要用来说明你用的XHTML或者HTML是什么版本。浏览器根据你DOCTYPE定义的DTD(文档类型定义)来解释页面代码。所以,如果你不注意设置了错误的DOCTYPE,结果会让你大吃一惊。XHTML1.0提供了三种DOCTYPE可选择:

(1)过渡型(Transitional )

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

(2)严格型(Strict )

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

(3)框架型(Frameset )

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

对于我们初级改善来说,只要选用过渡型的声明就可以了。它依然可以兼容你的表格布局、表现标识等,不至于让你觉得变化太大,难以掌握。

Tip:你懒得输入上面过渡型代码的话,可以访问http://www.macromedia.com/网站的首页,然后查看源代码,把head区同样的代码拷贝粘贴就可以了。

  • 设定一个名字空间(Namespace)

直接在DOCTYPE声明后面添加如下代码:

<html XMLns="http://www.w3.org/1999/xhtml" >

一个namespace是收集元素类型和属性名字的一个详细的DTD,namespace声明允许你通过一个在线地址指向来识别你的namespace。只要照样输入代码就可以。

  • 声明你的编码语言

为了被浏览器正确解释和通过标识校验,所有的XHTML文档都必须声明它们所使用的编码语言。代码如下:

<meta http-equiv="Content-Type" content="text/html; charset=GB2312" />

这里声明的编码语言是简体中文GB2312,你如果需要制作繁体内容,可以定义为BIG5。

  • 用小写字母书写所有的标签

XML对大小写是敏感的,所以,XHTML也是大小写有区别的。所有的XHTML元素和属性的名字都必须使用小写。否则你的文档将被W3C校验认为是无效的。例如下面的代码是不正确的:

<TITLE>公司简介</TITLE>

正确的写法是:

<title>公司简介</title> 同样的,<P>改成<p>,<B>改成<b>等等。这步转换很简单。

  • 为图片添加 alt 属性

为所有图片添加alt属性。alt属性指定了当图片不能显示的时候就显示供替换文本,这样做对正常用户可有可无,但对纯文本浏览器和使用屏幕阅读机的用户来说是至关重要的。只有添加了alt属性,代码才会被W3C正确性校验通过。注意的是我们要添加有意义的alt属性,象下面这样的写法毫无意义:

<img src="logo_unc_120×30.gif" alt="logo_unc_120×30.gif">

正确的写法:

<img src="logo_unc_120×30.gif" alt="UNC公司标志,点击返回首页">

  • 给所有属性值加引号

在HTML中,你可以不需要给属性值加引号,但是在XHTML中,它们必须被加引号。

例:height="100",而不能是height=100。

  • 关闭所有的标签

在XHTML中,每一个打开的标签都必须关闭。就象这样:

<p>每一个打开的标签都必须关闭。</p> <b>HTML可以接受不关闭的标,XHTML就不可以。</b>

这个规则可以避免HTML的混乱和麻烦。举例来说:如果你不关闭图像标签,在一些浏览器中就可能出现CSS显示问题。用这种方法能确保页面和你设计的一样显示。需要说明的是:空标签也要关闭,在标签尾部使用一个正斜杠"/"来关闭它们自己。例如:

<br /> <img src="webstandards.gif" />

经过上述七个规则处理后,页面就基本符合XHTML1.0的要求。但我们还需要校验一下是否真的符合标准了。我们可以利用W3C提供免费校验服务(http://validator.w3.org/)。发现错误后逐个修改。在后面的资源列表中我们也提供了其他校验服务和对校验进行指导的网址,可以作为W3C校验的补充。当最后通过了XHTML验证,恭喜你已经向网站标准迈出了一大步。不是想象中的那么难吧!

2.中级改善

接下来我们的改善主要在结构和表现相分离上,这一步不象第一步那么容易实现,我们需要观念上的转变,以及对CSS2技术的学习和运用。但学习任何新知识都需要花点时间的,不是吗?诀窍在于边做边学。假如你一直采用表格布局,根本没用过 CSS,也不必急于跟表格布局说再见,你可以先用样式表代替 font 标签。随着你学到的越多,你能做的就越多。好,一起来看看我们需要做哪些事:

  • 用CSS定义元素外观

我们在写标识时已经养成习惯,当希望字体大点就用<h1>,希望在前面加个点符号就用<li>。我们总是想<h1>的意思是大的,<li>的意思是圆点,<b>的意思是“加粗文本”。而实际上, <h1>能变成你想要的任何样子,通过CSS,<h1>能变成小的字体,<p>文本能够变成巨大的、粗体的,<li>能够变成一张图片等等。我们不能强迫用结构元素实现表现效果,我们应该使用CSS来确定那些元素的外观。例如,我们可以使原来默认的6级标题可以看起来大小一样:

h1, h2, h3, h4, h5, h6{ font-family: 宋体, serif; font-size: 12px; }

  • 用结构化元素代替无意义的垃圾

许多人可能从来都不知道HTML和XHTML元素设计本意是用来表达结构的。我们很多人已经习惯用元素来控制表现,而不是结构。例如,一段列表内容可能会使用下面这样的标识:

句子一<br /> 句子二<br /> 句子三<br />

如果我们采用一个无序列表代替会更好:

<ul> <li>句子一</li> <li>句子二</li> <li>句子三</li> </ul>

你或许会说“但是<li>显示的是一个圆点,我不想用圆点”。事实上,CSS没有设定元素看起来是什么样子,你完全可以用CSS关掉圆点。

  • 给每个表格和表单加上id

给表格或表单赋予一个唯一的、结构的标记,例如

<table id="menu">

接下来,在书写样式表的时候,你就可以创建一个“menu”的选择器,并且关联一个CSS规则,用来告诉表格单元、文本标签和所有其他元素怎么去显示。这样,不需要对每个<td>标签附带一些多余的、占用带宽的表现层的高、宽、对齐和背景颜色等等属性。只需要一个附着的标记(标记“menu”的id标记),你就可以在一个分离的样式表内为干净的、紧凑的代码标记进行特别的表现层处理。

中级改善我们这里先列主要的三点,但其中包含的内容和知识点非常多,需要我们逐步学习和掌握,直到最后实现完全采用CSS而不才用任何表格实现布局。

2007年01月13日

至少现在还是不可能直接播放的,必须经过转换才可以.转换的方式可以参考:

http://www.mobilitysite.com/forums/pocketpc-tips-tricks/30478-tutorial-playing-flash-video-flv-files-pocket-pc-possible.html

Total Video Converter转换时,转换为ASF也可以,我是这样做的,我用的版本是3.00

在PPC上使用TCPMP播放器,就是原来的BetaPlayer,我用的版本是0.66

2007年01月12日

以下代码不能正常工作,即把OLD的值替换掉 

var oReg=new RegExp(old);
  document.getElementById ("player").outerHTML  = document.getElementById ("player").outerHTML.replace(oReg,fname );


  必须这样写

  var oReg=new RegExp(old,"g");
  document.getElementById ("player").outerHTML  = document.getElementById ("player").outerHTML.replace(oReg,fname );

2007年01月11日

<form >
<OBJECT codeBase="
http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" height="288" width="344" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
<PARAM NAME="_cx" VALUE="9102"/>
<PARAM NAME="_cy" VALUE="7620"/>
<PARAM NAME="FlashVars" VALUE=""/>
<PARAM NAME="Src" VALUE="googleplayer.swf?videoUrl=http%3A%2F%2Flocalhost%2FflvTest%2F爱如潮水%2Eflv&thumbnailUrl=images%2Fmosaic3%2Ejpg&playerMode=embedded"/>
<PARAM NAME="WMode" VALUE="Window"/>
<PARAM NAME="Play" VALUE="0"/>
<PARAM NAME="Loop" VALUE="1"/>
<PARAM NAME="Quality" VALUE="High"/>
<PARAM NAME="SAlign" VALUE="LT"/>
<PARAM NAME="Menu" VALUE="1"/>
<PARAM NAME="Base" VALUE=""/>
<PARAM NAME="AllowScriptAccess" VALUE=""/>
<PARAM NAME="Scale" VALUE="NoScale"/>
<PARAM NAME="DeviceFont" VALUE="0"/>
<PARAM NAME="EmbedMovie" VALUE="0"/>
<PARAM NAME="BGColor" VALUE=""/>
<PARAM NAME="SWRemote" VALUE=""/>
<PARAM NAME="MovieData" VALUE=""/>
<PARAM NAME="SeamlessTabbing" VALUE="1"/>
<PARAM NAME="Profile" VALUE="0"/>
<PARAM NAME="ProfileAddress" VALUE=""/>
<PARAM NAME="ProfilePort" VALUE="0"/>
<embed src="googleplayer.swf?videoUrl=http%3A%2F%2Flocalhost%2FflvTest%2Fasd%2Eflv&thumbnailUrl=images%2Fmosaic3%2Ejpg&playerMode=normal" width="344" height="288" play="true" loop="false" menu="true" quality="high" pluginspage="
http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash">
</embed>
</OBJECT>
<form>

 


 

 


 

Customize the Embedded Google Video Player

If you go to Google Video, you can get a code that allows you to embed a video into your site. Although Google doesn’t mention that, the Flash player used by Google Video (googleplayer.swf) lets you customize many parameters. In the code obtained from Google, you’ll see in the src attribute: http://video.google.com/googleplayer.swf?docId=[number]&hl=en. You can add more parameters to the player, not just docId and hl. Here are some of the more interesting.

* playerMode lets you change the skin of the player.

playerMode=simple (a basic version of the player without progress bar and volume control, you can see it in the screenshot below)
playerMode=mini (even more basic)
playerMode=clickToPlay (the skin used for video ads)
playerMode=embedded (the standard skin)

* autoPlay lets you control if the video starts automatically.
autoPlay=true
autoPlay=false (by default)

* loop lets you repeat a video indefinitely.
loop=true
loop=false (by default)

* showShareButtons is useful if you want to add a button at the end of the video that says "Send link to a friend".
showShareButtons=true
showShareButtons=false (by default)

So here’s one of example of customized player, that repeats a video and shows a simplified skin:
http://video.google.com/googleplayer.swf?docId=[number] &loop=true&playerMode=simple


 

如果是播放MP3,只需要将videoUrl改为audioUrl

具体细节:http://dengjie.com/temp/google_player_cn.swf


最后放一段完整的代码,包括对Normal模式下有脚本错误的处理

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Untitled Page</title>

    <script language="javascript" type="text/javascript">
        function FlashRequest(Yes,I_Love_fisker){
        //fix a javascript error from google audio player
        //powered by www.x2y2.com – fisker
        }
    </script>

</head>
<body>
    <form>

        <script>
   var old="不能承受的感动";
  function play(fname)
 {
  var oReg=new RegExp(old,"g");
  document.getElementById ("player").outerHTML  = document.getElementById ("player").outerHTML.replace(oReg,fname );
  old  = fname ;
 }
        </script>

        <object id="player" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0"
            height="288" width="344" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
            <param name="_cx" value="9102" />
            <param name="_cy" value="7620" />
            <param name="FlashVars" value="" />
            <param name="Src" value="googleplayer.swf?videoUrl=http%3A%2F%2Flocalhost%2FflvTest%2F不能承受的感动%2Eflv&thumbnailUrl=test%2Ejpg&playerMode=normal&autoPlay=true&loop=true" />
            <param name="WMode" value="Window" />
            <param name="Play" value="0" />
            <param name="Loop" value="1" />
            <param name="Quality" value="High" />
            <param name="SAlign" value="LT" />
            <param name="Menu" value="1" />
            <param name="Base" value="" />
            <param name="AllowScriptAccess" value="" />
            <param name="Scale" value="NoScale" />
            <param name="DeviceFont" value="0" />
            <param name="EmbedMovie" value="0" />
            <param name="BGColor" value="" />
            <param name="SWRemote" value="" />
            <param name="MovieData" value="" />
            <param name="SeamlessTabbing" value="1" />
            <param name="Profile" value="0" />
            <param name="ProfileAddress" value="" />
            <param name="ProfilePort" value="0" />
            <param name="AutoStart" value="1" />
            <embed src="googleplayer.swf?videoUrl=http%3A%2F%2Flocalhost%2FflvTest%2Fasd%2Eflv&thumbnailUrl=images%2Fmosaic3%2Ejpg&playerMode=normal"
                width="344" height="288" autoplay="true" loop="false" menu="true" quality="high"
                pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash">
            </embed>
        </object>
        <br />
        <select id="lst" onchange="play(this.value)" style="width: 200px">
            <option value="99夜">99夜 </option>
            <option value="不能承受的感动" selected>不能承受的感动 </option>
            <option value="爱如潮水">爱如潮水 </option>
            <option value="没有你的日子我真的很孤单">没有你的日子我真的很孤单 </option>
            <option value="雪人">雪人 </option>
            <option value="遇">遇 </option>
            <option value="秋天不回来">秋天不回来 </option>
            <option value="隐形的翅膀">隐形的翅膀 </option>
        </select>
    </form>
</body>
</html>

NStruts的配置主要包括:

(1)WEB.CONFIG

<httpHandlers>
    <add verb="*" path="*Action.do" type="nstruts.ActionHandler,nstruts"/>
  <!–add verb="*" path="*Action.aspx" type="nstruts.ActionHandler,nstruts"/–>
   </httpHandlers>

将Action.do的页面导向由NStruts处理

(2)nstruts.config中的控制器:controller节点中设置

(3)nstruts.config中的动作映射:

有两种方式:Execute直接映射和Method反射方式

综合,NStruts核心是由控制器接收请求,并处理业务逻辑和返回视图.

2007年01月10日

完全没必要用烧录方法、修改网卡中的MAC地址。要知道Windows安装的时候,会自动从网卡中读入MAC地址,把它存放在注册表中以备后用。当数据在网络中传输时,从网卡发出的数据包中要求有一个源MAC地址,这个MAC地址就是从注册表中读取的(并非从网卡中读取的),因此只要你修改了注册表中的MAC地址,就相当于改了网卡EEPROM中的MAC地址,两者实际效果是完全相同的!

在注册表中修改

  对于非RTL8139芯片的网卡,你可以直接修改注册表中的MAC,注意:修改注册表前,要先备份注册表。

  (1)Win2003/XP/2000

  点击“开始”/运行,输入regedit打开注册表,定位到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0000、0001、0002等主键下,查找DriverDesc的内容,了解网卡使用了哪个主键(例如0001),如果主键下有params项,则该主键也是网卡所使用的;

  例如网卡使用了0001主键,因此我们就选中它,在其右边建一个字符串项(名为NetworkAddress),双击该串,输入你指定的MAC地址值(注意应该是12位的连续数字或字母,其间没有-号);在0001下的NDI\params中添加一项子键(名为NetworkAddress),选择该子键,在其右边添加名为default的字符串,键值为修改后的MAC地址,与上面的数值相同;修改后重启生效。

  (2)Win98

  点击“开始”/运行,键入winipcfg选择你要修改的网卡,并记录下MAC地址值;然后点击“开始”/运行,输入regedit打开注册表,定位到HKEY_LOCAL_MACHINE\System\Current ControlSet\Services\Class\Net,下面有“0000”、“0001”、“0002”等子键;从“0000”子键开始点击,依次查找子键下的“DriverDesc”键内容,直到找到刚才记录的MAC地址为止;

  例如网卡使用了0001主键,因此我们就选中它,在其右边新建一个串,名称为networkaddress,再双击该串,输入新的MAC地址值(注意应该是12位的连续数字或字母,其间没有-号);最后重启电脑使修改生效。

2007年01月05日

问题:只允许我的机器(192.9.200.156)能够用SQLServer企业管理器访问192.9.200.77上的SQLServer服务器(端口是1433)

方法(在服务器上设置):

1.设置规则:所有IP都不能访问服务器的1433端口

2.设置规则:只有192.9.200.156能访问服务器的1433端口

3.将本机IP与MAC地址在服务器上绑定

心得:似乎安全规则的应用顺序是"允许"优先,第一次符合即有效

2007年01月04日

一.工作流管理

二.消息快捷传递:即时通讯,邮件,短信等

三.项目管理

四.统一身份验证

五.与OA和业务集成

2006年12月29日

公司限制上网,作为开发部经理,我坚决反对,并不执行相关规定.

对互联网资源限制访问,是公司文化的一大退步,使我感觉想到了那种经历

公司的官僚风气的加重,是产生这种做法的根源

于是我可能要辞职

2006年12月20日

1. 介绍
今天的Internet的"middleboxes"已经普遍存在, 比如象网络地址转换(NAT),主要是因为IPv4的地址空间消耗危机中产生的一个解决方案。然而,由这些"middleboxes"建立的不对称寻址和连接,已经成为点对点 (P2P)应用和协议中独特的问题, 这些应用和协议包括例如网络电话和多人在线游戏。这些话题甚至可能在使用 IPv6 协议后继续存在, 比如说在 NAT 常被当作兼容 IPv4 机制[NAT-PT]的地方,还有当NAT 不再需要之后,防火墙将会依然存在(这些问题)。

当前发展的"middleboxes"最初计划用在C/S结构中,即在那些相关的匿名客户端主动去连接有着固定IP地址和DNS域名的可连接主机。大多数的"middleboxes"实现一个不对称的沟通模型,即那些私有的内部网络上的主机可以和公网上的主机连接通讯,但是公网上的外部主机不能够和内网上的主机通讯除了被 middlebox’s 的管理者明确地配置之外。 在 NAPT 的通常情形中,在内部网络上的一位客户机在公网上并没有一个唯一独特的IP地址,但是可以在同一私网上的其他客户机一样,分享一个公网IP地址,并有NAPT管理。 这些在一台"middlebox"后的不知道名称和不易访问的内部主机对客户端软件比如网页浏览器并不是一个问题,它们之需要向外连接。而且这种不易访问的特性有时候被视为对保护隐私有利。

但是,在点对点的应用中,英特网上的主机通常会考虑要和"客户"建立直接和彼此访问的通话连接。呼叫者和被叫者可能会在不同的"middleboxes" 后面,两者都可能没有任何的固定IP地址或者其他的公网存在表现。举例来说,一个通常的在线游戏架构,是让参加游戏的主人连接到一个大家都知道的服务器上设定一些初识值,以及连接后的使用目的。然后,为了在游戏期间有更加快速和有效的游戏速度,需要建立彼此直接的连接。同样地,一个可共享的文件可能可以让一个大家都知道的资源搜索引擎发现或者查找到,但如果需要文件数据传输,就需要和那台共享文件的主机建立直接的连接了。在点对点连接时,"middlebox"就生成了一个问题。因为在"middlebox"后面的那些需要用TCP或者UDP和其他机器连接的主机通常没有固定可用的公网端口可以进行连接。 RFC 3235[ NAT-APPL]简短地说明了这个问题,但是没有提供任何的通常解决方案。

在这一份文档中,我们就 P2P/ middlebox 问题有2点说明。 首先,我们总结那些在middleboxes存在时P2P应用程序可以工作的已知方法。其次,我们提供基于这些实践的一套应用程序设计指导方针使P2P在middleboxes下应用的更健康。更进一步,我们提供的设计指导方针可以让将来的 middleboxes 更有效率的支持支援 P2P 应用。 我们的重点是要能够穿透 middleboxes,以提供更广阔和更直接的P2P 应用。

2. 术语
在本章中我们首先简要描述一下一些"middlebox"术语,我们这里的重点是两种常导致P2P应用出现问题的middlebox.

防火墙
一个防火墙限制私人内网和公众英特网之间的通讯,典型地防火墙就是丢弃那些它认为未经许可的数据包。在数据包穿越一个防火墙时,它检查但是不修改包里的 IP地址和TCP/ UDP 端口信息。
 
网络地址转换(NAT)
当数据包穿过NAT时,NAT不仅检查同时也修改数据的包头信息,并且允许更多的在NAT后的主机分享少数公网IP地址(通常只有1个)。

NAT通常有2种主要类型:
Basic Nat
一个Basic NAT映射一个内在的私有IP地址到一个公网IP地址,但当数据包穿过NAT时,不更换它的TCP/UDP端口号。Basic Nat通常是只用在一些具备公共IP地址池的NAT上,通过它可以地址绑定,即代表一台内部主机。

Network Address/Port Translator (NAPT)
但是最通常的,当数据包穿过NAT时,一个NAPT检查并修改它的TCP/UDP端口,那么就可以允许多台内网主机同时共享一个单独的公网IP地址了。

关于 NAT 的分类和术语,[NAT-TRAD] 和 [NAT-TERM]中有更多的信息。那些将来分类的NAPT的附加术语在较近的工作[STUN]中被定义。当一个内网的主机经过一个NAT和外部进行TCP或者UDP连接的期间,NAPT分配一个公网IP 住址和端口,以便来自外部终端响应的数据包能被NAPT接收,解释,并转发给内网的主机。这个结果是由 NAPT 建立一个(私有IP地址,私有端口)和(公网IP地址,公网端口)之间的端口绑定实现的。在这个期间NAPT将为绑定的端口执行地址翻译。一个关于P2P应用的问题是,当一个内部主机从一个私有IP,私有端口同时与外网上的多台不同的主机建立多个连接时,NAT是如何运作的。

Cone NAT
建立一个端口,把一个(私有IP,私有端口)和(公用IP,公用端口)绑定后,对于以后来自同一私有IP和端口号的应用连接,cone NAT将重复使用这个绑定的端口,只要有一个连接会话,这个绑定端口就会保持激活状态。
例如,下面图表中,推想一下客户端A通过一个cone NAT同时建立2个外部会话,从同样的内部网络终端(10.0.0.1:1234)到2个不同的外部服务器,S1和S2。cone NAT只会分配一个公用的终端,155.99.25.11:62000,都会到两个会话,并在地址转换期间确保客户端端口的一致。Basic NAT和防火墙不修改通过middlebox的数据包中的端口号,这些类型的middlebox可以被认为是一种特殊的Cone Nat。

 Server S1 Server S2
 18.181.0.31:1235 138.76.29.7:1235
 | |
 | |
 +———————-+———————-+
 |
 ^ Session 1 (A-S1) ^ | ^ Session 2 (A-S2) ^
 | 18.181.0.31:1235 | | | 138.76.29.7:1235 |
 v 155.99.25.11:62000 v | v 155.99.25.11:62000 v
 |
 Cone NAT
 155.99.25.11
 |
 ^ Session 1 (A-S1) ^ | ^ Session 2 (A-S2) ^
 | 18.181.0.31:1235 | | | 138.76.29.7:1235 |
 v 10.0.0.1:1234 v | v 10.0.0.1:1234 v
 |
 Client A
 10.0.0.1:1234

Symmetric NAT
对称的NAT(Symmetric NAT),与Cone NAT有明显差别,在所有会话期间中不会保持绑定(私有IP,私有端口)和(公共IP,公共端口)的端口不变。相反,它会为每个新对话重新分配一个新的公共端口。
举例来说,设想客户A从同样端口上要发起两个外部对话,一个和S1连接,另一个和S2连接。Symmetric NAT可能会为第一个会话分配一个公共的端点 155.99.25.11:62000,而为第二个会话分配一个不同的公共端点155.99.25.11:62001。为了地址转换,NAT可以区分这两个会话传输的目的,因为和这些会话有关的外部端点(就是S1、S2)是不同的,甚至在通过地址转换时丢失了客户端的目的标示。(即丢了S1、S2的IP地址NAT也知道如何区分,我是这么理解的,可能有误。)

 Server S1 Server S2
 18.181.0.31:1235 138.76.29.7:1235
 | |
 | |
 +———————-+———————-+
 |
 ^ Session 1 (A-S1) ^ | ^ Session 2 (A-S2) ^
 | 18.181.0.31:1235 | | | 138.76.29.7:1235 |
 v 155.99.25.11:62000 v | v 155.99.25.11:62001 v
 |
 Symmetric NAT
 155.99.25.11
 |
 ^ Session 1 (A-S1) ^ | ^ Session 2 (A-S2) ^
 | 18.181.0.31:1235 | | | 138.76.29.7:1235 |
 v 10.0.0.1:1234 v | v 10.0.0.1:1234 v
 |
 Client A
 10.0.0.1:1234

Cone NAT和Symmetric NAT之间的比较与TCP/UDP之间的比较有些类似。(TCP需要绑定,UDP不需要,Cone NAT需要绑定,Symmetric NAT不需要)

按照NAT从已知的公共IP,公共端口接收的数据限制,Cone NAT可以更进一步的进行分类。这种分类通常都是UDP连接的,因为NAT和防火墙会拒绝任何无条件的TCP连接,除非明确地以别的方式配置。

Full Cone NAT
在给一个新的外部会话建立了一个公共/私有的端口绑定后,一个full cone NAT就可以通过这个公共端口从公网上的任何外部端点接收数据通讯了。Full cone NAT也常常叫做"混合"NAT。

Restricted Cone NAT
当网络主机发一个或者几个数据包给外部主机后,一个受限的cone NAT(Restricted Cone NAT)才会接受来自这个外部(源)IP地址的数据包。受限的cone NAT有效的运用了防火墙的原理,拒绝没有要求的数据,只接收已知道的外部IP地址传来的数据。(偏开原文,大意就是网络主机需要发一个请求给外部IP地址要求要数据,NAT才会接收这个外部IP地址传来的数据,不然不接收。)

Port-Restricted Cone NAT
一个端口受限的cone NAT(Port-Restricted Cone NAT),也是这样,只接收那些网络主机曾经发给一个外部IP地址和端口相匹配的数据。一个Port-Restricted cone NAT可以和对称 NAT一样(symmetric NAT),保护内部节点不接收未被请求的数据包,但是保持一个私有端口在连接过程中不变。
(偏开原文,即不仅请求的IP和外部发来数据的IP是一样的,PORT也要是一样,这样才接收数据。对称NAT也有这个效果,但这种cone NAT保持端口不变,而对称NAT要变端口号的)。

最后,在这篇文档中我们定义一些新的术语来给middleboxes中有关P2P的行为进行分类:

P2P-Application
在这篇文档中P2P-Application被当做一个应用程序,在那些参与P2P连接的并在一个公共的登录服务器注册的终端运行,可以是一个私有端点,也可以是一个公共端点,或者两者都是,并建立一个初步的会话。

P2P-Middlebox
P2P- Middlebox就是允许P2P应用程序交换数据的的middlebox。

P2P-firewall
一个P2P-防火墙就是提供防火墙功能的P2P- Middlebox,但不具备地址映射功能。

P2P-NAT
P2P-NAT就是提供NAT功能,也提供防火墙功能的P2P- Middlebox。一台P2P- Middlebox必须为UDP传输至少提供Cone NAT功能,允许应用程序使用UDP建立完整的P2P连接。
 
loopback translation(自环映射)
当一台位于私有域的主机,它的NAT试图用此主机在公网的映射地址连接其他位于同样NAT后的其他主机,相当于NAT装置在数据包上做了两次NAT转换。在数据报到达目标主机之前,源主机的私有端点被转换成NAT分配的公共端点,然后把目标主机的公共端点转换成目标主机的私有端点。我们在上面提到的地址转换用一台NAT装置完成就称为"Loopback translation"。

3. 用middleboxes进行P2P通讯的技术
这段文章详细的回顾一下使用现有的middlebox实现P2P通讯的技术,主要从应用程序或协议设计上来述说。

3.1 Relaying(传输)
最可靠的,但是效率最低的,实现P2P通讯的方法就是在传输过程中,把P2P通讯看成向C/S通讯的网络一样。例如,推想2个客户主机,A和B,各自发起一个TCP或UDP的连接,连接到一个大家都知道的拥有固定IP地址的服务器S上。客户主机都在各自的私有网络中,但是它们各自的middlebox不允许自己的客户端可以直接和其它主机连接。
 Server S
 |
 |
 +———————-+———————-+
 | |
 NAT A NAT B
 | |
 | |
 Client A Client B

不能直接连接,两个客户端就使用S服务器进行消息的传递。例如,要发送一条信息到客户端B,客户端A以C/S连接方式简单的发送一条信息到S服务器,然后S服务器使用已经和客户端B建立的C/S连接发送这条信息到客户端B。

这种方法的优势在于只要两个客户端都连在服务器上,它就是有效的。它的明显缺点是它需要了服务器的处理并占用了带宽,而且即使服务器的网络状况良好,也有一定的通讯滞后问题。TRUN协议[TURN]定义了这种P2P应用的相关方法。

3.2 逆向连接 (Connection reversal)
第二种技术是在只有一个客户位于middlebox后的条件下运用的。举例来说, 推想客户A在 NAT 后面但是客户 B 有一个全球有效的 IP 地址, 参照下面图表:

 Server S
 18.181.0.31:1235
 |
 |
 +———————-+———————-+
 | |
 NAT A |
 155.99.25.11:62000 |
 | |
 | |
 Client A Client B
 10.0.0.1:1234 138.76.29.7:1234

客户A有一个私有IP地址10.0.0.1,并且一个应用程序使用TCP端口1234。这个客户端和服务器S的公网IP地址18.181.0.31和端口1235建立了一个连接。NAT A为了客户端A和服务器S的会话,临时分配了一个终端地址,其TCP端口62000,它自己的IP地址是155.99.25.11:因此,服务器S认为客户端A用的是IP地址155.99.25.11,端口是62000。然而,客户端B有着自己的固定IP地址,138.76.29.7,并且在它上面的P2P应用程序可以在端口1234接收TCP连接。

现在推想客户端B想要与客户端A建立一个P2P连接会话。B可能用客户端A本身的地址,即10.0.0.1:1234,也可能用在服务器S上得到到的地址,155,99.25.11:62000,去尝试连接。然而无论在哪一种情况下,连接都会失败。第一种情况下,指向IP地址10.0.0.1的通讯包会被丢弃,因为10.0.0.1不是一个公网固定IP地址。第二种情况下,来自客户端B的TCP SYN请求包将会到达NAT A的62000端口,但NAT A将会拒绝这个请求,因为NAT A只允许向外发送数据。

在尝试和客户端A建立直接连接失败后,客户端B会利用服务器S传递一个请求,让客户端A去主动连接客户。客户端A在通过服务器S接收到传递的请求后,会使用客户端B的公共IP地址和端口建立一个TCP连接。 因为这个连接是在防火墙内部发起的,所以NAT A允许这个连接建立,而客户端B也能接收这个连接,因为它并不处于middlebox后面。当前实现P2P系统的一种技术,它有一个主要的局限性,就是它只能允许P2P中一方在NAT后面:而两方都在NAT后面的情况是很常见的,这种方法就会失败。因为这种逆向连接并不是解决问题的普遍方法,通常不推荐这个方法。应用程序可以选择试一试逆向连接,但当"向前"或"逆向"都不能建立连接时,应用程序应该能够自动的可以选择另外的连接机制,比如relaying(即3.1说的)。

3.3 UDP hole punching
第三种技术,也是这篇文章的一个重要点之一,就是被称为"UDP Hole Punching"的技术。当两个需要通讯的主机可能都在middlebox后面的时候,UDP hole punching依赖于cone NAT和普通防火墙的一些特性,允许合适的P2P应用程序以"punch holes"方式通过middlebox并且建立彼此之间直接的连接。这种技术在RFC 3027[NAT- PORT]的5.1节中简要的提及,并且在英特网[KEGEL]非证实的提到,也在最近的一些协议[TEREDO, ICE]中用到。正如名字中的所提到的,这种技术只能用于UDP连接。

我们将会考虑两个特别情况,并且考虑应用程序如何完善的处理两者之间的握手连接。第一种情况下,也是较为普通的情况,两个在不通的NAT后面的客户端要求直接的进行P2P连接。第二种情况,两台客户端位于同一个NAT后面,但不能肯定(两台客户端位于同一个NAT后面)。

3.3.1 位于不同NAT后面(Peers behind different NATs)
假设客户端A和B都有自己的私有IP地址,也都位于不同的NAT后面。P2P应用程序在A、B和服务器S上运行,用的都是UDP端口1234。A和B各自和服务器S建立UDP通讯连接,使NAT A为A的连接分配一个自己的公共端口62000,而NAT B为B的连接分配的是31000端口。

 Server S
 18.181.0.31:1234
 |
 |
 +———————-+———————-+
 | |
 NAT A NAT B
 155.99.25.11:62000 138.76.29.7:31000
 | |
 | |
 Client A Client B
 10.0.0.1:1234 10.1.1.3:1234

现在推想一下,客户端A想要直接和B建立一个UDP通讯会话。假设A简单的发一个UDP信息包到B的公共地址138.76.29.7:31000,然而NAT B将会丢弃这些进入的数据信息(除非它是一个FULL cone NAT),原因是NAT B和S已经建立的外部会话,而A发送的信息中的源地址和端口号是和S不匹配的(可以参照一下上面的内容,匹配才能接受)。同样,假如B发送一个条UDP数据包给A的公网地址,NAT A也会丢弃。

但是,假设A发出一个UDP数据信息给B的公网IP地址,同时也通过服务器S传递一个请求给B,要求B也发一个UDP信息给A的公网IP地址。A直接向B的公共IP地址(138.76.29.7:31000)发送的数据包会让NAT A在A的私有地址和B的公网地址之间建立了一个新的连接会话。同时,B到A的公网地址(155.99.25.11:62000)的信息会导致NAT B在B的私有地址和A的公共地址之间建立一个新的连接会话。一旦这种新的UDP连接在两者之间建立起来,客户端A和B就不需要服务器S的"介绍"就能彼此直接通讯了。

UDP hole punching技术有几个很有用的特点。一旦在两个位于middlebox后面的客户端建立了一个直接的P2P连接,在连接中的任何一方都可以扮演一个"介绍人"的角色,依次继续和另一个客户端建立连接,减少了最初的服务器S的负担。如果说有[STUN]的话,假如两个中的任意一个或两个都碰巧不在middlebox后面,上述应用程序将同样可以建立P2P通讯通道,应用程序不需要尝试明确middlebox的类型。Hole punching技术甚至可以自动的运用在多级NAT下面,多重NAT就是那些客户端需要经历多级地址转换才能进入公网。

3.3.2 位于同一NAT后(Peers behind the same NAT)
现在考虑两台客户端(但并不确定)都在同一个NAT后面的情况,因此会有私有IP地址空间。客户端A与服务器S建立一个UDP会话,NAT会分配一个公共端口62000。客户端B与服务器S也建立一个简单的连接,NAT为此分配一个公共端口62001。

 Server S
 18.181.0.31:1234
 |
 |
 NAT
 A-S 155.99.25.11:62000
 B-S 155.99.25.11:62001
 |
 +———————-+———————-+
 | |
 Client A Client B
 10.0.0.1:1234 10.1.1.3:1234

假想A和B使用UDP hole punching技术与服务器S的建立一个外部的通讯路线做为中间介绍。然后A和B将可以通过服务器S得到各自公共IP地址和端口号,然后使用这些地址各自向对方发送数据。两个客户能够以这种方式彼此通讯,只要NAT不仅仅允许外网上的主机可以和内网上的主机进行UDP传输会话,也可以允许内网上的主机可以和其他内网的主机进行UDP会话。我们在"loopback translation"中设计到这种情况,因为来自私有网络的数据包到达NAT后,会"looped back"到私有网络上就象从公网来的一样。例如,当A向B的公共IP地址发送一个UDP包,这个包的包头有一个源IP地址和端口,是10.0.0.1:1234,而目的地址是155.99.25.11.62001。NAT接受到这个包,会把源地址转换(映射)为155.99.25.11:62000(就是A的公网地址),把目的地址转换为10.1.1.3:1234,然后发给B。即使NAT支持回环映射,NAT的转换和发送步骤看上去是多余的,在A和B通讯时似乎为NAT添加了潜在的负担。

这个问题的解决方法是直接的。当A和B一开始在服务器S上交换地址信息时,它们就可以包含他们自己的IP地址和端口号,并且是可见的,对服务器S也是可见的。客户端根据它们得到的地址同时开始向对方发数据包,并建立成功的通讯。假如这两个客户端都在同一NAT后面,数据包象通讯一开始就能直接到达,而不需要通过NAT就能建立直接连接。假如这两个客户端位于不同的NAT后,到达彼此私有地址的数据包会被丢弃,但是客户端可以通过各自的公共地址来建立连接。重要的是这些数据包需要通过一些方法去鉴别,然而,在这种情况下,A发到B的私有地址的数据包完全有可能到达A私网内其他无关的终端,B发到A的包也是这样。

3.3.3 Peers separated by multiple NATs(多级NAT)
在有多重NAT设备的拓扑结构中,如果没有一些拓扑的知识,在两个客户端之间建立理想的P2P链路是不可能的。看看下面的举的例子。

 Server S
 18.181.0.31:1234
 |
 |
 NAT X
 A-S 155.99.25.11:62000
 B-S 155.99.25.11:62001
 |
 |
 +———————-+———————-+
 | |
 NAT A NAT B
 192.168.1.1:30000 192.168.1.2:31000
 | |
 | |
 Client A Client B
 10.0.0.1:1234 10.1.1.3:1234

假设NAT X是由一个英特网服务提供者(ISP)设置的一个大型NAT,在一些公网IP地址上拥有许多用户,NAT A和B是小用户群的NAT网关,由ISP的用户自己独自配置,有各自的私有网络和用户群,使用的是ISP提供的IP地址。只有SERVER S和NAT X有自己全球固定的IP地址,而NAT A和B用的"公共"IP地址实际上是ISP地址域中私有地址,而客户端A和B的地址对NAT A和B来说也是私有的地址。每当客户端需要和服务器S建立一个外部的连接,都会导致NAT A和B和客户端建立一个单独的公共/私有连接,然后让NAT X为每个连接会话建立一个公共/私有连接。

现在推想客户A和B尝试建立一个直接的P2P UDP连接。对客户端A来说,最佳的方法是发送一个数据信息到客户端B在NAT B上,属于ISP的地址域的公共IP地址192.168.1.2:31000,对客户端B来说就是发信息到A在NAT A的公共IP地址192.168.1.1:30000(原文是NAT B,是不是笔误,还是我理解有问题?)。不幸的是,A和B并没有知道这些地址的方法,因为服务器S只能看到客户端"全局"的公共IP地址,就是155.99.25.11:62000和155.99.25.11:62001。甚至当A和B有某些方法可以得到这些地址,但他们依然不能保证这些地址是有用的,因为这些由ISP的私有地址域分配的地址可能与客户自己分配的私有地址由冲突。客户端因此没有选择只能使用由服务器S知道的公共IP地址来通讯,并且依赖NAT X来提供loopback translation。

3.3.4 Consistent prot binddings(保持端口绑定)
hole punching 技术有一个需要注意的地方:它只能工作在两台NAT都是cone NAT(或没有NAT 防火墙)的情况下,只要UDP端口还在使用,它就需要保持一个固定的端口把一个给定(私有IP,私有UDP端口)和一个(公共IP,公共UDP端口)绑定。象对称NAT一样,为每个新的连接会话分配一个新的公共端口,对一个UDP应用程序来说,为了和不同的外部通讯重用一个已经存在的地址转换是不可以的。(这边稍微有点糊涂,再多看看。) 既然cone NAT运用是相当普遍的,UDP hole punching技术应用的也相当广泛,但是还有一小部分是对等NAT配置,因此不能支持这种技术。

3.4 UDP port number prediction

有关UDP hole punching技术在上面已经被讨论过,它可以允许在一些对等NAT存在的地方也能建立P2P UDP连接会话。这种方法有时被称为"N+1"技术 [BIDIR ]并且由Takeda[SYM-STUN]详细介绍。这种方法分析NAT的工作方式并且试图预测它为将来的连接会话分配的公共端口。再次考虑那两个客户的状态,A和B,在各自分开的NAT后面,已经与一台拥有永久地址的服务器S建立了UDP连接。
 Server S
 18.181.0.31:1234
 |
 |
 +———————-+———————-+
 | |
 Symmetric NAT A Symmetric NAT B
 A-S 155.99.25.11:62000 B-S 138.76.29.7:31000
 | |
 | |
 Client A Client B
 10.0.0.1:1234 10.1.1.3:1234

NAT A分配一个属于自己的UDP端口62000以在A和S之间建立通讯连接,而NAT B分配一个31000端口用于在B和S之间建立连接。通过与服务器的通讯,A和B可以从服务器S上得到对方的公共IP地址和端口号。客户端A现在发送一个UDP数据包到地址138.76.29.7,端口31001(注意端口数目的增加),而客户端B同时发送一个数据包到地址的155,99.25.11,端口62001上。如果NAT A和B依次为新的连接分配端口,如果从A-S和B-S连接建立后没过多少时间,那在A和B之间的一个双向通讯通道就可以工作起来。A到B的数据包让NAT A建立一个新的连接,NAT A(所期望的)分配一个公共端口62001,因为之前A和S的连接会话用的62000端口,接下来就是62001。同样的,B到A的数据包将让NAT B打开一个新连接,并将(也是所期望的)分配一个端口31001。如果客户端可以正确的预测到NAT为新的连接分配的端口,一条双向的UDP通讯通道就会象如下图所示一样建立起来。

 Server S
 18.181.0.31:1234
 |
 |
 +———————-+———————-+
 | |
 NAT A NAT B
 A-S 155.99.25.11:62000 B-S 138.76.29.7:31000
 A-B 155.99.25.11:62001 B-A 138.76.29.7:31001
 | |
 | |
 Client A Client B
 10.0.0.1:1234 10.1.1.3:1234

显而易见有很多情况都能导致这种方法失败。假如任意一个预测的端口碰巧已经被其他无关的连接占用,NAT将会错过正确的端口,连接尝试也将失败。假如任意一个NAT有时或者总是选择非连续的端口号,这个方法也将失败。假如在A(B)建立了它和S的连接之后,但在发送第一个数据包到B(A)之前,一个不同的客户端在NAT(也或者B)打开一个新的外部连接到任何外部主机,无关的客户端会不注意的"偷"了(A TO B或者B TO A)所要求的端口。因此在任一NAT都包含不止一台客户端时,这种方法很少使用。

实际上,如果那些NAT是cone NAT,或者一个是cone NAT,另一个是对称NAT,这种情况下的P2P应用程序依然需要工作,应用程序需要实现查明在任何一个上与end [STUN]有关的NAT是哪一钟,并按此来修改它的工作方式,这样增加了算法的复杂程序并让网络变的脆弱。最终,假如任何一方客户端在2级以上的NAT下并且离客户端最近的NAT是对称的,预测端口的方式是无法工作的。对所有这些原因来说,应用程序是无法实现这种方法的,在这里被提及是为了历史和信息目的(就是告诉大家有这么回事,我想)

3.5. Simultaneous TCP open(TCP同时打开)
在一对节点都在已存在middlebox后,有一种建立直接P2P TCP连接的方法有时候会被使用。大多数TCP连接都是从一个终端发从一个SYN包到另一个终端,另一个中断同步响应一个SYN-ACK包。无论怎样,对于两个终端来说,同时通过发送同步包到对方然后用一个ACK包应答来建立一个TCP连接是可行的。这种过程就被称为"simultaneous open"(同时打开)

如果一个middlebox从尝试建立一个TCP连接的私有网络的外面接受一个TCP SYN包,middlebox通常以丢弃这个SYN包或者发送一个TCP RST(连接复位)包的方式来拒绝这个连接尝试。但是,如果同步包与源和目的地址端口一起到达,那么会让middlebox相信一个TCP连接已经建立起来,然后middlebox将会允许数据包通过。特别是如果middlebox刚刚得到并转换了一个从同样地址和端口来的SYN包,它将认为连接是成立的并允许进来的SYN通过。如果客户端A和B能彼此预测公共端口,它们各自的middlebox将分配下一个TCP连接端口,如果其中一个客户端和另一个客户端建立一个外部的TCP连接,可以在对方SYN到达本地middlebox之前就发送SYN包通过它本地自己的middlebox,那么P2P TCP连接就可以工作了。

令人遗憾的是,这个方法也可能比上面说的UDP端口号预测方法更脆弱并对时效更加敏感。首先,除非在进行TCP连接时,两个middleboxes是简单的防火墙或者cone NAT,在各自尝试猜测公共端口号来让NAT分配新的连接时,和上面(UDP端口预测)说到的完全一样的事情会导致连接失败。另外,如果有一方的客户发送的同步包太迅速的到达对面的middlebox,远端middlebox可能会用一个RST包拒绝SYN包,接下来就会导致本地的middlebox关闭对话并且在将来SYN重发时使用了相同但无用的端口号。最终,对simultaneous open的支持作为一个TCP的特殊应用,没有在广泛的系统中被使用。因此,这个方法也只为历史因素在这里被同样提及;它不建议被应用程序使用。在现有NAT上想要实现P2P直接通讯的应用程序应该使用UDP。

4. Application design guidelines(应用程序设计思路)

4.1 What works with P2P middleboxes(如何和P2P middlebox一起工作)
既然UDP hole punching是在两个都位于NAT后的主机之间建立P2P直接通讯方法中最有效率的一个,并且它可以在多种现有NAT上使用,如果要求建立有效的P2P通讯,通常建议这种方法,但当直接通讯不能建立时,就得依靠简单的传播。(还不怎么明白)

4.2 Peers behind the same NAT(主机在同一个NAT后面)
实际上有相当数量的用户不止2个IP地址,会有3个或者更多的IP地址。这样的话,告诉登录服务器究竟是哪一个地址变的就有些困难了。因此在这种情况下,应用程序应该发送它所有的IP地址。

4.3 Peer discovery(主机发现)

应用程序会发送一些数据包到几个地址,以发现哪一个地址是最合适的,应用程序可能变成(后面的不太明白,自己理解吧,sorry), 由于主机可能会不恰当的选择一个路由地址当做一个内部局域网(例如11.0.1.1,已经被DOD网络分配,DOD是一种网络模型)。因此应用程序应该小心的发送推测的呼叫包。
申请把包送到几地址发现, 哪一个适宜适合一规定贵族使用可能成为一个乱扔净价的’ 空间废品’的显著的源头,

4.4 TCP P2P applications (TCP P2P应用程序)

被程序员们广泛使用的SOCKET API,常用于C/S结构应用设计中。在它的通常使用方式中,一个SOCKET能绑定一个TCP或UDP端口。一个应用程序不会被允许用同样的端口(TCP or UDP)和多个SOCKET绑定来和多个外部主机同时建立连接(或)用一个SOCKET在端口上监听而其他SOCKET来建立外部连接。但是上述单个SOCKET的端口绑定限制在UDP上不是问题,因为UDP是基于数据报文的协议。UDP P2P应用程序设计者可以用recvfrom()和sendto()函数来让一个SOCKET不仅发送而且可以从多个主机上接受数据报文。

这不是TCP具有的情况。由于TCP,每个输入和输出连接都要和一个单独的SOCKET有联系。Linux Sockets API用SO_REUSEADDR选项的帮助来解决这个问题(是不是应该这么说?),这个选项好象不起作用,但可以
(在标准Single Unix里没有这个函数)。Win32 API提供了一个相同的调用SetReuseAddress。使用任何上述的选择,应用程序可以复用一个TCP端口的多个SOCKET。就是说,可以打开两个绑定在同样端口上的TCP stream Socket,一个用与listen(),另一个用与其它主机connect()

4.5 Use of midcom protocol()

如果应用程序知道它们需要穿越的middlebox并且这些middlebox实现midcom 协议,应用程序能使用midcom协议更容易的穿越middlebox。
例如,P2P应用程序需要NAT middlebox保持终端端口的绑定状态。假如middlebox可以支持midcom,P2P应用程序可以控制修改绑定端口(或者绑定地址)的参数,例如生存时间,maxidletime(?),因此应用程序不仅可以直接的连接外部主机而且也可以从外部主机接受连接;这样就不需要定期保持端口绑定的状态。当应用程序不再需要绑定,也可以使用midcom协议简单的取消绑定。

5. NAT Design Guidelines (NAT设计指导)
这部分讨论网络地址转换的设计,他们会影响P2P应用程序。

5.1 Deprecat the use of symmetric NATs (不赞成使用对等NAT)
对等NAT在那些C/S结构的应用中比如网络浏览中得到广泛应用,它们只需要建立一个向外的连接即可。但是现在,比如实时消息和语音会议等P2P应用程序被广泛的应用。对等NAT不能支持保留终端的定义并且不适用于P2P应用程序。不建议使用对等NAT来支持P2P应用程序。
一个P2P-middlebox必须在UDP通讯时具备Cone NAT的特点,允许应用程序可以建立使用UDP hole punching技术建立稳定的P2P连接。理论上,一个P2P-middlebox应该也允许应用程序既可以经过TCP,也可以通过UDP建立P2P连接。

5.2 Add incremental cone-NAT support to symmetric NAT devices (增加递增的cone-NAT以支持对等NAT设备)

一种可以让对等NAT设备扩展支持P2P应用程序的是分配它的可转让的端口空间,为一到一的连接预订一个合适的端口,为一个一到多的连接预订合适的一套不同的端口。
更进一步(未来?),一个NAT装置可以明确的被那些P2P应用程序和主机配置,因此NAT装置可以自动由正确的端口数据块来分配一个P2P端口。

5.3 Maintain consisten port bindings for UDP ports (保持UDP端口的绑定)
这份资料对NAT设计者最主要和最重要的建议是NAT保持一个固定的端口,绑定一个给定的(内部IP地址,内部UDP端口)和一个相应的(公共IP地址,公共UDP端口)
只要有任何连接存在并使用这个端口绑定,这个端口绑定就要存在。通过检查每一个包的源和目的IP地址和端口号,NAT可能会过滤关于每一个连接基础的数据包(? 俺8懂)。当在一个私有网络上的节点建立了一个新的外部连接时,使用了一个现有的已经转换过的UDP连接会话的IP地址和UDP端口号,NAT应该保证新的UDP连接作为现有连接给定一个同样的公共IP地址和UDP端口。

5.3.1 Preserving port numbers(保持端口号) (就是客户端用啥端口,NAT分配啥端口这个意思吧)
一些NAT,当建立一个新的UDP连接时,会尝试给一个相应的私有端口号分配一个同样的公共端口号,如果这个端口号碰巧是可用的。例如,假如地址是10.0.0.1的客户端A用一个从端口1234发送的数据包建立一个外部的UDP连接,NAT的公共端口1234碰巧是可用的,那么NAT会为连接使用NAT公共IP地址上的端口号1234作为转换客户端A的地址。由于如果内部网络的最多一个节点正在使用这个端口号,它是对一个NAT保持端口唯一可行的方法,这种方式可能对一些希望只用特别的UDP端口号的过去的UDP程序有帮助,但不建议应用程序依靠这种方式。
另外, 一个NAT不应该在一个新连接中保持端口号,如果确实如此将与保持公共和私有终端地址绑定的目的相抵触。例如,假定客户端A在内部的1234端口上与外部服务器S建立了一个连接,NAT A已经为这个连接分配了公共端口62000,因为端口号1234在NAT上此时是不可用的。现在假想在NAT上的端口号1234后来可以使用了,而此时A和S的连接仍然存在,客户端A用同样的内部端口1234建立一个新的连接到外部节点B上。在这种情况下,因为端口绑定已经在客户端A的端口1234和NAT的公共端口62000上建立,所以这个绑定应该继续保持,新连接也应该用62000端口作为公共端口,来对应客户端A的端口1234。NAT不应该仅仅因为端口1234变的可用了就为新的连接分配公共端口1234:这种特点不可能在任何情况下都对应用程序有帮助,由于应用程序已经对一个转换的端口号进行操作,并且它会中断应用程序用UDP hole punching技术建立P2P连接的尝试。

5.4 Maintaining consistent port bindings for TCP ports (为TCP端口保持端口绑定)
和UDP地址转换的特点一致,cone NAT也应该对TCP连接保持私有和公共IP地址,TCP端口号的绑定不变,就如上面的关于UDP描述的方式一样。保持TCP终端绑定不变将增加NAT对P2P TCP应用程序在从同样源端口建立多个TCP连接时的兼容性。

5.5 Large timeout for P2P applications (P2P程序的大超时?)
我们推荐middlebox在P2P应用时使用的最小超时大约5分钟(300秒),即,在P2P应用时为端口绑定或为分配端口时,来给middlebox配置这个空闲超时时间。当middlebox惯用目前配置时,就常常尝试使用更短的时间。但是更短的超时时间是有些问题的。考虑一个有16个终端节点的P2P应用程序,他们将每10秒发给网络一个保持活动状态的数据包以避免NAT超时。这样做是因为一个可能会以middlebox超时时间的5倍发送保持活动的数据包,在这种情况下,保持活动的包将在网络上被丢弃。

5.6 Support loopback translation(支持自环转换)
我们强烈建议middlebox 支持自环转换,允许在一台middlebox后面的主机可以和其它位于同一middlebox后的主机通过它们的可能被转换的公共端点通讯。支持自环转换是相当重要的,特别是在那些大容量多层NAT中,作为第一级的NAT。如第3.3.3 部分的描述,位于同一台一级NAT下,但是第二级NAT不同的主机无法通过UDP hole punching彼此通讯,即使全部middlebox保持端点在NAT上的映射不变,除非第一级NAT支持自环转换。