﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Luben Park-随笔分类-Java文章</title><link>http://www.blogjava.net/Ben/category/5900.html</link><description>Java Ben 成长之路</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 06:52:00 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 06:52:00 GMT</pubDate><ttl>60</ttl><item><title>[转]揭开正则表达式的神秘面纱</title><link>http://www.blogjava.net/Ben/archive/2006/02/22/31923.html</link><dc:creator>Ben</dc:creator><author>Ben</author><pubDate>Wed, 22 Feb 2006 02:47:00 GMT</pubDate><guid>http://www.blogjava.net/Ben/archive/2006/02/22/31923.html</guid><wfw:comment>http://www.blogjava.net/Ben/comments/31923.html</wfw:comment><comments>http://www.blogjava.net/Ben/archive/2006/02/22/31923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ben/comments/commentRss/31923.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ben/services/trackbacks/31923.html</trackback:ping><description><![CDATA[<P><FONT size=1>[原创文章，转载请保留或注明出处：<A href="http://www.regexlab.com/zh/regref.htm">http://www.regexlab.com/zh/regref.htm</A>]</FONT></P>
<P><B>引言</B><BR><BR>&nbsp;&nbsp;&nbsp; 正则表达式（regular expression）描述了一种字符串匹配的模式，可以用来：（1）检查一个串中是否含有符合某个规则的子串，并且可以得到这个子串；（2）根据匹配规则对字符串进行灵活的替换操作。<BR><BR>&nbsp;&nbsp;&nbsp; 正则表达式学习起来其实是很简单的，不多的几个较为抽象的概念也很容易理解。之所以很多人感觉正则表达式比较复杂，一方面是因为大多数的文档没有做到由浅入深地讲解，概念上没有注意先后顺序，给读者的理解带来困难；另一方面，各种引擎自带的文档一般都要介绍它特有的功能，然而这部分特有的功能并不是我们首先要理解的。<BR><BR>&nbsp;&nbsp;&nbsp; 文章中的每一个举例，都可以点击进入到测试页面进行测试。闲话少说，开始。</P>
<HR color=#fea089 SIZE=1>

<P><B>1. 正则表达式规则</B></P>
<P><B>1.1 普通字符</B></P>
<P>&nbsp;&nbsp;&nbsp; 字母、数字、汉字、下划线、以及后边章节中没有特殊定义的标点符号，都是"普通字符"。表达式中的普通字符，在匹配一个字符串的时候，匹配与之相同的一个字符。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=c&amp;txt=abcde">举例1：表达式 "c"，在匹配字符串 "abcde" 时</A>，匹配结果是：成功；匹配到的内容是："c"；匹配到的位置是：开始于2，结束于3。（注：下标从0开始还是从1开始，因当前编程语言的不同而可能不同）<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=bcd&amp;txt=abcde">举例2：表达式 "bcd"，在匹配字符串 "abcde" 时</A>，匹配结果是：成功；匹配到的内容是："bcd"；匹配到的位置是：开始于1，结束于4。</P>
<HR color=#fea089 SIZE=1>

<P><B>1.2 简单的转义字符</B></P>
<P>&nbsp;&nbsp;&nbsp; 一些不便书写的字符，采用在前面加 "\" 的方法。这些字符其实我们都已经熟知了。</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=70>
<P>表达式</P></TD>
<TD>
<P>可匹配</P></TD></TR>
<TR>
<TD>
<P>\r, \n</P></TD>
<TD>
<P>代表回车和换行符</P></TD></TR>
<TR>
<TD>
<P>\t</P></TD>
<TD>
<P>制表符</P></TD></TR>
<TR>
<TD>
<P>\\</P></TD>
<TD>
<P>代表 "\" 本身</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; 还有其他一些在后边章节中有特殊用处的标点符号，在前面加 "\" 后，就代表该符号本身。比如：^, $ 都有特殊意义，如果要想匹配字符串中 "^" 和 "$" 字符，则表达式就需要写成 "\^" 和 "\$"。</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=66>
<P>表达式</P></TD>
<TD>
<P>可匹配</P></TD></TR>
<TR>
<TD>
<P>\^</P></TD>
<TD>
<P>匹配 ^ 符号本身</P></TD></TR>
<TR>
<TD>
<P>\$</P></TD>
<TD>
<P>匹配 $ 符号本身</P></TD></TR>
<TR>
<TD>
<P>\.</P></TD>
<TD>
<P>匹配小数点（.）本身</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; 这些转义字符的匹配方法与 "普通字符" 是类似的。也是匹配与之相同的一个字符。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%5C$d&amp;txt=abc$de">举例1：表达式 "\$d"，在匹配字符串 "abc$de" 时</A>，匹配结果是：成功；匹配到的内容是："$d"；匹配到的位置是：开始于3，结束于5。</P>
<HR color=#fea089 SIZE=1>

<P><B>1.3 能够与 '多种字符' 匹配的表达式</B></P>
<P>&nbsp;&nbsp;&nbsp; 正则表达式中的一些表示方法，可以匹配 '多种字符' 其中的任意一个字符。比如，表达式 "\d" 可以匹配任意一个数字。虽然可以匹配其中任意字符，但是只能是一个，不是多个。这就好比玩扑克牌时候，大小王可以代替任意一张牌，但是只能代替一张牌。</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=66>
<P>表达式</P></TD>
<TD>
<P>可匹配</P></TD></TR>
<TR>
<TD>
<P>\d</P></TD>
<TD>
<P>任意一个数字，0~9 中的任意一个</P></TD></TR>
<TR>
<TD>
<P>\w</P></TD>
<TD>
<P>任意一个字母或数字或下划线，也就是 A~Z,a~z,0~9,_ 中任意一个</P></TD></TR>
<TR>
<TD>
<P>\s</P></TD>
<TD>
<P>包括空格、制表符、换页符等空白字符的其中任意一个</P></TD></TR>
<TR>
<TD>
<P>.</P></TD>
<TD>
<P>小数点可以匹配除了换行符（\n）以外的任意一个字符</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cd%5Cd&amp;txt=abc123">举例1：表达式 "\d\d"，在匹配 "abc123" 时</A>，匹配的结果是：成功；匹配到的内容是："12"；匹配到的位置是：开始于3，结束于5。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=a.%5Cd&amp;txt=aaa100">举例2：表达式 "a.\d"，在匹配 "aaa100" 时</A>，匹配的结果是：成功；匹配到的内容是："aa1"；匹配到的位置是：开始于1，结束于4。</P>
<HR color=#fea089 SIZE=1>

<P><B>1.4 自定义能够匹配 '多种字符' 的表达式</B></P>
<P>&nbsp;&nbsp;&nbsp; 使用方括号 [ ] 包含一系列字符，能够匹配其中任意一个字符。用 [^ ] 包含一系列字符，则能够匹配其中字符之外的任意一个字符。同样的道理，虽然可以匹配其中任意一个，但是只能是一个，不是多个。</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=80>
<P>表达式</P></TD>
<TD>
<P>可匹配</P></TD></TR>
<TR>
<TD>
<P>[ab5@]</P></TD>
<TD>
<P>匹配 "a" 或 "b" 或 "5" 或 "@"</P></TD></TR>
<TR>
<TD>
<P>[^abc]</P></TD>
<TD>
<P>匹配 "a","b","c" 之外的任意一个字符</P></TD></TR>
<TR>
<TD>
<P>[f-k]</P></TD>
<TD>
<P>匹配 "f"~"k" 之间的任意一个字母</P></TD></TR>
<TR>
<TD>
<P>[^A-F0-3]</P></TD>
<TD>
<P>匹配 "A"~"F","0"~"3" 之外的任意一个字符</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=[bcd][bcd]&amp;txt=abc123">举例1：表达式 "[bcd][bcd]" 匹配 "abc123" 时</A>，匹配的结果是：成功；匹配到的内容是："bc"；匹配到的位置是：开始于1，结束于3。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%5B%5Eabc%5D&amp;txt=abc123">举例2：表达式 "[^abc]" 匹配 "abc123" 时</A>，匹配的结果是：成功；匹配到的内容是："1"；匹配到的位置是：开始于3，结束于4。</P>
<HR color=#fea089 SIZE=1>

<P><B>1.5 修饰匹配次数的特殊符号</B></P>
<P>&nbsp;&nbsp;&nbsp; 前面章节中讲到的表达式，无论是只能匹配一种字符的表达式，还是可以匹配多种字符其中任意一个的表达式，都只能匹配一次。如果使用表达式再加上修饰匹配次数的特殊符号，那么不用重复书写表达式就可以重复匹配。<BR><BR>&nbsp;&nbsp;&nbsp; 使用方法是："次数修饰"放在"被修饰的表达式"后边。比如："[bcd][bcd]" 可以写成 "[bcd]{2}"。</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=67>
<P>表达式</P></TD>
<TD>
<P>作用</P></TD></TR>
<TR>
<TD>
<P>{n}</P></TD>
<TD>
<P>表达式重复n次，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=\w{2}&amp;txt=ab+c6">"\w{2}" 相当于 "\w\w"</A>；<A href="http://www.regexlab.com/zh/workshop.asp?pat=a{5}&amp;txt=bbaaaaaddee">"a{5}" 相当于 "aaaaa"</A></P></TD></TR>
<TR>
<TD>
<P>{m,n}</P></TD>
<TD>
<P>表达式至少重复m次，最多重复n次，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=ba{1,3}&amp;txt=a,baaa,baa,b,ba">"ba{1,3}"可以匹配 "ba"或"baa"或"baaa"</A></P></TD></TR>
<TR>
<TD>
<P>{m,}</P></TD>
<TD>
<P>表达式至少重复m次，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=\w\d{2,}&amp;txt=b1,a12,_456,_4AA,M12344,12346546547446534543543">"\w\d{2,}"可以匹配 "a12","_456","M12344"...</A></P></TD></TR>
<TR>
<TD>
<P>?</P></TD>
<TD>
<P>匹配表达式0次或者1次，相当于 {0,1}，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=a[cd]%3F&amp;txt=a,c,d,ac,ad">"a[cd]?"可以匹配 "a","ac","ad"</A></P></TD></TR>
<TR>
<TD>
<P>+</P></TD>
<TD>
<P>表达式至少出现1次，相当于 {1,}，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=a%2Bb&amp;txt=a%2Cb%2Cab%2Caab%2Caaab">"a+b"可以匹配 "ab","aab","aaab"...</A></P></TD></TR>
<TR>
<TD>
<P>*</P></TD>
<TD>
<P>表达式不出现或出现任意次，相当于 {0,}，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=%5C%5E*b&amp;txt=%5E%2Cb%2C%5E%5E%5Eb%2C%5E%5E%5E%5E%5E%5E%5Eb">"\^*b"可以匹配 "b","^^^b"...</A></P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cd%2B%5C.%3F%5Cd*&amp;txt=It%20costs%20%2412.5">举例1：表达式 "\d+\.?\d*" 在匹配 "It costs $12.5" 时</A>，匹配的结果是：成功；匹配到的内容是："12.5"；匹配到的位置是：开始于10，结束于14。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=go{2,8}gle&amp;txt=Ads%20by%20goooooogle%2C%20or%20gooogle">举例2：表达式 "go{2,8}gle" 在匹配 "Ads by goooooogle" 时</A>，匹配的结果是：成功；匹配到的内容是："goooooogle"；匹配到的位置是：开始于7，结束于17。</P>
<HR color=#fea089 SIZE=1>

<P><B>1.6 其他一些代表抽象意义的特殊符号</B></P>
<P>&nbsp;&nbsp;&nbsp; 一些符号在表达式中代表抽象的特殊意义：</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=67>
<P>表达式</P></TD>
<TD>
<P>作用</P></TD></TR>
<TR>
<TD>
<P>^</P></TD>
<TD>
<P>与字符串开始的地方匹配，不匹配任何字符</P></TD></TR>
<TR>
<TD>
<P>$</P></TD>
<TD>
<P>与字符串结束的地方匹配，不匹配任何字符</P></TD></TR>
<TR>
<TD>
<P>\b</P></TD>
<TD>
<P>匹配一个单词边界，也就是单词和空格之间的位置，不匹配任何字符</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; 进一步的文字说明仍然比较抽象，因此，举例帮助大家理解。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=^aaa&amp;txt=xxx+aaa+xxx">举例1：表达式 "^aaa" 在匹配 "xxx aaa xxx" 时</A>，匹配结果是：失败。因为 "^" 要求与字符串开始的地方匹配，因此，只有当 "aaa" 位于字符串的开头的时候，"^aaa" 才能匹配，<A href="http://www.regexlab.com/zh/workshop.asp?pat=^aaa&amp;txt=aaa+xxx+xxx">比如："aaa xxx xxx"</A>。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=aaa$&amp;txt=xxx+aaa+xxx">举例2：表达式 "aaa$" 在匹配 "xxx aaa xxx" 时</A>，匹配结果是：失败。因为 "$" 要求与字符串结束的地方匹配，因此，只有当 "aaa" 位于字符串的结尾的时候，"aaa$" 才能匹配，<A href="http://www.regexlab.com/zh/workshop.asp?pat=aaa$&amp;txt=xxx+xxx+aaa">比如："xxx xxx aaa"</A>。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=.%5Cb.&amp;txt=@@@abc">举例3：表达式 ".\b." 在匹配 "@@@abc" 时</A>，匹配结果是：成功；匹配到的内容是："@a"；匹配到的位置是：开始于2，结束于4。<BR>&nbsp;&nbsp;&nbsp; 进一步说明："\b" 与 "^" 和 "$" 类似，本身不匹配任何字符，但是它要求它在匹配结果中所处位置的左右两边，其中一边是 "\w" 范围，另一边是 非"\w" 的范围。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cbend%5Cb&amp;txt=weekend,endfor,end">举例4：表达式 "\bend\b" 在匹配 "weekend,endfor,end" 时</A>，匹配结果是：成功；匹配到的内容是："end"；匹配到的位置是：开始于15，结束于18。</P>
<P>&nbsp;&nbsp;&nbsp; 一些符号可以影响表达式内部的子表达式之间的关系：</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=65>
<P>表达式</P></TD>
<TD>
<P>作用</P></TD></TR>
<TR>
<TD>
<P>|</P></TD>
<TD>
<P>左右两边表达式之间 "或" 关系，匹配左边或者右边</P></TD></TR>
<TR>
<TD>
<P>( )</P></TD>
<TD>
<P>(1). 在被修饰匹配次数的时候，括号中的表达式可以作为整体被修饰<BR>(2). 取匹配结果的时候，括号中的表达式匹配到的内容可以被单独得到</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=Tom%7CJack&amp;txt=I%27m+Tom%2C+he+is+Jack">举例5：表达式 "Tom|Jack" 在匹配字符串 "I'm Tom, he is Jack" 时</A>，匹配结果是：成功；匹配到的内容是："Tom"；匹配到的位置是：开始于4，结束于7。匹配下一个时，匹配结果是：成功；匹配到的内容是："Jack"；匹配到的位置时：开始于15，结束于19。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%28go%5Cs*%29%2B&amp;txt=Let%27s%20go%20go%20go%21">举例6：表达式 "(go\s*)+" 在匹配 "Let's go go go!" 时</A>，匹配结果是：成功；匹配到内容是："go go go"；匹配到的位置是：开始于6，结束于14。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%uFFE5%28%5Cd%2B%5C.%3F%5Cd*%29&amp;txt=%uFF0410.9%2C%uFFE520.5">举例7：表达式 "￥(\d+\.?\d*)" 在匹配 "＄10.9,￥20.5" 时</A>，匹配的结果是：成功；匹配到的内容是："￥20.5"；匹配到的位置是：开始于6，结束于10。单独获取括号范围匹配到的内容是："20.5"。</P>
<HR color=#fea089 SIZE=1>

<P><B>2. 正则表达式中的一些高级规则</B></P>
<P><B>2.1 匹配次数中的贪婪与非贪婪</B></P>
<P>&nbsp;&nbsp;&nbsp; 在使用修饰匹配次数的特殊符号时，有几种表示方法可以使同一个表达式能够匹配不同的次数，比如："{m,n}", "{m,}", "?", "*", "+"，具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中，总是尽可能多的匹配。比如，针对文本 "dxxxdxxxd"，举例如下：</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=93>
<P>表达式</P></TD>
<TD>
<P>匹配结果</P></TD></TR>
<TR>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B)&amp;txt=dxxxdxxxd">(d)(\w+)</A></P></TD>
<TD>
<P>"\w+" 将匹配第一个 "d" 之后的所有字符 "xxxdxxxd"</P></TD></TR>
<TR>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B)(d)&amp;txt=dxxxdxxxd">(d)(\w+)(d)</A></P></TD>
<TD>
<P>"\w+" 将匹配第一个 "d" 和最后一个 "d" 之间的所有字符 "xxxdxxx"。虽然 "\w+" 也能够匹配上最后一个 "d"，但是为了使整个表达式匹配成功，"\w+" 可以 "让出" 它本来能够匹配的最后一个 "d"</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; 由此可见，"\w+" 在匹配的时候，总是尽可能多的匹配符合它规则的字符。虽然第二个举例中，它没有匹配最后一个 "d"，但那也是为了让整个表达式能够匹配成功。同理，带 "*" 和 "{m,n}" 的表达式都是尽可能地多匹配，带 "?" 的表达式在可匹配可不匹配的时候，也是尽可能的 "要匹配"。这 种匹配原则就叫作 "贪婪" 模式 。</P>
<P>&nbsp;&nbsp;&nbsp; 非贪婪模式：<BR><BR>&nbsp;&nbsp;&nbsp; 在修饰匹配次数的特殊符号后再加上一个 "?" 号，则可以使匹配次数不定的表达式尽可能少的匹配，使可匹配可不匹配的表达式，尽可能的 "不匹配"。这种匹配原则叫作 "非贪婪" 模式，也叫作 "勉强" 模式。如果少匹配就会导致整个表达式匹配失败的时候，与贪婪模式类似，非贪婪模式会最小限度的再匹配一些，以使整个表达式匹配成功。举例如下，针对文本 "dxxxdxxxd" 举例：</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=93>
<P>表达式</P></TD>
<TD>
<P>匹配结果</P></TD></TR>
<TR>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B%3F)&amp;txt=dxxxdxxxd">(d)(\w+?)</A></P></TD>
<TD>
<P>"\w+?" 将尽可能少的匹配第一个 "d" 之后的字符，结果是："\w+?" 只匹配了一个 "x"</P></TD></TR>
<TR>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=(d)(%5Cw%2B%3F)(d)&amp;txt=dxxxdxxxd">(d)(\w+?)(d)</A></P></TD>
<TD>
<P>为了让整个表达式匹配成功，"\w+?" 不得不匹配 "xxx" 才可以让后边的 "d" 匹配，从而使整个表达式匹配成功。因此，结果是："\w+?" 匹配 "xxx"</P></TD></TR></TBODY></TABLE>
<P>&nbsp;&nbsp;&nbsp; 更多的情况，举例如下：<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%3Ctd%3E%28%2E%2A%29%3C%2Ftd%3E&amp;txt=%3Ctd%3E%3Cp%3Eaa%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%3E%3Cp%3Ebb%3C%2Fp%3E%3C%2Ftd%3E">举例1：表达式 "&lt;td&gt;(.*)&lt;/td&gt;" 与字符串 "&lt;td&gt;&lt;p&gt;aa&lt;/p&gt;&lt;/td&gt; &lt;td&gt;&lt;p&gt;bb&lt;/p&gt;&lt;/td&gt;" 匹配时</A>，匹配的结果是：成功；匹配到的内容是 "&lt;td&gt;&lt;p&gt;aa&lt;/p&gt;&lt;/td&gt; &lt;td&gt;&lt;p&gt;bb&lt;/p&gt;&lt;/td&gt;" 整个字符串， 表达式中的 "&lt;/td&gt;" 将与字符串中最后一个 "&lt;/td&gt;" 匹配。 <BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%3Ctd%3E%28%2E%2A%3F%29%3C%2Ftd%3E&amp;txt=%3Ctd%3E%3Cp%3Eaa%3C%2Fp%3E%3C%2Ftd%3E%3Ctd%3E%3Cp%3Ebb%3C%2Fp%3E%3C%2Ftd%3E">举例2：相比之下，表达式 "&lt;td&gt;(.*?)&lt;/td&gt;" 匹配举例1中同样的字符串时</A>，将只得到 "&lt;td&gt;&lt;p&gt;aa&lt;/p&gt;&lt;/td&gt;"， 再次匹配下一个时，可以得到第二个 "&lt;td&gt;&lt;p&gt;bb&lt;/p&gt;&lt;/td&gt;"。</P>
<HR color=#fea089 SIZE=1>

<P><B>2.2 反向引用 \1, \2...</B></P>
<P>&nbsp;&nbsp;&nbsp; 表达式在匹配时，表达式引擎会将小括号 "( )" 包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候，小括号包含的表达式所匹配到的字符串可以单独获取。这一点，在前面的举例中，已经多次展示了。在实际应用场合中，当用某种边界来查找，而所要获取的内容又不包含边界时，必须使用小括号来指定所要的范围。比如前面的 "&lt;td&gt;(.*?)&lt;/td&gt;"。<BR><BR>&nbsp;&nbsp;&nbsp; 其实，"小括号包含的表达式所匹配到的字符串" 不仅是在匹配结束后才可以使用，在匹配过程中也可以使用。表达式后边的部分，可以引用前面 "括号内的子匹配已经匹配到的字符串"。引用方法是 "\" 加上一个数字。"\1" 引用第1对括号内匹配到的字符串，"\2" 引用第2对括号内匹配到的字符串……以此类推，如果一对括号内包含另一对括号，则外层的括号先排序号。换句话说，哪一对的左括号 "(" 在前，那这一对就先排序号。</P>
<P>&nbsp;&nbsp;&nbsp; 举例如下：<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%28%27%7C%22%29%28%2E%2A%3F%29%28%5C1%29&amp;txt=%27Hello%27%2C+%22World%22">举例1：表达式 "('|")(.*?)(\1)" 在匹配 " 'Hello', "World" " 时</A>，匹配结果是：成功；匹配到的内容是：" 'Hello' "。再次匹配下一个时，可以匹配到 " "World" "。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%28%5Cw%29%5C1%7B4%2C%7D&amp;txt=aa%20bbbb%20abcdefg%20ccccc%20111121111%20999999999">举例2：表达式 "(\w)\1{4,}" 在匹配 "aa bbbb abcdefg ccccc 111121111 999999999" 时</A>，匹配结果是：成功；匹配到的内容是 "ccccc"。再次匹配下一个时，将得到 999999999。这个表达式要求 "\w" 范围的字符至少重复5次，<A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cw%7B5%2C%7D&amp;txt=aa%20bbbb%20abcdefg%20ccccc%20111121111%20999999999">注意与 "\w{5,}" 之间的区别</A>。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%3C%28%5Cw%2B%29%5Cs%2A%28%5Cw%2B%28%3D%28%27%7C%22%29%2E%2A%3F%5C4%29%3F%5Cs%2A%29%2A%3E%2E%2A%3F%3C%2F%5C1%3E&amp;txt=%3Ctd+id%3D%27td1%27+style%3D%22bgcolor%3Awhite%22%3E%3C%2Ftd%3E%0D%0A%3Cbody+onload%3D%22doit%28%29%22%3E%3C%2Fbody%3E">举例3：表达式 "&lt;(\w+)\s*(\w+(=('|").*?\4)?\s*)*&gt;.*?&lt;/\1&gt;" 在匹配 "&lt;td id='td1' style="bgcolor:white"&gt;&lt;/td&gt;" 时</A>，匹配结果是成功。如果 "&lt;td&gt;" 与 "&lt;/td&gt;" 不配对，则会匹配失败；如果改成其他配对，也可以匹配成功。</P>
<HR color=#fea089 SIZE=1>

<P><B>2.3 预搜索，不匹配；反向预搜索，不匹配</B></P>
<P>&nbsp;&nbsp;&nbsp; 前面的章节中，我讲到了几个代表抽象意义的特殊符号："^"，"$"，"\b"。它们都有一个共同点，那就是：它们本身不匹配任何字符，只是对 "字符串的两头" 或者 "字符之间的缝隙" 附加了一个条件。理解到这个概念以后，本节将继续介绍另外一种对 "两头" 或者 "缝隙" 附加条件的，更加灵活的表示方法。</P>
<P>&nbsp;&nbsp;&nbsp; 正向预搜索："(?=xxxxx)"，"(?!xxxxx)"<BR><BR>&nbsp;&nbsp;&nbsp; 格式："(?=xxxxx)"，在被匹配的字符串中，它对所处的 "缝隙" 或者 "两头" 附加的条件是：所在缝隙的右侧，必须能够匹配上 xxxxx 这部分的表达式。因为它只是在此作为这个缝隙上附加的条件，所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 "\b"，本身不匹配任何字符。"\b" 只是将所在缝隙之前、之后的字符取来进行了一下判断，不会影响后边的表达式来真正的匹配。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=Windows+%28%3F%3DNT%7CXP%29&amp;txt=Windows+98%2C+Windows+NT%2C+Windows+2000">举例1：表达式 "Windows (?=NT|XP)" 在匹配 "Windows 98, Windows NT, Windows 2000" 时</A>，将只匹配 "Windows NT" 中的 "Windows "，其他的 "Windows " 字样则不被匹配。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%28%5Cw%29%28%28%3F%3D%5C1%5C1%5C1%29%28%5C1%29%29%2B&amp;txt=aaa+ffffff+999999999">举例2：表达式 "(\w)((?=\1\1\1)(\1))+" 在匹配字符串 "aaa ffffff 999999999" 时</A>，将可以匹配6个"f"的前4个，可以匹配9个"9"的前7个。这个表达式可以读解成：重复4次以上的字母数字，则匹配其剩下最后2位之前的部分。当然，这个表达式可以不这样写，在此的目的是作为演示之用。</P>
<P>&nbsp;&nbsp;&nbsp; 格式："(?!xxxxx)"，所在缝隙的右侧，必须不能匹配 xxxxx 这部分表达式。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%28%28%3F%21%5Cbstop%5Cb%29%2E%29%2B&amp;txt=fdjka+ljfdl+stop+fjdsla+fdj">举例3：表达式 "((?!\bstop\b).)+" 在匹配 "fdjka ljfdl stop fjdsla fdj" 时</A>，将从头一直匹配到 "stop" 之前的位置，如果字符串中没有 "stop"，则匹配整个字符串。<BR><BR>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=do%28%3F%21%5Cw%29&amp;txt=done%2C+do%2C+dog">举例4：表达式 "do(?!\w)" 在匹配字符串 "done, do, dog" 时</A>，只能匹配 "do"。在本条举例中，"do" 后边使用 "(?!\w)" 和使用 "\b" 效果是一样的。</P>
<P>&nbsp;&nbsp;&nbsp; 反向预搜索："(?&lt;=xxxxx)"，"(?&lt;!xxxxx)"<BR><BR>&nbsp;&nbsp;&nbsp; 这两种格式的概念和正向预搜索是类似的，反向预搜索要求的条件是：所在缝隙的 "左侧"，两种格式分别要求必须能够匹配和必须不能够匹配指定表达式，而不是去判断右侧。与 "正向预搜索" 一样的是：它们都是对所在缝隙的一种附加条件，本身都不匹配任何字符。<BR><BR>&nbsp;&nbsp;&nbsp; 举例5：表达式 "(?&lt;=\d{4})\d+(?=\d{4})" 在匹配 "1234567890123456" 时，将匹配除了前4个数字和后4个数字之外的中间8个数字。由于 JScript.RegExp 不支持反向预搜索，因此，本条举例不能够进行演示。很多其他的引擎可以支持反向预搜索，比如：Java 1.4 以上的 java.util.regex 包，.NET 中System.Text.RegularExpressions 命名空间，boost::regex 以及 <A href="http://www29.websamba.com/sswater/zh/greta/index.htm">GRETA 正则表达式库</A>等。</P>
<HR color=#fea089 SIZE=1>

<P><B>3. 其他通用规则</B></P>
<P>&nbsp;&nbsp;&nbsp; 还有一些在各个正则表达式引擎之间比较通用的规则，在前面的讲解过程中没有提到。</P>
<P>3.1 表达式中，可以使用 "\xXX" 和 "\uXXXX" 表示一个字符（"X" 表示一个十六进制数）</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=63>
<P>形式</P></TD>
<TD>
<P>字符范围</P></TD></TR>
<TR>
<TD>
<P>\xXX</P></TD>
<TD>
<P>编号在 0 ~ 255 范围的字符，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cx20&amp;txt=It+is%2E">空格可以使用 "\x20" 表示</A></P></TD></TR>
<TR>
<TD>
<P>\uXXXX</P></TD>
<TD>
<P>任何字符可以使用 "\u" 再加上其编号的4位十六进制数表示，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cu4E2D&amp;txt=%D6%D0%B9%FA">"\u4E2D"</A></P></TD></TR></TBODY></TABLE>
<P>3.2 在表达式 "\s"，"\d"，"\w"，"\b" 表示特殊意义的同时，对应的大写字母表示相反的意义</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=55>
<P>表达式</P></TD>
<TD>
<P>可匹配</P></TD></TR>
<TR>
<TD>
<P>\S</P></TD>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=%5CS%2B&amp;txt=abc+123+%40%23%24%25">匹配所有非空白字符（"\s" 可匹配各个空白字符）</A></P></TD></TR>
<TR>
<TD>
<P>\D</P></TD>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=%5CD%2B&amp;txt=abc+123+%40%23%24%25">匹配所有的非数字字符</A></P></TD></TR>
<TR>
<TD>
<P>\W</P></TD>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=%5CW%2B&amp;txt=abc+123+%40%23%24%25">匹配所有的字母、数字、下划线以外的字符</A></P></TD></TR>
<TR>
<TD>
<P>\B</P></TD>
<TD>
<P><A href="http://www.regexlab.com/zh/workshop.asp?pat=%5CB%2E%5CB&amp;txt=abc+123+%40%23%24%25">匹配非单词边界，即左右两边都是 "\w" 范围或者左右两边都不是 "\w" 范围时的字符缝隙</A></P></TD></TR></TBODY></TABLE>
<P>3.3 在表达式中有特殊意义，需要添加 "\" 才能匹配该字符本身的字符汇总</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=55>
<P>字符</P></TD>
<TD>
<P>说明</P></TD></TR>
<TR>
<TD>
<P>^</P></TD>
<TD>
<P>匹配输入字符串的开始位置。要匹配 "^" 字符本身，请使用 "\^"</P></TD></TR>
<TR>
<TD>
<P>$</P></TD>
<TD>
<P>匹配输入字符串的结尾位置。要匹配 "$" 字符本身，请使用 "\$"</P></TD></TR>
<TR>
<TD>
<P>( )</P></TD>
<TD>
<P>标记一个子表达式的开始和结束位置。要匹配小括号，请使用 "\(" 和 "\)"</P></TD></TR>
<TR>
<TD>
<P>[ ]</P></TD>
<TD>
<P>用来自定义能够匹配 '多种字符' 的表达式。要匹配中括号，请使用 "\[" 和 "\]"</P></TD></TR>
<TR>
<TD>
<P>{ }</P></TD>
<TD>
<P>修饰匹配次数的符号。要匹配大括号，请使用 "\{" 和 "\}"</P></TD></TR>
<TR>
<TD>
<P>.</P></TD>
<TD>
<P>匹配除了换行符（\n）以外的任意一个字符。要匹配小数点本身，请使用 "\."</P></TD></TR>
<TR>
<TD>
<P>?</P></TD>
<TD>
<P>修饰匹配次数为 0 次或 1 次。要匹配 "?" 字符本身，请使用 "\?"</P></TD></TR>
<TR>
<TD>
<P>+</P></TD>
<TD>
<P>修饰匹配次数为至少 1 次。要匹配 "+" 字符本身，请使用 "\+"</P></TD></TR>
<TR>
<TD>
<P>*</P></TD>
<TD>
<P>修饰匹配次数为 0 次或任意次。要匹配 "*" 字符本身，请使用 "\*"</P></TD></TR>
<TR>
<TD>
<P>|</P></TD>
<TD>
<P>左右两边表达式之间 "或" 关系。匹配 "|" 本身，请使用 "\|"</P></TD></TR></TBODY></TABLE>
<P>3.4 括号 "( )" 内的子表达式，如果希望匹配结果不进行记录供以后使用，可以使用 "(?:xxxxx)" 格式</P>
<P>&nbsp;&nbsp;&nbsp; <A href="http://www.regexlab.com/zh/workshop.asp?pat=%28%3F%3A%28%5Cw%29%5C1%29%2B&amp;txt=a bbccdd efg">举例1：表达式 "(?:(\w)\1)+" 匹配 "a bbccdd efg" 时</A>，结果是 "bbccdd"。括号 "(?:)" 范围的匹配结果不进行记录，因此 "(\w)" 使用 "\1" 来引用。</P>
<P>3.5 常用的表达式属性设置简介：Ignorecase，Singleline，Multiline，Global</P>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 bgColor=#f8f8f8 border=1>
<TBODY>
<TR bgColor=#f0f0f0>
<TD width=80>
<P>表达式属性</P></TD>
<TD>
<P>说明</P></TD></TR>
<TR>
<TD>
<P>Ignorecase</P></TD>
<TD>
<P>默认情况下，表达式中的字母是要区分大小写的。配置为 Ignorecase 可使匹配时不区分大小写。有的表达式引擎，把 "大小写" 概念延伸至 UNICODE 范围的大小写。</P></TD></TR>
<TR>
<TD>
<P>Singleline</P></TD>
<TD>
<P>默认情况下，小数点 "." 匹配除了换行符（\n）以外的字符。配置为 Singleline 可使小数点可匹配包括换行符在内的所有字符。</P></TD></TR>
<TR>
<TD>
<P>Multiline</P></TD>
<TD>
<P>默认情况下，表达式 "^" 和 "$" 只匹配字符串的开始 ① 和结尾 ④ 位置。如：<BR><BR>①xxxxxxxxx②\n<BR>③xxxxxxxxx④<BR><BR>配置为 Multiline 可以使 "^" 还可以匹配换行符之后，下一行开始前 ③ 的位置，使 "$" 还可以匹配换行符之前，一行结束 ② 的位置。</P></TD></TR>
<TR>
<TD>
<P>Global</P></TD>
<TD>
<P>主要在将表达式用来替换时起作用，配置为 Global 表示替换所有的匹配。</P></TD></TR></TBODY></TABLE>
<P>
<HR color=#fea089 SIZE=1>

<P></P>
<P><B>4. 综合提示</B></P>
<P>4.1 如果要要求表达式所匹配的内容是整个字符串，而不是从字符串中找一部分，那么可以在表达式的首尾使用 "^" 和 "$"，比如："^\d+$" 要求整个字符串只有数字。</P>
<P>4.2 如果要求匹配的内容是一个完整的单词，而不会是单词的一部分，那么在表达式首尾使用 "\b"，比如：<A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cb%28if%7Cwhile%7Celse%7Cvoid%7Cint%29%5Cb&amp;txt=if%28ifdo%29%0D%0A++++dosome%28%29%3B%0D%0Aelse%0D%0A++++doelse%28%29%3B">使用 "\b(if|while|else|void|int……)\b" 来匹配程序中的关键字</A>。</P>
<P>4.3 表达式不要匹配空字符串。否则会一直得到匹配成功，而结果什么都没有匹配到。比如：准备写一个匹配 "123"、"123."、"123.5"、".5" 这几种形式的表达式时，整数、小数点、小数数字都可以省略，但是不要将表达式写成："\d*\.?\d*"，因为如果什么都没有，这个表达式也可以匹配成功。<A href="http://www.regexlab.com/zh/workshop.asp?pat=%5Cd%2B%5C%2E%3F%5Cd%2A%7C%5C%2E%5Cd%2B&amp;txt=123%2C+123%2E%2C+123%2E5%2C+%2E5%2C+%2E">更好的写法是："\d+\.?\d*|\.\d+"</A>。</P>
<P>4.4 能匹配空字符串的子匹配不要循环无限次。如果括号内的子表达式中的每一部分都可以匹配 0 次，而这个括号整体又可以匹配无限次，那么情况可能比上一条所说的更严重，匹配过程中可能死循环。虽然现在有些正则表达式引擎已经通过办法避免了这种情况出现死循环了，比如 .NET 的正则表达式，但是我们仍然应该尽量避免出现这种情况。如果我们在写表达式时遇到了死循环，也可以从这一点入手，查找一下是否是本条所说的原因。</P>
<P>4.5 合理选择贪婪模式与非贪婪模式。</P>
<P>4.6 或 "|" 的左右两边，对某个字符最好只有一边可以匹配，这样，不会因为 "|" 两边的表达式因为交换位置而有所不同。</P>
<HR color=#fea089 SIZE=1>

<P><B>5. 搜索更多正则表达式支持 </B><BR><BR>在以下搜索字段中输入关键字，查找问题的答案。 <BR></P><!-- Search Google -->
<FORM action=http://www.google.com/custom method=get target=_top>
<TABLE bgColor=#ffffff>
<TBODY>
<TR>
<TD vAlign=top noWrap align=left height=32><INPUT maxLength=255 size=31 name=q></INPUT> <INPUT type=submit value="Google 搜索" name=sa></INPUT> <INPUT type=hidden value=pub-0994550267179056 name=client></INPUT> <INPUT type=hidden value=1 name=forid></INPUT> <INPUT type=hidden value=GB2312 name=ie></INPUT> <INPUT type=hidden value=GB2312 name=oe></INPUT> <INPUT type=hidden value=GALT:#008000;GL:1;DIV:#336699;VLC:663399;AH:center;BGC:FFFFFF;LBGC:336699;ALC:0000FF;LC:0000FF;T:000000;GFNT:0000FF;GIMP:0000FF;FORID:1; name=cof></INPUT> <INPUT type=hidden value=zh-CN name=hl></INPUT> </TD></TR></TBODY></TABLE></FORM><!-- Search Google --><img src ="http://www.blogjava.net/Ben/aggbug/31923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ben/" target="_blank">Ben</a> 2006-02-22 10:47 <a href="http://www.blogjava.net/Ben/archive/2006/02/22/31923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]TCP/IP协议介绍</title><link>http://www.blogjava.net/Ben/archive/2006/02/15/30770.html</link><dc:creator>Ben</dc:creator><author>Ben</author><pubDate>Wed, 15 Feb 2006 03:13:00 GMT</pubDate><guid>http://www.blogjava.net/Ben/archive/2006/02/15/30770.html</guid><wfw:comment>http://www.blogjava.net/Ben/comments/30770.html</wfw:comment><comments>http://www.blogjava.net/Ben/archive/2006/02/15/30770.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ben/comments/commentRss/30770.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ben/services/trackbacks/30770.html</trackback:ping><description><![CDATA[<TABLE style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all" cellSpacing=1 cellPadding=3 width="98%" bgColor=#cccccc border=0>
<TBODY>
<TR bgColor=#f8f8f8>
<TD><FONT size=4><STRONG><IMG src="http://blog.21ic.com/images/face/1.gif"><A href="http://blog.21ic.com/blog.asp?name=yzy1102&amp;subjectid=1041">[以太网接口（毕业设计）]<A href="http://blog.21ic.com/more.asp?name=yzy1102&amp;id=8301">TCP/IP协议介绍</A></STRONG></FONT><BR>yzy1102 发表于 2006-1-16 19:33:00 </TD></TR>
<TR bgColor=#ffffff>
<TD height=0>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>
<P><B>&nbsp;&nbsp;&nbsp; TCP/IP协议</B>，或称为<B>TCP/IP协议栈</B>，或互联网协议系列。</P>
<DIV style="PADDING-LEFT: 15px; FLOAT: right">
<DIV class=center>
<P><B>TCP/IP协议栈</B><BR>(按<I>TCP/IP参考模型</I>划分)</P>
<TABLE cellSpacing=3 border=0>
<TBODY>
<TR>
<TD align=middle bgColor=#ffcc99>应用层</TD>
<TD align=middle bgColor=#9999ff>FTP</TD>
<TD align=middle bgColor=#9999ff>SMTP</TD>
<TD align=middle bgColor=#9999ff>HTTP</TD>
<TD align=middle bgColor=#9999ff>...</TD></TR>
<TR>
<TD align=middle bgColor=#ffcc99>传输层</TD>
<TD align=middle bgColor=#9999ff colSpan=2>TCP</TD>
<TD align=middle bgColor=#9999ff colSpan=2>UDP</TD></TR>
<TR>
<TD align=middle bgColor=#ffcc99>网络层</TD>
<TD align=middle bgColor=#9999ff colSpan=3>IP ICMP</TD>
<TD align=middle bgColor=#9999ff>ARP</TD></TR>
<TR>
<TD align=middle bgColor=#ffeebb rowSpan=2>链路层</TD>
<TD align=middle bgColor=#eeeeee rowSpan=2>以太网</TD>
<TD align=middle bgColor=#eeeeee rowSpan=2>令牌环</TD>
<TD align=middle bgColor=#eeeeee rowSpan=2>FDDI</TD>
<TD align=middle bgColor=#eeeeee rowSpan=2>...</TD></TR></TBODY></TABLE></DIV></DIV>
<P>&nbsp;&nbsp;&nbsp; 包含了一系列构成互联网基础的网络协议。这些协议最早发源于美国国防部的DARPA互联网项目。TCP/IP字面上代表了两个协议:TCP传输控制协议和IP互联网协议。</P>
<P>&nbsp;&nbsp;&nbsp; 时间回放到1983年1月1日，在这天，互联网的前身Arpanet中，TCP/IP协议取代了旧的网络核心协议NCP(Network Core Protocol)，从而成为今天的互联网的基石。最早的的TCP/IP由Vinton Cerf和Robert Kahn两位开发，慢慢地通过竞争战胜了其它一些网络协议的方案，比如国际标准化组织ISO的OSI模型。TCP/IP的蓬勃发展发生在上世纪的90年代中期。当时一些重要而可靠的工具的出世，例如页面描述语言HTML和浏览器Mosaic，导致了互联网应用的飞束发展。</P>
<P>&nbsp;&nbsp;&nbsp; 随着互联网的发展，目前流行的IPv4协议(IP Version 4，IP版本四)已经接近它的功能上限。IPv4最致命的两个缺陷在与:</P>
<UL>
<LI>地址只有32位，IP地址空间有限; 
<LI>不支持服务等级(Quality of Service, Qos)的想法，无法管理带宽和优先级，故而不能很好的支持现今越来越多的实时的语音和视频应用。因此IPv6 (IP Version 6, IP版本六) 浮出海面，用以取代IPv4。 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; TCP/IP成功的另一个因素在与对为数众多的低层协议的支持。这些低层协议对应与OSI模型 中的第一层(物理层)和第二层(数据链路层)。每层的所有协议几乎都有一半数量的支持TCP/IP，例如: 以太网(Ethernet)，令牌环(Token Ring)，光纤数据分布接口(FDDI)，端对端协议( PPP)，X.25，帧中继(Frame Relay)，ATM，Sonet, SDH等。</P>
<P>
<TABLE id=toc align=left border=0>
<TBODY>
<TR id=toctitle>
<TD align=middle><B>目录</B> </TD></TR>
<TR id=tocinside>
<TD>
<DIV class=tocline>1 TCP/IP协议栈组成<BR></DIV>
<DIV class=tocline>2 必须协议<BR></DIV>
<DIV class=tocline>3 推荐协议<BR></DIV>
<DIV class=tocline>4 可选协议<BR></DIV>
<DIV class=tocline>5 范例: 不同计算机运行的不同协议<BR></DIV>
<DIV class=tocline>6 参考文献<BR></DIV></TD></TR></TBODY></TABLE></P>
<P></P>
<H2>&nbsp;&nbsp;&nbsp;</H2>
<H2>&nbsp;</H2>
<H2>&nbsp;</H2>
<H2>&nbsp;</H2>
<H2>&nbsp;&nbsp;&nbsp; TCP/IP协议栈组成</H2>
<P>&nbsp;&nbsp;&nbsp; 整个通信网络的任务，可以划分成不同的功能块，即抽象成所谓的 ” 层” 。用于互联网的协议可以比照TCP/IP参考模型进行分类。TCP/IP协议栈起始于第三层协议IP(互联网协议) 。所有这些协议都在相应的RFC文档中讨论及标准化。重要的协议在相应的RFC文档中均标记了状态: “必须“ (required) ，“推荐“ (recommended) ，“可选“ (elective) 。其它的协议还可能有“ 试验“(experimental) 或“ 历史“(historic) 的状态。</P>
<P></P>
<H2>&nbsp;&nbsp;&nbsp; 必须协议</H2>
<P>&nbsp;&nbsp;&nbsp; 所有的TCP/IP应用都必须实现IP和ICMP。对于一个路由器(router) 而言，有这两个协议就可以运作了，虽然从应用的角度来看，这样一个路由器 意义不大。实际的路由器一般还需要运行许多“推荐“使用的协议，以及一些其它的协议。</P>
<P>&nbsp;&nbsp;&nbsp; 在几乎所有连接到互联网上的计算机上都存在的IPv4 协议出生在1981年，今天的版本和最早的版本并没有多少改变。升级版IPv6 的工作始于1995年，目的在与取代IPv4。ICMP 协议主要用于收集有关网络的信息查找错误等工作。</P>
<P></P>
<H2>&nbsp;&nbsp;&nbsp; 推荐协议</H2>
<P>&nbsp;&nbsp;&nbsp; 每一个应用层(TCP/IP参考模型 的最高层) 一般都会使用到两个传输层协议之一: 面向连接的TCP传输控制协议和无连接的包传输的UDP用户数据报文协议 。 其它的一些推荐协议有:</P>
<UL>
<LI>TELNET (Teletype over the Network, 网络电传) ，通过一个终端(terminal)登陆到网络(运行在TCP协议上)。 
<LI>FTP (File Transfer Protocol, 文件传输协议) ，由名知义(运行在TCP协议上) 。 
<LI>SMTP (Simple Mail Transfer Protocol，简单邮件传输协议) ，用来发送电子邮件(运行在TCP协议上) 。 
<LI>DNS (Domain Name Service，域名服务) ，用于完成地址查找，邮件转发等工作(运行在TCP和UDP协议上) 。 
<LI>ECHO (Echo Protocol, 回绕协议) ，用于查错及测量应答时间(运行在TCP和UDP协议上) 。 
<LI>NTP (Network Time Protocol，网络时间协议) ，用于网络同步(运行在UDP协议上) 。 
<LI>SNMP (Simple Network Management Protocol, 简单网络管理协议) ，用于网络信息的收集和网络管理。 
<LI>BOOTP (Boot Protocol，启动协议) ，应用于无盘设备(运行在UDP协议上)。 </LI></UL>
<P></P>
<H2>&nbsp;&nbsp;&nbsp; 可选协议</H2>
<P>&nbsp;&nbsp;&nbsp; 最常用的一些有</P>
<UL>
<LI>支撑万维网WWW的超文本传输协议HTTP， 
<LI>动态配置IP地址的DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)， 
<LI>收邮件用的POP3 (Post Office Protocol, version 3, 邮局协议) ， 
<LI>用于加密安全登陆用的SSH (Secure Shell，用于替代安全性差的TELNET) ， 
<LI>用于动态解析以太网硬件地址的ARP (Address Resolution Protocol，地址解析协议) 。 </LI></UL>
<P></P>
<H2>&nbsp;&nbsp;&nbsp; 范例: 不同计算机运行的不同协议</H2>
<UL>
<LI>一个简单的路由器上可能会实现ARP, IP, ICMP, UDP, SNMP, RIP。 
<LI>WWW用户端使用ARP, IP, ICMP, UDP, TCP, DNS, HTTP, FTP。 
<LI>一台用户电脑上还会运行如TELNET, SMTP, POP3, SNMP, ECHO, DHCP, SSH, NTP。 
<LI>无盘设备可能会在固件比如ROM中实现了ARP, IP, ICMP, UDP, BOOT, TFTP (均为面向数据报的协议，实现起来相对简单)。</LI></UL>
<P>TCP/IP基础讲座-1：1层，2层，3层？ </P>
<P>&nbsp;&nbsp;&nbsp; 读过关于网络的课程的，都知道ISO-OSI 7层协议这个名词，许多书籍都会具体的画出那幅图，然后标注上物理层，数据链路层，网络层等等.背的大家要死.但是却又不知道具体这些层次干吗用的勒？ </P>
<P>&nbsp;&nbsp;&nbsp; 其实在互联网中，由于实际使用的是TCP/IP模型，也就是DOD模型(现在不知道没关系，后面会说).所以7层模型在现实网络环境中只是一个理论上，学究派的东西.这个模型中，我们真正关心的是下面的3层. </P>
<P>1.物理层 .哦.是的.这个名词还算容易了解.网卡还有那些网线构成了这一层.那些在网线中传播的二进制数据流是这层的具体表象.也就是说，这一层上面没有什么协议(不是很精确的说法，但是你可以这么理解).有的都是电流而已.我们把两台机器用网线连起来.或者用HUB把机器都连起来，这些工作就是物理层的工作. </P>
<P>&nbsp;&nbsp;&nbsp; 有2个设备属于物理层的，一个是中继器，一个是HUB.大家知道.物理上面的连线距离一长就会产生电信号的衰减.为了重新加强这个信号，我们就需要在一定距离之后加上一个信号放大器，这就是中继器(repeater) </P>
<P>&nbsp;&nbsp;&nbsp; 恩...这个比较容易理解.repeater就是连接在2根网线之间的么.没有做任何处理.所以只是一个物理设备.属于1层的. </P>
<P>&nbsp;&nbsp;&nbsp; 那么集线器(HUB) 呢？这个怎么会是在1层？？？似乎非常难以理解. </P>
<P>&nbsp;&nbsp;&nbsp; 当我说出HUB的本质，大家就能够清楚了解了 </P>
<P>&nbsp;&nbsp;&nbsp; HUB的本质其实只是一个多口中继器(MULTI PORT REPEATER) .啊...这样大家能够理解了.HUB不叫多口中继器其实只是为了销售上面的策略.他的本质就是连接多根网线的一个物理设备.也是不对经过的电信号做任何逻辑处理的. </P>
<P><STRONG>2.数据链路层</STRONG> </P>
<P>&nbsp;&nbsp;&nbsp; 欧~这个名词有些别扭了.DATA LINK层.英文似乎更加容易理解. </P>
<P>&nbsp;&nbsp;&nbsp; 这个层面上面的东西不再是电信号了.而是DATA了.对，既然是DATA就有了逻辑关系了.这个层面上面的基本单位是帧(Frame) .这层和物理层的接触是最紧密的.他是把从网线上面传输的电流转换成0和1的组合. </P>
<P>&nbsp;&nbsp;&nbsp; 物理层只是网卡对网线发出或者接受各种电平信号，那就是说物理层是无法判别电流的来源和目标的.那么把电流打成0和1的帧之后.里面就有逻辑数据了.有了数据，就可以判别数据从何而来，到何处去.所以也就可以真正的形成LINK. </P>
<P>&nbsp;&nbsp;&nbsp; 既然可以判别地址，那么地址是按照什么来判别的呢？ </P>
<P>&nbsp;&nbsp;&nbsp; 那就是最重要的概念之一:MAC地址 </P>
<P>&nbsp;&nbsp;&nbsp; 大家肯定都听说过我们的网卡都有MAC地址 </P>
<P>&nbsp;&nbsp;&nbsp; 有些人可能也知道MAC地址都是唯一的. </P>
<P>&nbsp;&nbsp;&nbsp; 对.MAC地址是全球唯一的.也就是说你的网卡虽然便宜.但是他也是世界上独一无二的. </P>
<P>&nbsp;&nbsp;&nbsp; 有些人说他可以改MAC.那就不是唯一了.对.虽然可以更改，那只是欺骗上层对封包里面的MAC地址进行改写.你网卡真正的MAC地址是固化的.无法修改的.</P>
<P>&nbsp;&nbsp;&nbsp; 我们有了MAC地址了.这样就可以有针对性对所有连接在一起的计算机进行通讯了.是的.我们终于可以在一个局域网内通讯了.</P>
<P>&nbsp;&nbsp;&nbsp; 但是有个问题我们前面没有提到.就是既然物理层传输的是电信号.那么如果我有2台机器一起发电信号，信号岂不是混乱了么？ </P>
<P>&nbsp;&nbsp;&nbsp; 非常正确.这个问题在网络里面成为"碰撞"，所以协议里面规定了如果你需要往外发数据，一定需要先看看电缆里面有没有别的信号.如果没有，那就可以发.如果2者同时发送，检测到碰撞之后2者分别等待一个随机时间，然后重发.这个就是重要的"碰撞检测 ". </P>
<P>&nbsp;&nbsp;&nbsp; 哈.看来问题解决了.不是么.现在整个网络可以正常运行了. </P>
<P>&nbsp;&nbsp;&nbsp; 确实如此.但是如果连接在网络上的计算机越来越多，那么碰撞的现象会越来越频繁.这样效率一定很低了.恩.这里还有一个重要概念"冲突域 ".在同一个物理上连接的网络上的所有设备是属于同一个冲突域的. </P>
<P>&nbsp;&nbsp;&nbsp; 接着就需要引入我们的2层设备来分割冲突域了. </P>
<P>&nbsp;&nbsp;&nbsp; 网桥(Bridge) 就是连接2个不同的物理网络的.主要功能是在2个网络之间转发Frame.因为从实际中我们可以知道.其实很多时候并非整个网络都在相互通讯.最多相互通讯的一组计算机我们可以分在一个小的冲突域内.这样分割以后可以减少冲突域，也就相对的减少了冲突的机会.而之间使用网桥来桥接，由于网桥两边的通讯不是非常频繁，所以使用网桥来为2边作为"代言人".这样任意一个小网络里面产生冲突的机会就少了. </P>
<P>&nbsp;&nbsp;&nbsp; 交换机(Switch)是我们最熟悉的设备了，交换机的本质其实就是一个多口网桥(Multi port Bridge) .同理可得.交换机的每个口后面都是一个冲突域.我们都说交换机比HUB快，就是因为交换机分割了所有的冲突域. </P>
<P>&nbsp;&nbsp;&nbsp; 由于现在交换机非常便宜.所以一般我们都是直接在交换机的口上接计算机.这样每台计算机都是一个独立的冲突域.这样碰撞的问题就没有了.所以速度是比HUB快. </P>
<P>&nbsp;&nbsp;&nbsp; 而前面说过.2层设备主要是个转发的功能.交换机的主要功能就是转发包.而不是让所有的冲突域直接物理连接.所以交换机有CPU，有内存，可以对frame进行处理等等.这些也是交换机和HUB的区别. </P>
<P><BR>3.网络层 </P>
<P>&nbsp;&nbsp;&nbsp; 我们前面的一些技术就可以构建出局域网了.有了网络层以后.数据才能够真正的在整个世界间传送 </P>
<P>&nbsp;&nbsp;&nbsp; 由于伦纳德?博萨卡(Leonard Bosack)和姗蒂?雷纳(Sandy Lerner)为了解决他们之间的通信问题(关于路由器发明的版本有很多.你听到的别的说法可能比这个说法更准确，但是谁知道呢.呵呵).路由器被发明用来解决"信息孤岛"问题.而且如果是由SWITCH来构建整个网络，那么整个网络将会有"中心节点"，这样也不符合ARPANET的初衷.所以我们有了这一层.(这样说可能会感觉本末倒置，但是先这么理解吧.) </P>
<P>&nbsp;&nbsp;&nbsp; 这一层的基本单元是包(Packet) .所有的包都有一个IP头.啊.听起来很熟悉不是么.IP就是用来在这层上面标识包的来源和目的地址的. </P>
<P>&nbsp;&nbsp;&nbsp; 这层的一个主要概念就是"路由 "，也就是和switch一样，把包转发到其他的地方.不过有个不同的地方，switch只有知道具体的MAC在哪里的情况下才能够发送给指定的计算机，而路由则不需要知道最终IP所在的计算机在哪个位置，只要知道那个途径可以过去就可以工作. </P>
<P>&nbsp;&nbsp;&nbsp; 这3层构建了整个网络的基础.由于TCP/IP模型将最下面2层合并成为一层，所以在TCP/IP里面总共这2层也是整个构架最基础的内容.而网络方面要做的工作也都是针对于这2层做的.</P>
<P><BR><STRONG>2: TCP/IP.真实世界的模型</STRONG> </P>
<P>&nbsp;&nbsp;&nbsp; 上一讲里面我们说过OSI 7层模型只是一个理论模型,而实际中只需要保证7层的功能能够实现,实际分层无需按照7层来分.而且如果真的分7层.那么数据处理的速度便要慢许多. </P>
<P>&nbsp;&nbsp;&nbsp; 在实际应用中.使用最多的便是DoD模型.也成为TCP/IP协议簇 </P>
<P>&nbsp;&nbsp;&nbsp; DoD模型(Department Of Defanse Model 美国国防部模型) 顾名思义,是美国国防部设计的一个网络模型.最早用于ARPANET.这些话可能在许多教材的第一章就会讲了.但是一般教材对于DoD模型与OSI模型对应关系都没有讲到.或者很多是模糊或者错误的. </P>
<P>&nbsp;&nbsp;&nbsp; 在这里我就要描述一下2者对应关系.OSI模型有7层我们已经知道了,而DoD模型则只有4层.下面是对应关系 </P>
<P>&nbsp;&nbsp;&nbsp; OSI&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DoD </P>
<P>&nbsp;&nbsp;&nbsp; 7.Application&nbsp;&nbsp;&nbsp;&nbsp; ┐&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp; 6.Presentation&nbsp;&nbsp; |-&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. Application/Process </P>
<P>&nbsp;&nbsp;&nbsp; 5.Session&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ┘&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp; 4.Transport&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. Host to Host </P>
<P>&nbsp;&nbsp;&nbsp; 3.Network&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. Internet </P>
<P>&nbsp;&nbsp;&nbsp; 2.Data Link&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ┬-&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. Network Access </P>
<P>&nbsp;&nbsp;&nbsp; 1.Physical&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ┘ </P>
<P><BR>&nbsp;&nbsp;&nbsp; 由于我不会制表符.所以图有些难看.其实就是OSI的1.2层对应DoD的第1层 </P>
<P>OSI的5.6.7对应DoD的第4层 </P>
<P>&nbsp;&nbsp;&nbsp; 其实这个还是比较容易记忆的 </P>
<P>&nbsp;&nbsp;&nbsp; 由于物理层和数据链路层非常密切.所以分为一个.然后上面依次对应,最上面的一大块成为应用层(处理层) </P>
<P>现在我们有了一个可用的实际模型了.不过一般我们在描述某个设备或者协议的时候.还是会使用OSI的模型,比如我们在讨论SWITCH的时候,就会说他是一个2层的设备.而路由器是一个3层的设备,还会有一些特殊的设备,比如3层交换机,4层交换机.这些都是使用OSI模型进行分类的.这点大家不要搞混淆了. </P>
<P><BR>&nbsp;&nbsp;&nbsp; 我们一直听说TCP或者UDP.还有什么SMTP.POP3.这些协议到底是在哪一层定义的那?接下来的一张图会给大家一个非常清晰的概念了(不能算是图拉 :D ). </P>
<P><BR>&nbsp;&nbsp;&nbsp; 4. APPLICATION </P>
<P>&nbsp;&nbsp;&nbsp; HTTP,FTP,telnet,SNMP,SMTP,POP3,DNS 等等 </P>
<P><BR>&nbsp;&nbsp;&nbsp; 3.Host to Host </P>
<P>&nbsp;&nbsp;&nbsp; TCP,UDP </P>
<P><BR>&nbsp;&nbsp;&nbsp; 2.internet </P>
<P>&nbsp;&nbsp;&nbsp; ICMP,ARP,RARP,IP </P>
<P><BR>&nbsp;&nbsp;&nbsp; 1.Network Access </P>
<P>&nbsp;&nbsp;&nbsp; Ethernet,FastEthernet,Token Ring 等等 </P>
<P>&nbsp;&nbsp;&nbsp; 恩...这下清楚了.让我们从下至上来看看 </P>
<P>&nbsp;&nbsp;&nbsp; 首先是最下层的.包括了以太网,快速以太网,还有现在的千M以太网等等的协议,这些协议规定了线缆的绞数.连接方式等等物理层的东西.还有底层使用MAC通讯的方式等等. </P>
<P><BR>&nbsp;&nbsp;&nbsp; 接下来是IP.ARP这些.IP在OSI模型的时候也说过.通过IP地址.我们在转发包的时候无需知道具体目标机的位置.而路由器自然会根据路由表来转发.最后一站一站的慢慢传递.达到最终目标.而ARP协议就是在IP和MAC之间转换用的. </P>
<P>&nbsp;我在上一章提过,由于有了路由器,IP,整个网络才真正能够覆盖全球.所以这一层叫做internet大家也应该容易记忆了. </P>
<P><BR>&nbsp;&nbsp;&nbsp; WOW.TCP,UDP是我们听说最多的了.他是属于控制网络连接的.在OSI称为Transport.传输层.在DoD内是Host to Host 端对端.意思其实是一样的.就是在在2台计算机之间构建出一个虚拟的通讯通道来. </P>
<P><BR>&nbsp;&nbsp;&nbsp; 最上面一层就无穷无尽了.所有的最终应用层的东西都在这里,你甚至可以定义你自己的协议类型.这些都是完全可以的.因为本身这一层就是提供给开发人员自行发挥的.只是上面列举的都经过标准化了. </P>
<P><BR>&nbsp;&nbsp;&nbsp; TCP包头结构 </P>
<P>&nbsp;&nbsp;&nbsp; 源端口 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 目标端口&nbsp; 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 序列号&nbsp; 32位 </P>
<P>&nbsp;&nbsp;&nbsp; 回应序号&nbsp; 32位 </P>
<P>&nbsp;&nbsp;&nbsp; TCP头长度&nbsp; 4位 </P>
<P>&nbsp;&nbsp;&nbsp; reserved 6位 </P>
<P>&nbsp;&nbsp;&nbsp; 控制代码 6位 </P>
<P>&nbsp;&nbsp;&nbsp; 窗口大小 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 偏移量 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 校验和 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 选项&nbsp;&nbsp; 32位(可选) </P>
<P>&nbsp;&nbsp;&nbsp; 这样我们得出了TCP包头的最小大小.就是20字节. </P>
<P><BR>&nbsp;&nbsp;&nbsp; UDP包头结构 </P>
<P>&nbsp;&nbsp;&nbsp; 源端口 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 目的端口 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 长度&nbsp; 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 校验和&nbsp; 16位 </P>
<P>&nbsp;&nbsp;&nbsp; 恩...UDP的包小很多.确实如此.因为UDP是非可靠连接.设计初衷就是尽可能快的将数据包发送出去.所以UDP协议显得非常精简. </P>
<P>&nbsp;&nbsp;&nbsp; 有一个问题,似乎这些头里面怎么没有IP地址啊.没有IP地址这些包往哪里发送那? </P>
<P>&nbsp;&nbsp;&nbsp; 对.你观察的很仔细.TCP和UDP的头里面确实没有任何IP信息.我们回头想一下TCP和UDP是属于DoD的哪一层的? 对了!是第3层. 而IP则位于模型的第二层.也就是他们两者虽然有联系.但是不属于同一层. </P>
<P>&nbsp;&nbsp;&nbsp; 模型的一个重要规则就是.当发送端发送一个数据,上一层将数据传往下一层的时候.上一层的包就成为了下一层包的数据部分. </P>
<P>&nbsp;&nbsp;&nbsp; 而到接受端接受到数据.下一层将本层的头部信息去掉后交给上一层去处理. </P>
<P><STRONG>那么我们来看看实际例子</STRONG>: </P>
<P>&nbsp;&nbsp;&nbsp; 假使我们通过SMTP协议发送数据AAA到另外一段.那么数据先会被加上SMTP的头.成为[SMTP]AAA.往下发送到TCP层.成为[TCP][SMTP]AAA.再往下送到internet层[IP][TCP][SMTP]AAA.然后成为[MAC][IP][TCP][SMTP]AAA </P>
<P>&nbsp;&nbsp;&nbsp; 这样通过enternet或者FastEnternet发送到路由器.路由器得到后替换自己的MAC地址上去.传到下一级的路由器.这样经过长途跋涉.最终这个数据流到达目标机. </P>
<P><BR>&nbsp;&nbsp;&nbsp; 目标机先从下面一层开始.去掉MAC,成为[IP][TCP][SMTP]AAA往上到IP层,恩,比对后是发送给我这个IP的.去掉,成为[TCP][SMTP]AAA.TCP接到了查看校验和,没错.往上[SMTP]AAA.最后SMTP协议去解释.得到了AAA. </P>
<P><BR>&nbsp;&nbsp;&nbsp; 万里长征终于结束.我们也将AAA发送到了目标机.大家也应该明白了为何TCP包头和UDP包头里面没有IP地址那?因为IP位于他们下面一层.TCP和UDP的包头信息是作为IP包的数据段来传送的. </P>
<P><BR>&nbsp;&nbsp;&nbsp; IP层可不管那许多.他只管他那层的协议,也就是管把从上面层来的数据加上自己的头,传到下面一层.把从下面一层来的数据去掉头.传到上面一层. </P>
<P><BR>&nbsp;&nbsp;&nbsp; 每层都是这么干的.完美的契合完成了数据包的最终旅程.</P>
<P><STRONG>TCP/IP的通讯协议</STRONG> </P>
<P>　　这部分简要介绍一下TCP/IP的内部结构。TCP/IP协议组之所以流行，部分原因是因为它可以用在各种各样的信道和底层协议（例如T1和X.25、以太网以及RS-232串行接口）之上。确切地说，TCP/IP协议是一组包括TCP协议和IP协议，UDP（User Datagram Protocol）协议、ICMP（Internet Control Message Protocol）协议和其他一些协议的协议组。 </P>
<P>TCP/IP整体构架概述 </P>
<P>　　TCP/IP协议并不完全符合OSI的七层参考模型。传统的开放式系统互连参考模型，是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务。该模型的目的是使各种硬件在相同的层次上相互通信。这7层是:物理层、数据链路层、网路层、传输层、话路层、表示层和应用层。而TCP/IP通讯协议采用了4层的层级结构，每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为： </P>
<P>　　应用层：应用程序间沟通的层，如简单电子邮件传输（SMTP）、文件传输协议（FTP）、网络远程访问协议（Telnet）等。 </P>
<P>　　传输层：在此层中，它提供了节点间的数据传送服务，如传输控制协议（TCP）、用户数据报协议（UDP）等，TCP和UDP给数据包加入传输数据并把它传输到下一层中，这一层负责传送数据，并且确定数据已被送达并接收。 </P>
<P>　　互连网络层：负责提供基本的数据封包传送功能，让每一块数据包都能够到达目的主机（但不检查是否被正确接收），如网际协议（IP）。 </P>
<P>　　网络接口层：对实际的网络媒体的管理，定义如何使用实际网络（如Ethernet、Serial Line等）来传送数据。</P>
<P>TCP/IP中的协议 </P>
<P>　　以下简单介绍TCP/IP中的协议都具备什么样的功能，都是如何工作的：</P>
<P>　　1． IP </P>
<P>　　网际协议IP是TCP/IP的心脏，也是网络层中最重要的协议。 </P>
<P>　　IP层接收由更低层（网络接口层例如以太网设备驱动程序）发来的数据包，并把该数据包发送到更高层---TCP或UDP层；相反，IP层也把从TCP或UDP层接收来的数据包传送到更低层。IP数据包是不可靠的，因为IP并没有做任何事情来确认数据包是按顺序发送的或者没有被破坏。IP数据包中含有发送它的主机的地址（源地址）和接收它的主机的地址（目的地址）。 </P>
<P>　　高层的TCP和UDP服务在接收数据包时，通常假设包中的源地址是有效的。也可以这样说，IP地址形成了许多服务的认证基础，这些服务相信数据包是从一个有效的主机发送来的。IP确认包含一个选项，叫作IP source routing，可以用来指定一条源地址和目的地址之间的直接路径。对于一些TCP和UDP的服务来说，使用了该选项的IP包好象是从路径上的最后一个系统传递过来的，而不是来自于它的真实地点。这个选项是为了测试而存在的，说明了它可以被用来欺骗系统来进行平常是被禁止的连接。那么，许多依靠IP源地址做确认的服务将产生问题并且会被非法入侵。 </P>
<P>　　2. TCP </P>
<P>　　如果IP数据包中有已经封好的TCP数据包，那么IP将把它们向‘上’传送到TCP层。TCP将包排序并进行错误检查，同时实现虚电路间的连接。TCP数据包中包括序号和确认，所以未按照顺序收到的包可以被排序，而损坏的包可以被重传。 </P>
<P>　　TCP将它的信息送到更高层的应用程序，例如Telnet的服务程序和客户程序。应用程序轮流将信息送回TCP层，TCP层便将它们向下传送到IP层，设备驱动程序和物理介质，最后到接收方。 </P>
<P>　　面向连接的服务（例如Telnet、FTP、rlogin、X Windows和SMTP）需要高度的可靠性，所以它们使用了TCP。DNS在某些情况下使用TCP（发送和接收域名数据库），但使用UDP传送有关单个主机的信息。 </P>
<P>　　3.UDP </P>
<P>　　UDP与TCP位于同一层，但对于数据包的顺序错误或重发。因此，UDP不被应用于那些使用虚电路的面向连接的服务，UDP主要用于那些面向查询---应答的服务，例如NFS。相对于FTP或Telnet，这些服务需要交换的信息量较小。使用UDP的服务包括NTP（网落时间协议）和DNS（DNS也使用TCP）。 </P>
<P>　　欺骗UDP包比欺骗TCP包更容易，因为UDP没有建立初始化连接（也可以称为握手）（因为在两个系统间没有虚电路），也就是说，与UDP相关的服务面临着更大的危险。 </P>
<P>　　4.ICMP </P>
<P>　　ICMP与IP位于同一层，它被用来传送IP的的控制信息。它主要是用来提供有关通向目的地址的路径信息。ICMP的‘Redirect’信息通知主机通向其他系统的更准确的路径，而‘Unreachable’信息则指出路径有问题。另外，如果路径不可用了，ICMP可以使TCP连接‘体面地’终止。PING是最常用的基于ICMP的服务。 </P>
<P>　　5. TCP和UDP的端口结构 </P>
<P>　　TCP和UDP服务通常有一个客户/服务器的关系，例如，一个Telnet服务进程开始在系统上处于空闲状态，等待着连接。用户使用Telnet客户程序与服务进程建立一个连接。客户程序向服务进程写入信息，服务进程读出信息并发出响应，客户程序读出响应并向用户报告。因而，这个连接是双工的，可以用来进行读写。 </P>
<P>　　两个系统间的多重Telnet连接是如何相互确认并协调一致呢？TCP或UDP连接唯一地使用每个信息中的如下四项进行确认： </P>
<P>　　源IP地址　　发送包的IP地址。 </P>
<P>　　目的IP地址　接收包的IP地址。 </P>
<P>　　源端口　　　源系统上的连接的端口。 </P>
<P>　　目的端口　　目的系统上的连接的端口。 </P>
<P>　　端口是一个软件结构，被客户程序或服务进程用来发送和接收信息。一个端口对应一个16比特的数。服务进程通常使用一个固定的端口，例如，SMTP使用25、Xwindows使用6000。这些端口号是‘广为人知’的，因为在建立与特定的主机或服务的连接时，需要这些地址和目的地址进行通讯。</P></TD></TR></TBODY></TABLE><BR></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/Ben/aggbug/30770.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ben/" target="_blank">Ben</a> 2006-02-15 11:13 <a href="http://www.blogjava.net/Ben/archive/2006/02/15/30770.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有关webservice的一些介绍和调用方法</title><link>http://www.blogjava.net/Ben/archive/2006/02/13/30473.html</link><dc:creator>Ben</dc:creator><author>Ben</author><pubDate>Mon, 13 Feb 2006 08:51:00 GMT</pubDate><guid>http://www.blogjava.net/Ben/archive/2006/02/13/30473.html</guid><wfw:comment>http://www.blogjava.net/Ben/comments/30473.html</wfw:comment><comments>http://www.blogjava.net/Ben/archive/2006/02/13/30473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ben/comments/commentRss/30473.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ben/services/trackbacks/30473.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: [转]http://www.54bk.com/user1/8454/archives/2005/26611.html1. 什么是webservice　　从表面上看，Web service 就是一个应用程序，它向外界暴露出一个能够通过Web进行调用的API。这就是说，你能够用编程的方法通过Web来调用这个应用程序。　　对Web service 更精确的解释: Web services是建立可...&nbsp;&nbsp;<a href='http://www.blogjava.net/Ben/archive/2006/02/13/30473.html'>阅读全文</a><img src ="http://www.blogjava.net/Ben/aggbug/30473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ben/" target="_blank">Ben</a> 2006-02-13 16:51 <a href="http://www.blogjava.net/Ben/archive/2006/02/13/30473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> [转贴]使用jsp实现word、excel格式报表打印 </title><link>http://www.blogjava.net/Ben/archive/2006/01/05/26772.html</link><dc:creator>Ben</dc:creator><author>Ben</author><pubDate>Thu, 05 Jan 2006 12:00:00 GMT</pubDate><guid>http://www.blogjava.net/Ben/archive/2006/01/05/26772.html</guid><wfw:comment>http://www.blogjava.net/Ben/comments/26772.html</wfw:comment><comments>http://www.blogjava.net/Ben/archive/2006/01/05/26772.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ben/comments/commentRss/26772.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ben/services/trackbacks/26772.html</trackback:ping><description><![CDATA[使用jsp实现word、excel格式报表打印<BR>转载&nbsp;（evan&nbsp;原创）<BR>&nbsp; 
<P></P>
<P>title:&nbsp;使用JSP实现WORD、EXCEL格式报表打印</P>
<P>author:&nbsp;evan</P>
<P>email:&nbsp;maioto:evan_zhao@hotmail.com</P>
<P>date:&nbsp;2003-08-21</P>
<P><BR>因为ms&nbsp;word和excel的文档都支持html文本格式，因此可以先用word或excel做好模版，另存为Web页，然后将该html改成jsp，将数据部分动态填入即可，不用很辛苦的调整格式<BR>&nbsp;<BR>word页面只要在jsp头设置如下指令：<BR>&lt;%@page&nbsp;contentType="application/msword;charset=GBK"&nbsp;%&gt;<BR>&nbsp;<BR>excel如下：<BR>&lt;%@page&nbsp;contentType="application/vnd.ms-excel;charset=GBK"&nbsp;%&gt;</P>
<P>使用这种方式客户端必须安装有office软件，用户访问时将在ie中直接用word或excel打开该页面。</P>
<P>此方法优势是模板设计、调整方便，无需在服务器端使用复杂的POI或jxl技术，也无需在客户端使用ActiveX控件技术，更安全、方便，轻松实现较好的打印效果。&nbsp;</P>
<P>microsoft关于服务器端动态创建office文档的资料（asp示例）：&nbsp;<BR><A class=contentlink href="http://support.microsoft.com/default.aspx?scid=KB;en-us;301044&amp;" target=_blank><FONT color=#4455aa>http://support.microsoft.com/default.aspx?scid=KB;en-us;301044&amp;</FONT></A><BR>&nbsp;<BR>简单示例：</P>
<P>使用word建立一文档，画表格如下：<BR>----------------------------<BR>|&nbsp;用户名&nbsp;|&nbsp;真实姓名&nbsp;|&nbsp;性别&nbsp;|<BR>----------------------------<BR>|&nbsp;guest&nbsp;&nbsp;|&nbsp;路人甲&nbsp;&nbsp;&nbsp;|&nbsp;男&nbsp;&nbsp;&nbsp;|<BR>----------------------------<BR>保存为Web页test.htm，&nbsp;将test.htm改名为test.jsp，修改其中guest、路人甲、男为从数据库动态查询，如下：</P>
<P></P>
<P>&lt;%@&nbsp;page&nbsp;contentType="application/msword;charset=GBK"&nbsp;%&gt;<BR>&lt;%@&nbsp;page&nbsp;import="java.sql.*"&nbsp;%&gt;<BR>&lt;html&nbsp;xmlns:o="urn:schemas-microsoft-com:office:office"<BR>xmlns:w="urn:schemas-microsoft-com:office:word"<BR>xmlns="<A class=contentlink href='http://www.w3.org/TR/REC-html40">' target=_blank><FONT color=#4455aa>http://www.w3.org/TR/REC-html40"&gt;</FONT></A></P>
<P>&lt;head&gt;<BR>&lt;meta&nbsp;http-equiv=Content-Type&nbsp;content="text/html;&nbsp;charset=GB2312"&gt;<BR>&lt;meta&nbsp;name=ProgId&nbsp;content=Word.Document&gt;<BR>&lt;meta&nbsp;name=Generator&nbsp;content="Microsoft&nbsp;Word&nbsp;9"&gt;<BR>&lt;meta&nbsp;name=Originator&nbsp;content="Microsoft&nbsp;Word&nbsp;9"&gt;<BR>&lt;title&gt;用户信息&lt;/title&gt;<BR>&lt;!--[if&nbsp;gte&nbsp;mso&nbsp;9]&gt;&lt;xml&gt;<BR>&nbsp;&lt;o:DocumentProperties&gt;<BR>&nbsp;&nbsp;&lt;o:Author&gt;evan&nbsp;zhao&lt;/o:Author&gt;<BR>&nbsp;&nbsp;&lt;o:LastAuthor&gt;evan&nbsp;zhao&lt;/o:LastAuthor&gt;<BR>&nbsp;&nbsp;&lt;o:Revision&gt;1&lt;/o:Revision&gt;<BR>&nbsp;&nbsp;&lt;o:TotalTime&gt;1&lt;/o:TotalTime&gt;<BR>&nbsp;&nbsp;&lt;o:Created&gt;2003-08-20T16:26:00Z&lt;/o:Created&gt;<BR>&nbsp;&nbsp;&lt;o:LastSaved&gt;2003-08-20T16:27:00Z&lt;/o:LastSaved&gt;<BR>&nbsp;&nbsp;&lt;o:Pages&gt;1&lt;/o:Pages&gt;<BR>&nbsp;&nbsp;&lt;o:Company&gt;taiping&lt;/o:Company&gt;<BR>&nbsp;&nbsp;&lt;o:Lines&gt;1&lt;/o:Lines&gt;<BR>&nbsp;&nbsp;&lt;o:Paragraphs&gt;1&lt;/o:Paragraphs&gt;<BR>&nbsp;&nbsp;&lt;o:Version&gt;9.2812&lt;/o:Version&gt;<BR>&nbsp;&lt;/o:DocumentProperties&gt;<BR>&lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if&nbsp;gte&nbsp;mso&nbsp;9]&gt;&lt;xml&gt;<BR>&nbsp;&lt;w:WordDocument&gt;<BR>&nbsp;&nbsp;&lt;w:PunctuationKerning&gt;<BR>&nbsp;&nbsp;&lt;w:DrawingGridVerticalSpacing&gt;7.8&nbsp;磅&lt;/w:DrawingGridVerticalSpacing&gt;<BR>&nbsp;&nbsp;&lt;w:DisplayHorizontalDrawingGridEvery&gt;0&lt;/w:DisplayHorizontalDrawingGridEvery&gt;<BR>&nbsp;&nbsp;&lt;w:DisplayVerticalDrawingGridEvery&gt;2&lt;/w:DisplayVerticalDrawingGridEvery&gt;<BR>&nbsp;&nbsp;&lt;w:Compatibility&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;w:SpaceForUL&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;w:BalanceSingleByteDoubleByteWidth&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;w:DoNotLeaveBackslashAlone&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;w:ULTrailSpace&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;w:DoNotExpandShiftReturn&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;w:AdjustLineHeightInTable&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;w:UseFELayout&gt;<BR>&nbsp;&nbsp;&lt;/w:Compatibility&gt;<BR>&nbsp;&lt;/w:WordDocument&gt;<BR>&lt;/xml&gt;&lt;![endif]--&gt;<BR>&lt;style&gt;<BR>&lt;!--<BR>&nbsp;/*&nbsp;Font&nbsp;Definitions&nbsp;*/<BR>@font-face<BR>&nbsp;&nbsp;&nbsp;&nbsp;{font-family:宋体;<BR>&nbsp;&nbsp;&nbsp;&nbsp;panose-1:2&nbsp;1&nbsp;6&nbsp;0&nbsp;3&nbsp;1&nbsp;1&nbsp;1&nbsp;1&nbsp;1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-alt:SimSun;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-charset:134;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-generic-font-family:auto;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-pitch:variable;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-signature:3&nbsp;135135232&nbsp;16&nbsp;0&nbsp;262145&nbsp;0;}<BR>@font-face<BR>&nbsp;&nbsp;&nbsp;&nbsp;{font-family:"\@宋体";<BR>&nbsp;&nbsp;&nbsp;&nbsp;panose-1:2&nbsp;1&nbsp;6&nbsp;0&nbsp;3&nbsp;1&nbsp;1&nbsp;1&nbsp;1&nbsp;1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-charset:134;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-generic-font-family:auto;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-pitch:variable;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-signature:3&nbsp;135135232&nbsp;16&nbsp;0&nbsp;262145&nbsp;0;}<BR>&nbsp;/*&nbsp;Style&nbsp;Definitions&nbsp;*/<BR>p.MsoNormal,&nbsp;li.MsoNormal,&nbsp;div.MsoNormal<BR>&nbsp;&nbsp;&nbsp;&nbsp;{mso-style-parent:"";<BR>&nbsp;&nbsp;&nbsp;&nbsp;margin:0cm;<BR>&nbsp;&nbsp;&nbsp;&nbsp;margin-bottom:.0001pt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;text-align:justify;<BR>&nbsp;&nbsp;&nbsp;&nbsp;text-justify:inter-ideograph;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-pagination:none;<BR>&nbsp;&nbsp;&nbsp;&nbsp;font-size:10.5pt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-bidi-font-size:12.0pt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;font-family:"Times&nbsp;New&nbsp;Roman";<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-fareast-font-family:宋体;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-font-kerning:1.0pt;}<BR>&nbsp;/*&nbsp;Page&nbsp;Definitions&nbsp;*/<BR>@page<BR>&nbsp;&nbsp;&nbsp;&nbsp;{mso-page-border-surround-header:no;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-page-border-surround-footer:no;}<BR>@page&nbsp;Section1<BR>&nbsp;&nbsp;&nbsp;&nbsp;{size:595.3pt&nbsp;841.9pt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;margin:72.0pt&nbsp;90.0pt&nbsp;72.0pt&nbsp;90.0pt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-header-margin:42.55pt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-footer-margin:49.6pt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;mso-paper-source:0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;layout-grid:15.6pt;}<BR>div.Section1<BR>&nbsp;&nbsp;&nbsp;&nbsp;{page:Section1;}<BR>--&gt;<BR>&lt;/style&gt;<BR>&lt;/head&gt;</P>
<P>&lt;body&nbsp;lang=ZH-CN&nbsp;style='tab-interval:21.0pt;text-justify-trim:punctuation'&gt;</P>
<P>&lt;div&nbsp;class=Section1&nbsp;style='layout-grid:15.6pt'&gt;</P>
<P><BR>&lt;table&nbsp;border=1&nbsp;cellspacing=0&nbsp;cellpadding=0&nbsp;style='border-collapse:collapse;<BR>&nbsp;border:none;mso-border-alt:solid&nbsp;windowtext&nbsp;.5pt;mso-padding-alt:0cm&nbsp;5.4pt&nbsp;0cm&nbsp;5.4pt'&gt;<BR>&nbsp;&lt;tr&gt;<BR>&nbsp;&nbsp;&lt;td&nbsp;width=189&nbsp;valign=top&nbsp;style='width:142.0pt;border:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;padding:0cm&nbsp;5.4pt&nbsp;0cm&nbsp;5.4pt'&gt;<BR>&nbsp;&nbsp;&lt;p&nbsp;class=MsoNormal&gt;&lt;span&nbsp;style='font-family:宋体;mso-ascii-font-family:"Times&nbsp;New&nbsp;Roman";<BR>&nbsp;&nbsp;mso-hansi-font-family:"Times&nbsp;New&nbsp;Roman"'&gt;用户名&lt;/span&gt;&lt;/p&gt;<BR>&nbsp;&nbsp;&lt;/td&gt;<BR>&nbsp;&nbsp;&lt;td&nbsp;width=189&nbsp;valign=top&nbsp;style='width:142.05pt;border:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;border-left:none;mso-border-left-alt:solid&nbsp;windowtext&nbsp;.5pt;padding:0cm&nbsp;5.4pt&nbsp;0cm&nbsp;5.4pt'&gt;<BR>&nbsp;&nbsp;&lt;p&nbsp;class=MsoNormal&gt;&lt;span&nbsp;style='font-family:宋体;mso-ascii-font-family:"Times&nbsp;New&nbsp;Roman";<BR>&nbsp;&nbsp;mso-hansi-font-family:"Times&nbsp;New&nbsp;Roman"'&gt;真实姓名&lt;/span&gt;&lt;/p&gt;<BR>&nbsp;&nbsp;&lt;/td&gt;<BR>&nbsp;&nbsp;&lt;td&nbsp;width=189&nbsp;valign=top&nbsp;style='width:142.05pt;border:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;border-left:none;mso-border-left-alt:solid&nbsp;windowtext&nbsp;.5pt;padding:0cm&nbsp;5.4pt&nbsp;0cm&nbsp;5.4pt'&gt;<BR>&nbsp;&nbsp;&lt;p&nbsp;class=MsoNormal&gt;&lt;span&nbsp;style='font-family:宋体;mso-ascii-font-family:"Times&nbsp;New&nbsp;Roman";<BR>&nbsp;&nbsp;mso-hansi-font-family:"Times&nbsp;New&nbsp;Roman"'&gt;性别&lt;/span&gt;&lt;/p&gt;<BR>&nbsp;&nbsp;&lt;/td&gt;<BR>&nbsp;&lt;/tr&gt;<BR>&lt;%<BR>Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");&nbsp;</P>
<P>String&nbsp;url="jdbc:odbc:mydb";</P>
<P>//连接mydb数据库<BR>Connection&nbsp;con=DriverManager.getConnection&nbsp;(url,&nbsp;"",&nbsp;"");&nbsp;</P>
<P>try{<BR>&nbsp;&nbsp;Statement&nbsp;stmt=con.createStatement();&nbsp;</P>
<P>&nbsp;&nbsp;//查询employee表<BR>&nbsp;&nbsp;ResultSet&nbsp;rs=stmt.executeQuery("select&nbsp;user_name,&nbsp;real_name,&nbsp;gender&nbsp;from&nbsp;employee&nbsp;");</P>
<P>&nbsp;&nbsp;while(rs.next()){<BR>%&gt;</P>
<P>&nbsp;&lt;tr&gt;<BR>&nbsp;&nbsp;&lt;td&nbsp;width=189&nbsp;valign=top&nbsp;style='width:142.0pt;border:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;border-top:none;mso-border-top-alt:solid&nbsp;windowtext&nbsp;.5pt;padding:0cm&nbsp;5.4pt&nbsp;0cm&nbsp;5.4pt'&gt;<BR>&nbsp;&nbsp;&lt;p&nbsp;class=MsoNormal&gt;&lt;span&nbsp;lang=EN-US&gt;&lt;%=rs.getString("user_name")%&gt;&lt;/span&gt;&lt;/p&gt;<BR>&nbsp;&nbsp;&lt;/td&gt;<BR>&nbsp;&nbsp;&lt;td&nbsp;width=189&nbsp;valign=top&nbsp;style='width:142.05pt;border-top:none;border-left:<BR>&nbsp;&nbsp;none;border-bottom:solid&nbsp;windowtext&nbsp;.5pt;border-right:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;mso-border-top-alt:solid&nbsp;windowtext&nbsp;.5pt;mso-border-left-alt:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;padding:0cm&nbsp;5.4pt&nbsp;0cm&nbsp;5.4pt'&gt;<BR>&nbsp;&nbsp;&lt;p&nbsp;class=MsoNormal&gt;&lt;span&nbsp;style='font-family:宋体;mso-ascii-font-family:"Times&nbsp;New&nbsp;Roman";<BR>&nbsp;&nbsp;mso-hansi-font-family:"Times&nbsp;New&nbsp;Roman"'&gt;&lt;%=rs.getString("real_name")%&gt;&lt;/span&gt;&lt;/p&gt;<BR>&nbsp;&nbsp;&lt;/td&gt;<BR>&nbsp;&nbsp;&lt;td&nbsp;width=189&nbsp;valign=top&nbsp;style='width:142.05pt;border-top:none;border-left:<BR>&nbsp;&nbsp;none;border-bottom:solid&nbsp;windowtext&nbsp;.5pt;border-right:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;mso-border-top-alt:solid&nbsp;windowtext&nbsp;.5pt;mso-border-left-alt:solid&nbsp;windowtext&nbsp;.5pt;<BR>&nbsp;&nbsp;padding:0cm&nbsp;5.4pt&nbsp;0cm&nbsp;5.4pt'&gt;<BR>&nbsp;&nbsp;&lt;p&nbsp;class=MsoNormal&gt;&lt;span&nbsp;style='font-family:宋体;mso-ascii-font-family:"Times&nbsp;New&nbsp;Roman";<BR>&nbsp;&nbsp;mso-hansi-font-family:"Times&nbsp;New&nbsp;Roman"'&gt;&lt;%=rs.getString("gender")%&gt;&lt;/span&gt;&lt;/p&gt;<BR>&nbsp;&nbsp;&lt;/td&gt;<BR>&nbsp;&lt;/tr&gt;</P>
<P>&lt;%<BR>&nbsp;&nbsp;}&nbsp;//&nbsp;end&nbsp;while<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;rs.close();<BR>&nbsp;&nbsp;stmt.close();<BR>}&nbsp;finally&nbsp;{<BR>&nbsp;&nbsp;con.close();<BR>}<BR>%&gt;&nbsp;<BR>&nbsp;<BR>&lt;/table&gt;</P>
<P>&lt;p&nbsp;class=MsoNormal&gt;&lt;span&nbsp;lang=EN-US&gt;&lt;![if&nbsp;!supportEmptyParas]&gt;&nbsp;&lt;![endif]&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;</P>
<P>&lt;/div&gt;</P>
<P>&lt;/body&gt;</P>
<P>&lt;/html&gt;<IMG height=20 src="http://www.blogjava.net/Emoticons/QQ/smile.gif" width=20 border=0></P><img src ="http://www.blogjava.net/Ben/aggbug/26772.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ben/" target="_blank">Ben</a> 2006-01-05 20:00 <a href="http://www.blogjava.net/Ben/archive/2006/01/05/26772.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转贴]2005年11月程序语言世界排行榜-Java居首位 </title><link>http://www.blogjava.net/Ben/archive/2005/12/23/25237.html</link><dc:creator>Ben</dc:creator><author>Ben</author><pubDate>Fri, 23 Dec 2005 08:53:00 GMT</pubDate><guid>http://www.blogjava.net/Ben/archive/2005/12/23/25237.html</guid><wfw:comment>http://www.blogjava.net/Ben/comments/25237.html</wfw:comment><comments>http://www.blogjava.net/Ben/archive/2005/12/23/25237.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ben/comments/commentRss/25237.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ben/services/trackbacks/25237.html</trackback:ping><description><![CDATA[<DIV style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all">摘要：<BR>近日来，在TIOBE程序员社区中公布了其2005年11月的程序语言排行榜。这得注意的是PHP即将超过C++成为了排行榜的老三！而Java作为开源先锋首当其冲的成为了龙头老大，并且仍然保持着很好的增长势头。<BR><BR><BR><BR>转载：转载请保留本信息，本文来自<A href="http://www.matrix.org.cn/resource/news/315.html" target=_blank><U><FONT color=#800080>http://www.matrix.org.cn/resource/news/315.html</FONT></U></A> <BR><BR><BR><FONT color=red>版权申明：</FONT>转载必须保留以下信息<BR>
<CENTER>作者：cleverpig</CENTER><BR>
<CENTER>可以自由转载, 转载请保留下面的作者信息:</CENTER><BR>
<CENTER>作者 cleverpig(<A href="http://www.matrix.org.cn/blog/cleverpig" target=_blank><U><FONT color=#0000ff>http://www.matrix.org.cn/blog/cleverpig</FONT></U></A>)</CENTER><BR><BR>近日来，在TIOBE程序员社区中公布了其2005年11月的程序语言排行榜。这得注意的是PHP即将超过C++成为了排行榜的老三！而Java作为开源先锋首当其冲的成为了龙头老大，并且仍然保持着很好的增长势头。<BR><BR>这个排行榜每月更新一次，其排名顺序按照世界范围内的技术工程师、讲师、第三方厂商的调查依据，并查询了目前流行的搜索引擎：Google,MSN,Yahoo，结合前两者的数据计算后得出的。根据TIOBE的观点，此排行榜是被程序员们用来检查自己的程序技能是否过时，或者作为建立新的软件系统时进行参考之依据，并非意味着哪种语言是最好的。<BR><BR>1。世界前20位语言排行榜：<BR><BR><IMG alt="" src="http://www.matrix.org.cn/resource/upload/forum/2005_11_25_104159_ccyqPFcFFs.jpg" border=0><BR><IMG alt="" src="http://www.matrix.org.cn/resource/upload/forum/2005_11_25_104206_scDpPaCkWo.jpg" border=0><BR><BR>2。世界前10位语言在前五年内长期发展趋势图：<BR><BR><IMG alt="" src="http://www.matrix.org.cn/resource/upload/forum/2005_11_25_112025_FyhUVRBDYn.jpg" border=0><BR><BR><BR>3。世界前30-50位语言排行榜：<BR><BR><IMG alt="" src="http://www.matrix.org.cn/resource/upload/forum/2005_11_25_104212_fyLjnFxVAM.jpg" border=0><BR><BR><IMG alt="" src="http://www.matrix.org.cn/resource/upload/forum/2005_11_25_104218_iJOANMNmFu.jpg" border=0><BR><BR><IMG alt="" src="http://www.matrix.org.cn/resource/upload/forum/2005_11_25_104224_gknaHBuewV.jpg" border=0><BR><BR>图示说明：<BR>* <FONT color=blue>(Position)</FONT>：此列表明当前语言与去年位置的变化。<BR>* <FONT color=blue>Ratings</FONT>：在查询搜索引擎计算排名顺序时使用了 '+"<LANGUAGE> programming" -tv -channel'公式，对上12个月内Google，MSN，Yahoo！和Google新闻组的数据进行查询。注意此公式应用于标准的Google web点击率、标准的MSN web点击率、标准的Yahoo！web点击率和标准的Google新闻组点击率。这里的“标准”意味着一次对前50位语言web点击率总和的查询是均匀分布的，即保证了排名的相对公正性和科学性。<BR>* <FONT color=blue>(Ratings)</FONT>： 此列表明当前语言在上12个月内的排名变化。<BR>* <FONT color=blue>Status</FONT>：带有“A”的程序语言被认为是主流语言。<BR>带有“A-”和“A--”表示程序语言位于“A”和“B”之间。<BR>从支持能力的观点看，尽量在工业的、任务危机的软件系统中使用带有“A”的主流程 序语言。<BR>如果某种语言在上3个月内具有超过0.7%的增长率，则此语言将获得“A”状态。上两个月内具有超过0.7%的增长率的程序语言相应的将获得“A--”和“A-”状态。</DIV><!-- / message --><img src ="http://www.blogjava.net/Ben/aggbug/25237.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ben/" target="_blank">Ben</a> 2005-12-23 16:53 <a href="http://www.blogjava.net/Ben/archive/2005/12/23/25237.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Jsp如何实现网页的重定向</title><link>http://www.blogjava.net/Ben/archive/2005/12/20/24785.html</link><dc:creator>Ben</dc:creator><author>Ben</author><pubDate>Tue, 20 Dec 2005 06:26:00 GMT</pubDate><guid>http://www.blogjava.net/Ben/archive/2005/12/20/24785.html</guid><wfw:comment>http://www.blogjava.net/Ben/comments/24785.html</wfw:comment><comments>http://www.blogjava.net/Ben/archive/2005/12/20/24785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ben/comments/commentRss/24785.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ben/services/trackbacks/24785.html</trackback:ping><description><![CDATA[转自&nbsp; 豆豆技术网<BR>1．可以使用： <BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　response.sendRedirect("http://www.foo.com/path/error.html"); </TD></TR></TBODY></TABLE><BR>　　2．可以手工修改HTTP header的Location属性，如下：<BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜% <BR>response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); <BR>String newLocn = "/newpath/index.html"; <BR>response.setHeader("Location",newLocn); <BR>%＞ </TD></TR></TBODY></TABLE><BR>　　3．也可以使用forward: <BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　＜jsp:forward page="/newpage.jsp" /＞ </TD></TR></TBODY></TABLE><BR>　　请注意：只能在任何输出还没有发送到客户端之前使用这种方式。<BR><BR>　　<B>5.6 类似global.asa的做法 </B><BR><BR>　　在JSP中没有global.asa的对应物。但可以有一个workaround来运行。例如，如果你需要存储或存取application scope变量，你总是可以创建一个Javabean，并在页面中需要这些变量的地方将它包含进来。 <BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜jsp:useBean id="globals" scope="application" class="com.xxx.GlobalBean"/＞ </TD></TR></TBODY></TABLE><BR>　　但是，也有一些产品具有这样的对应：<BR><BR>　　Allaire公司的产品JRun 3.0将提供global.jsa。JRun 2.3.3仍然给予支持，但只对JSP 0.92。当JRun 3.0最终推出时它将支持用于JSP 1.0和1.1的global.jsa。 <BR><BR>　　你可以从http://beta.allaire.com/jrun30得到JRun 3.0 beta 5 <BR><BR>　　另外，Oracle的JSP支持globals.jsa。 <BR><BR>　　<B>5.7 jsp显示当前时间 </B><BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜%@ page import="Java.util.*, Java.text.*" %＞<BR>＜HTML＞<BR>＜HEAD＞<BR>＜TITLE＞JSP to display the current time＜/TITLE＞<BR>＜/HEAD＞<BR>＜BODY＞<BR>The current time is: <BR>＜%<BR>Date now = new Date();<BR>out.println(DateFormat.getTimeInstance().format(now));<BR>%＞<BR>＜/BODY＞<BR>＜/HTML＞ </TD></TR></TBODY></TABLE><BR>　　<B>5.8在JSP中创建目录 Mkdir(String path) </B><BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜%@ page import="Java.io.*" %＞<BR>＜%!<BR>String Mkdir(String path) <BR>{<BR>String msg=null;<BR>Java.io.File dir;<BR><BR>// 新建文件对象<BR>dir =new Java.io.File(path);<BR>if (dir == null) {<BR>msg = "错误原因:＜BR＞对不起，不能创建空目录！";<BR>return msg;<BR>}<BR>　　　　if (dir.isFile()) {<BR>　　　　msg = "错误原因:＜BR＞已有同名文件＜B＞" + dir.getAbsolutePath() + "＜/B＞存在。";<BR>　　　　return msg;<BR>　　　　}<BR>　　　　if (!dir.exists()) <BR>{<BR>　　　　boolean result = dir.mkdirs();<BR>　　　　　　　　if (result == false) {<BR>　　　　msg = "错误原因:＜BR＞目录＜b＞" + dir.getAbsolutePath() + "＜/B＞创建失败，原因不明！";<BR>　　　　　　　　return msg;<BR>　　　　}<BR>　　　// 如果成功创建目录，则无输出。<BR>　　　　// msg ="成功创建目录: ＜B＞" + dir.getAbsolutePath() + "＜/B＞";<BR>　　　　return msg;<BR>　　　　}<BR>　　else {<BR>　　　　　　msg = "错误原因:＜BR＞目录＜b＞" + dir.getAbsolutePath() + "＜/b＞已存在。";<BR>　　　　}<BR>　　return msg;<BR>}<BR>%＞<BR>＜%<BR>String filepath = "/usr/home/hoyi/html/dir";<BR>String opmsg = Mkdir(filepath);<BR>%＞ </TD></TR></TBODY></TABLE><BR>　　<B>5.9将return 转为＜br＞函数 </B><BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>public static String returnToBr(String sStr)<BR>{<BR>if (sStr == null // sStr.equals("")) <BR>{<BR>return sStr;<BR>} <BR><BR>String sTmp = new String();<BR>int i = 0; <BR><BR>while (i ＜= sStr.length()-1)<BR>{<BR>if (sStr.charAt(i) == '\n')<BR>{<BR>sTmp = sTmp.concat("＜br＞");<BR>}<BR>else<BR>{ <BR>sTmp = sTmp.concat(sStr.substring(i,i+1));<BR>}<BR>i++;<BR>}<BR>return sTmp;<BR>}<BR></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/Ben/aggbug/24785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ben/" target="_blank">Ben</a> 2005-12-20 14:26 <a href="http://www.blogjava.net/Ben/archive/2005/12/20/24785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SWT……内幕？</title><link>http://www.blogjava.net/Ben/archive/2005/12/12/23528.html</link><dc:creator>Ben</dc:creator><author>Ben</author><pubDate>Mon, 12 Dec 2005 10:23:00 GMT</pubDate><guid>http://www.blogjava.net/Ben/archive/2005/12/12/23528.html</guid><wfw:comment>http://www.blogjava.net/Ben/comments/23528.html</wfw:comment><comments>http://www.blogjava.net/Ben/archive/2005/12/12/23528.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ben/comments/commentRss/23528.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ben/services/trackbacks/23528.html</trackback:ping><description><![CDATA[注: 转载至 JR&nbsp;&nbsp; 
<TABLE cellSpacing=0 cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD class=title1 align=middle width="100%" bgColor=#eeeeee colSpan=3 height=40><B>SWT……内幕？</B></TD></TR>
<TR>
<TD align=middle width="100%" bgColor=#eeeeee><A href="http://www.javaresearch.org/profile.jsp?user=4104">FooSleeper</A></TD></TR></TBODY></TABLE><STRONG>原文：<BR></STRONG><A class=l2 href="http://groups.yahoo.com/group/straight_talking_java/" target=_blank>http://groups.yahoo.com/group/straight_talking_java/</A><BR><A class=l2 href="http://groups.yahoo.com/group/straight_talking_java/messages/24236" target=_blank>http://groups.yahoo.com/group/straight_talking_java/messages/24236</A><BR><BR><B>翻译整理：</B>FooSleeper<BR><B>最后修改：</B>2004-03-03<BR><BR><BR><B>译注：</B>本文来自<A class=l2 href="mailto:straight_talking_java@yahoogroups.com" target=_blank>straight_talking_java@yahoogroups.com</A>讨论组，已经是一年多前的文章。Alan&nbsp;Williamson是Java&nbsp;Developers&nbsp;Journal的编辑，下文来自他在IBM的一个消息来源。SWT和Swing的论争我见过不少，Netbeans和Eclipse的也同样多。译者翻译此文并不是要激起什么争执，也不是支持哪一方（虽然我的确是站在SWT一边的），更不是要攻击Amy。我最重要的理由是，这是一篇有趣的文章。里面有内幕、线人、公司政治、垄断巨头、美女、商界风云……足够拍一出电影。有趣，这就够了。不过此文反映了IBM对Swing的看法和SWT的由来，还是有一点营养的。<BR><BR><B>From:&nbsp;</B>&nbsp;Alan&nbsp;Williamson&nbsp;&lt;<A class=l2 href="mailto:alan@n-ary.com" target=_blank>alan@n-ary.com</A>&gt;<BR><B>Date:&nbsp;</B>&nbsp;Wed&nbsp;Nov&nbsp;6,&nbsp;2002&nbsp;&nbsp;10:31&nbsp;am&nbsp;<BR><B>Reply-To:&nbsp;</B>&lt;<A class=l2 href="mailto:straight_talking_java@yahoogroups.com" target=_blank>straight_talking_java@yahoogroups.com</A>&gt;<BR><B>To:&nbsp;</B>&lt;<A class=l2 href="mailto:straight_talking_java@yahoogroups.com" target=_blank>straight_talking_java@yahoogroups.com</A>&gt;<BR><B>Subject:&nbsp;</B>&nbsp;SWT&nbsp;...&nbsp;the&nbsp;scoop?（SWT……内幕？）<BR><BR>好了这就来……阅读……消化……再阅读……再消化……<BR>;-)&nbsp;<BR><BR>--------------------------------<BR>谢谢你的回复。我很乐意给你提供Swing和SWT背后的一些信息，既然你还把我当作你秘密的“IBM内幕线人”。<BR><BR>要想弄清楚为什么一切都被弄得如此混乱，要从几年前只存在AWT的时候说起。SUN当时已经建立了一套基本的可移植控件类，这些类映射到不同操作系统上的原生窗口组件（native&nbsp;widget），显然下一步应该继续增强这套模型，除了初始的CUA&nbsp;92组件（文字、按钮等等），再继续加上表格、树、记事本、滑块等等……当时的AWT还满是漏洞，远不能称为可靠，还需要SUN的coder们去修补。SUN的developer们如Graham和Otto总是习惯于公开把他们的bug归咎为操作系统的差异，比如“Windows和OS/2的焦点次序不同”或者“在……之间Ctrl-X的行为不一样”，以及其他苍白的托辞，好让批评的火力从SUN太早释出代码这个问题的真相上移开。然后Amy&nbsp;Fowler来到了SUN。不是我大男子主义，Amy是个聪明的美女，大多数呆头呆脑只懂技术的开发人员都要被她捏在手里。<BR><BR>Amy来自一家Smalltalk公司，叫做Objectshare，在那里她负责搞UI类库。跟Java相比Smalltalk的历史有些悲惨，曾几何时有3家庞大的Smalltalk公司——IBM、Parc-Place和Digitalk。在90年代初期3家公司的市场份额大致相等，生活是美好的。Parc-Place采用仿窗口部件（emulated&nbsp;widgets）的设计（即Swing的设计），IBM和Digitalk则采用原生窗口部件（native&nbsp;widgets）。后来IBM压倒了另外两家，因此他们打算合并成一家，假设叫做Parc-Place&nbsp;Digitalk。随后当他们试图将他们的产品融合到一个叫做Jigsaw的计划中时爆发了一场大战，计划由于政治原因失败了（开发人员实际上已经能让它运转起来），就因为原生和仿造两派的死战。Amy赢得了精神上的胜利，不过在IBM我们赢得了他们所有的生意，因为这两家公司在一整年里除了吵架什么都没做。当尘埃落定之后PPD（Parc-Place&nbsp;Digitalk当时已改名为Objectshare，跟Windscale改名为Sellafield的原因相同——让人们淡忘之前发生的灾难）的股票价格从60美元掉到了低于1美元1股。他们因为伪报收入被NASDAQ摘牌，从此消失。此时SUN正走上与PPD类似的技术方向，于是PDD的技术人员都把他们的简历投到了SUN。Amy被雇佣了，她承诺通过轻量级方案解决所有窗口组件的问题，因此说服SUN管理层让她当了GUI开发部门的头头。她是拿着“这里原来的人都搞砸了，我是来解决的”的钥匙进来的。随后Amy雇佣了所有她过去在Parc-Place的旧朋友，让他们来开发Swing。<BR><BR>显然Swing应该做的是仅仅成为一个绘制框架，给那些希望创建地图软件或者绘图软件的人们使用，无论如何，应该围绕AWT类库来建造它，按钮之类的东西仍然交给AWT来管。SUN的人比如Philip和Mark已经让AWT能够处理表格、树和记事本（notebook，？），所以Swing的方向应该说很明显了。但那些毁了PDD的人不干，他们非要把一切都弄成轻量级的。由于SUN管理层的无知，再加上Amy无情的政治手段，造成了我们今天所见的混乱局面。Amy还使SUN相信Swing是作为Mozilla项目的一部分与Netscape联合开发的，事实上这只是她的宣传伎俩。<BR><BR>在IBM，我们从第一天起就憎恶Swing。庞大、满是错误，而且难看至极。原先我们的工具如VisualAge&nbsp;for&nbsp;Java都是用Smalltalk（用的是原生窗口组件）写的，所以当我们将这些工具向Java代码库迁移时，我们需要一套窗口组件。IBM这边的开发人员都是原来搞Smalltalk的那一批人，我们对管理层要求用Swing来构建WebSphere&nbsp;Studio工具都非常不情愿。Swing是个可怕的充满缺陷的怪兽。在WebSphere&nbsp;Studio最初的预览中，当与Microsoft&nbsp;Visual&nbsp;Studio作对比演示的时候，我们所有的客户都讨厌它，就因为它的外观，而不管它的功能有多强。大多数消费者都不会买一辆让人觉得难看的车，哪怕这车有一台出色的引擎。因此我们开始了一个项目，是把我们的Smalltalk原生窗口组件移植到Java上去。这个项目是加拿大的Object&nbsp;Technology&nbsp;International小组做的。这个项目获得了成功，被运用在在我们发布的VisualAge&nbsp;Micro&nbsp;Edition产品中，VisualAge&nbsp;Micro&nbsp;Edition后来成为J2ME开发方面一个非常成功的IDE。但是OTI的人发现，Swing在读取Windows事件方面有极严重的缺陷，我们甚至无法进行SWT（S开始是Simple的缩写，不过后来变成了Standard的缩写）和Swing间的互操作。他们在读事件队列的时候用了一种可能留下内存漏洞的方式，所以我们不得不采用我们自己的查询Windows事件队列的循环，以纠正这个错误。我们试了一次又一次让SUN修复这个错误，但Amy就是听不进去，所以我们才决定SWT和AWT/Swing不能共存。我们甚至在SWT中定义了自己的Point和Rectangle类——整个工具包对AWT或Swing都没有任何依赖。我们把这个工具包放到了Eclipse中，这是一个工具平台，它的总体设计目标就是要战胜Micrsoft和Visual&nbsp;Studio。Eclipse是开源的，所以任何人都可以在上面构建自己的东西，我们已经有像TogetherSoft和Rational这样的公司移植到了上面。我们的竞争者是Microsoft，所以我们所有努力和注意力都是从正面针对Microsoft。<BR><BR>不管怎么说SUN对此非常不满。他们的Netbeans跟Eclipse做的是相同的事，因此他们向IBM高层抱怨。他们认为SWT是要将你绑到Windows上，这纯粹是胡说，因为SWT能通过GTK在Mac/Linux上运行，以及一大堆嵌入式平台。他们拒绝让Eclipse获得Java认证，因为里面有原生代码，所以Eclipse产品必须很小心地使用单词“Java”这个SUN的商标。Eclipse甚至不能把自己称为一个Java&nbsp;IDE，SUN已经威胁过要采取法律行动来制止IBM在任何时候把Eclipse称作一个Java&nbsp;IDE。结果之一就是IBM在Eclipse上创建的GUI设计工具，允许你构建Swing/AWT&nbsp;GUI，却不让你往里面拖放SWT窗口控件。<BR><BR>将SWT从Eclipse中分离出来是完全可能的，只需要把DLL抠出来放到路径中，并使用窗口组件工具包来给你的银行或者保险或者其他什么应用程序开发GUI。再次说明，我们无法更进一步，因为SUN把我们的双手绑上了。虽然作为Eclipse开放源码协议的一部分，CPL允许我们提供这样的解决方案，但SUN已经很清楚地表明他们不希望我们这样做。<BR><BR>对于用户社区来说，无论IBM和SUN的最终动机是什么，我发现有一点总是很有趣：喜爱Swing的人总会说“一旦你花上几年时间去掌握它，你就能正确地使用它”，这基本上是他们在试图证明和维护他们辛苦得来的用途有限的专门技术；而SWT的拥护者们说的是“哇，这真快，这跟原生的一样，还可以用XP皮肤……它还又轻又小”。有一句话是我喜欢的，我们的一个用户说，Swing就像Java决定不通过操作系统来实现原生的IO，而是通过磁头马达API自己来读磁盘的扇区。Swing基本上就是这样的，它拿着个底层的“paint(Graphics)”方法，自己来绘制所有的窗口组件。<BR>--------------------------------<BR><BR><B>后记：</B>现在的情况已经有所不同，SWT到底还是单独发布了，VE也承诺在1.0版的时候支持SWT的GUI设计。&nbsp; <BR><img src ="http://www.blogjava.net/Ben/aggbug/23528.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ben/" target="_blank">Ben</a> 2005-12-12 18:23 <a href="http://www.blogjava.net/Ben/archive/2005/12/12/23528.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>