<?xml version="1.0" encoding="gb2312"?>

<!-- RSS generated by oioj.net on 4/16/2004 ; 感谢LeXRus提供 RSS 2.0 文档; 此文件可自由使用，但请保留此行信息 --> 
<!-- Source download URL: http://blogger.org.cn/blog/rss2.asp       -->
<rss version="2.0">

<channel>
<title>邢红瑞的blog</title>
<link>http://blogger.org.cn/blog/blog.asp?name=hongrui</link>
<description>邢红瑞的博客</description>
<copyright>blogger.org.cn</copyright>
<generator>W3CHINA Blog</generator>
<webMaster>webmaster@blogger.org.cn</webMaster>
<item>
<title><![CDATA[java如何从一个字符串中删除空格]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49653</link>
<author>hongrui</author>
<pubDate>2010-8-27 15:31:40</pubDate>
<description><![CDATA[<P>仔细想了一下 两种方法</P>
<P>1.4 之前的</P>
<P>&nbsp;public static String removeSpaces(String s) {<BR>&nbsp; StringTokenizer st = new StringTokenizer(s," ",false);<BR>&nbsp; String t="";<BR>&nbsp; while (st.hasMoreElements()) t += st.nextElement();<BR>&nbsp; return t;<BR>}</P>
<P>1.4之后的</P>
<P>&nbsp;public static String ltrim(String source) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return source.replaceAll(" ", "");<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>使用正则</P>
<P>&nbsp;public static String ltrim(String source) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return source.replaceAll("<A href="file://\\s">\\s</A>", "");<BR>&nbsp;&nbsp;&nbsp; }</P>]]></description>
</item><item>
<title><![CDATA[64位RedHat下编译gnokii]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49603</link>
<author>hongrui</author>
<pubDate>2010-8-20 16:56:39</pubDate>
<description><![CDATA[
<P><A href="http://ftp.gnome.org/pub/gnome/sources/intltool/0.40/intltool-0.40.6.tar.gztar%20zxvf%20intltool-0.40.6.tar.gzcd%20intltool-0.40.6./configure%20make%20&amp;&amp;%20make%20install然后编译%20从http://www.gnokii.org/下载gnokii,并编译安装.[root@SAG]# tar jxvf gnokii-0.6.28.1.tar.bz2&nbsp; [root@SAG]# cd gnokii-0.6.28 [root@SAG]# ./configure[root@SAG]# gmake[root@SAG]# gmake install[root@SAG]#cp /usr/local/share/doc/gnokii/sample/gnokiirc&nbsp; /root/.gnokiirc[root@SAG]#vi ~/.gnokiirc">　64位linux 发送短信，需要gnokii，找了一下rpm 最近的也是0.6.19,安装后 还需要libxpm.so晕倒。发现0.6.24就不是要了。<BR>只有自己编译了。<BR>出现<BR>checking for intltool &gt;= 0.35.0... 0.31.2 found<BR>configure: error: Your intltool is too old.&nbsp; You need intltool 0.35.0 or later.<BR>解决办法如下：<BR>wget http://ftp.gnome.org/pub/gnome/sources/intltool/0.40/intltool-0.40.6.tar.gz<BR>tar zxvf intltool-0.40.6.tar.gz<BR>cd intltool-0.40.6<BR>./configure <BR>make &amp;&amp; make install<BR>然后编译 <BR>从http://www.gnokii.org/下载gnokii,并编译安装.<BR>[root@SAG]# tar jxvf gnokii-0.6.28.1.tar.bz2&nbsp; <BR>[root@SAG]# cd gnokii-0.6.28 <BR>[root@SAG]# ./configure<BR>[root@SAG]# gmake<BR>[root@SAG]# gmake install<BR>[root@SAG]#cp /usr/local/share/doc/gnokii/sample/gnokiirc&nbsp; /root/.gnokiirc<BR>[root@SAG]#vi ~/.gnokiirc</A></P>
<P>echo -e "SMS-TEST FROM Lenovo" | gnokii --sendsms 1581XXXX<BR>自己做的安装脚本<BR>cp -f ./gnokii /usr/local/bin/<BR>chmod a+x /usr/local/bin/gnokii<BR>cp -f ./lib*&nbsp; /usr/local/lib/<BR>cp -f ./.gnokiirc /root</P>]]></description>
</item><item>
<title><![CDATA[在Windows Visual C++ 8 下编译带ssl的curl]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49546</link>
<author>hongrui</author>
<pubDate>2010-8-12 18:37:57</pubDate>
<description><![CDATA[
<P><A>　编译openssl 0.9.8k： <BR>1． 安装Perl：ActivePerl-5.8.0.806-MSWin32-x861.msi<BR>2． 编译OpenSSL<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下载openssl，目前版本是：openssl-0.9.8k。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 解压，比如：c:\.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cd c:\openssl-0.9.8g<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; perl Configure VC-WIN32<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行ms\do_ms.bat<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行： ""C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 回到c:\openssl-0.9.8k，运行：nmake -f ms\nt.mak&nbsp; 声称静态库 不建议 nmake -f ms\ntdll.mak声称动态库，在out32dll目录下生成libeay32.dll, libeay32.lib, ssleay32.dll, ssleay32.lib</A></P>
<P>3． 编译Libcurl：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下载curl源代码，当前版本是curl-7.17.1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 解压 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行： ""C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set OPENSSL_PATH=c:\openssl-0.9.8k <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; curl目录中 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行 nmake vc-ssl' 生成 curl.exe <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'nmake vc-ssl-dll' 需要libeay32.dll ssleay32.dll</P>]]></description>
</item><item>
<title><![CDATA[redhat系列平台eclipse无法显示GBK编码]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49524</link>
<author>hongrui</author>
<pubDate>2010-8-6 16:43:32</pubDate>
<description><![CDATA[<P>准备在redhat中使用ecplipse cpp版本，发现以前的代码中中文全是乱码。打开Window--&gt;Preferences--&gt;General--&gt;Workspace--&gt;Text file encoding就没有GBK选项，后来发现可以直接输入GBK就可以。</P>
<P>Ubuntu支持GBK，.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改/var/lib/locales/supported.d/local文件,在文件中添加<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zh_CN.GBK GBK<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zh_CN.GB2312 GB2312<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sudo dpkg-reconfigure --force locales<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;输出</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zh_CN.GB2312 done<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zh_CN.GBK done&nbsp;&nbsp;</P>
<P>设置eclipse。<BR>&nbsp; 首先Windows-&gt;Preferences, 然后选择General下面的Workspace. Text file encoding选择Other GBK， 如果没有GBK的选项，&nbsp; 直接输入GBK，点击 Apply， OK。</P>]]></description>
</item><item>
<title><![CDATA[PCI-DSS标准之SSL Weak Encryption Algorithms解决方法(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49508</link>
<author>hongrui</author>
<pubDate>2010-8-2 16:08:09</pubDate>
<description><![CDATA[<P><A>　　PCI信用卡支付标准中弱点扫描对SSL的加密强度有要求，中级漏洞中是不能使用SSLv2级别的加密，而低级漏洞中直接报告加密强度不够。那么，该如何补救呢？<BR>　　中级漏洞好补，如果系统是Apache，那就ssl中配置SSLProtocol -ALL +SSLv3 +TLSv。如果是Tomcat，最好前面加个前置Pound，在Pound中设置ssl代理，加密强度Ciphers "HIGH:!SSLv2:!ADH:!aNULL:!eNULL:!NULL"即可。如果是resin，等会说。<BR>　　低级漏洞，如果是apache，那就SSLCipherSuite HIGH:!SSLv2:!ADH:!aNULL:!eNULL:!NULL即可。<BR>　　接下来说Resin，可怜的Resin啊，Resin缺省支持两种SSL方式，openssl和jsse-ssl，如果用openssl，可以提高加密强度，但是（重要），但是，这样根本无法应用于生产环境，网站的速度会慢到无法忍受的地步，会被客户大量投诉。没办法，只能使用jsse-ssl，Resinjsse-ssl的配法比较复杂，下面说一下配法：<BR>　　1. Resin必须是最新的professional的版本3.1.9，貌似3.1.6以上的版本才支持jsse-ssl中Ciphers的配置。<BR>　　2. Java1.6的配置：<BR>　　　　Java1.6必须配置成支持256的高加密强度：下载jce-policy-6.zip和jsse-1_0_3_04-gl.zip，把jsse-1_0_3_04-gl.zip解压出来的jcert.jar jnet.jar jsse.jar放入JAVA_HOME/jre/lib/ext目录下，把jce-policy-6.zip解压出来的local_policy.jar和US_export_policy.jar放入JAVA_HOME/jre/lib/security，替换掉原来的文件。<BR>import java.io.*;<BR>import java.security.*;<BR>import javax.net.ssl.*;<BR>import java.util.regex.*; </A></P>
<P>public class h {<BR>&nbsp; public static void main(String[] args) {<BR>&nbsp;&nbsp;&nbsp; try {&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLServerSocket sslSocket;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLServerSocketFactory sslSrvFact =<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SSLServerSocketFactory)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLServerSocketFactory.getDefault();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sslSocket =(SSLServerSocket)sslSrvFact.createServerSocket(8181);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int port = sslSocket.getLocalPort();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String [] cipherSuites = sslSocket.getEnabledCipherSuites();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i = 0; i &lt; cipherSuites.length; i++){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Cipher Suite " + i +" = " + cipherSuites[i]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sslSocket.close();<BR>&nbsp;&nbsp;&nbsp; } catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Exception" + e);<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp; }<BR>}<BR>运行结果如果显示２５６的字样就成功了。<BR>Cipher Suite 0 = SSL_RSA_WITH_RC4_128_MD5<BR>Cipher Suite 1 = SSL_RSA_WITH_RC4_128_SHA<BR>Cipher Suite 2 = TLS_RSA_WITH_AES_128_CBC_SHA<BR>Cipher Suite 3 = TLS_RSA_WITH_AES_256_CBC_SHA<BR>Cipher Suite 4 = TLS_DHE_RSA_WITH_AES_128_CBC_SHA<BR>Cipher Suite 5 = TLS_DHE_RSA_WITH_AES_256_CBC_SHA<BR>Cipher Suite 6 = TLS_DHE_DSS_WITH_AES_128_CBC_SHA<BR>Cipher Suite 7 = TLS_DHE_DSS_WITH_AES_256_CBC_SHA<BR>Cipher Suite 8 = SSL_RSA_WITH_3DES_EDE_CBC_SHA<BR>Cipher Suite 9 = SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA<BR>Cipher Suite 10 = SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA<BR>Cipher Suite 11 = SSL_RSA_WITH_DES_CBC_SHA<BR>Cipher Suite 12 = SSL_DHE_RSA_WITH_DES_CBC_SHA<BR>Cipher Suite 13 = SSL_DHE_DSS_WITH_DES_CBC_SHA<BR>Cipher Suite 14 = SSL_RSA_EXPORT_WITH_RC4_40_MD5<BR>Cipher Suite 15 = SSL_RSA_EXPORT_WITH_DES40_CBC_SHA<BR>Cipher Suite 16 = SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA<BR>Cipher Suite 17 = SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</P>
<P>运行openssl找出高强度加密方式对应的java ciphers<BR>openssl ciphers -v 'HIGH:!SSLv2:!ADH:!aNULL:!eNULL:!NULL'<BR>DHE-RSA-AES256-SHA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLv3 Kx=DH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Au=RSA&nbsp; Enc=AES(256)&nbsp; Mac=SHA1<BR>DHE-DSS-AES256-SHA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLv3 Kx=DH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Au=DSS&nbsp; Enc=AES(256)&nbsp; Mac=SHA1<BR>AES256-SHA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLv3 Kx=RSA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Au=RSA&nbsp; Enc=AES(256)&nbsp; Mac=SHA1<BR>KRB5-DES-CBC3-MD5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLv3 Kx=KRB5&nbsp;&nbsp;&nbsp;&nbsp; Au=KRB5 Enc=3DES(168) Mac=MD5<BR>KRB5-DES-CBC3-SHA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLv3 Kx=KRB5&nbsp;&nbsp;&nbsp;&nbsp; Au=KRB5 Enc=3DES(168) Mac=SHA1<BR>EDH-RSA-DES-CBC3-SHA&nbsp;&nbsp;&nbsp; SSLv3 Kx=DH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Au=RSA&nbsp; Enc=3DES(168) Mac=SHA1<BR>EDH-DSS-DES-CBC3-SHA&nbsp;&nbsp;&nbsp; SSLv3 Kx=DH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Au=DSS&nbsp; Enc=3DES(168) Mac=SHA1<BR>DES-CBC3-SHA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLv3 Kx=RSA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Au=RSA&nbsp; Enc=3DES(168) Mac=SHA1</P>
<P>基本匹配的就三个：<BR>TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_DSS_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA<BR>　　3. Resin3.1.9的配置：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;http port="443"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;jsse-ssl&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key-store-type&gt;jks&lt;/key-store-type&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key-store-file&gt;mykey.key&lt;/key-store-file&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;password&gt;mykey&lt;/password&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;cipher-suites&gt;TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_DSS_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA&lt;/cipher-suites&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/jsse-ssl&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/http&gt;</P>]]></description>
</item><item>
<title><![CDATA[SSL/TLS协议简介(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49505</link>
<author>hongrui</author>
<pubDate>2010-8-2 14:24:34</pubDate>
<description><![CDATA[密码技术 <BR>
<P>要了解SSL协议，首先要了解：加密算法、消息摘要算法（又称为哈希算法Hash），数字签名等概念。这些技术每个都可以写出一整本的书，它们结合在一起，提供了保密性、完整性和身份验证的功能。 </P><B><FONT class=header1>加密算法</FONT></B><BR>
<P>设想：ALICE想发消息给她的银行要汇出一笔款。ALICE希望这些消息是保密的，因为这里面包括她的帐户资料和汇款金额。一种办法是使用加密算法，这种技术将她要传递的消息变成经过加密的密文，直接银行解密才可以被读取。 如果采用这种形式，消息只能被一个密钥所加密。没有这个密钥，消息就是无用的。一个良好的加密算法，可以使入侵者面临无法克服困难来解密原文。</P>
<P>有两种加密算法系列：传统加密算法（对称加密）和公钥加密算法（非对称加密）</P><B><FONT class=header2>传统加密算法</FONT></B><BR>
<P>也称为对称加密，需要发送者和接收者共享一个密钥：同时用于加密和解密的信息。 只要密钥是保密的，除了收件人和发件人外没有人可以阅读该消息。如果Alice和银行知道这个密钥，那么他们可以给对方发送的经过此密钥加密的消息。这种算法的主要任务在于发送者和接收者如何共享一个密钥，同时确保没有第三方知道这个密钥，如果多人之间传递消息，如何保证这么多密钥的安全，就是一个棘手的问题。 </P><B><FONT class=header2>公钥加密算法</FONT></B><BR>
<P>也被称为非对称加密技术，通过使用2个密钥（其中一个可以解密另外一个加密的消息），解决了加密密钥交换的问题。 如果用其中的一个密钥用于加密信息，必须使用另外一个密钥来解密。这样就有可能获得简单地发布一个密钥（公钥），并使用未发布的密钥（私钥）来接受经过公钥加密的消息。 </P>
<P>任何人都可以使用公共密钥加密消息，但只有私钥拥有者将能够读取它。这样，ALICE可以在发送需要保密的汇款消息给银行的时候，可以使用银行的密钥对中的公钥来对这个消息进行加密，而只有银行可以使用他们自己保管的私钥来进行解密。</P><B><FONT class=header1>消息摘要算法</FONT></B><BR>
<P>虽然ALICE可以加密她的消息，但仍然有一个问题，就是有人可能会修改她发给银行的消息，并将ALICE的钱转移到自己的帐户上。为了保证ALICE消息在传递过程中没有被人篡改，可以让她创建一个消息的摘要和加密的消息一起寄到银行，银行收到消息后，将消息和消息的摘要做一个比较，如果消息内容和摘要匹配，则就可以证明消息传递过程中，没有别人篡改。</P>
<P>像这样的摘要被称为消息摘要， 单向函数或哈希函数 。消息摘要用于创建一个简短的固定长度，或可变长度的消息。消息摘要算法被设计成为每个消息产生一条独立的信息摘要。消息摘要算法的目的，就是让人无法为两条不同的消息找到相同的消息摘要，从而消除了使用一条摘要相同的消息替换另外一条消息的可能性。</P>
<P>另一个爱丽丝面临的挑战是找到一种方法，即使安全地将消息摘要发送到银行;如果消息摘要发送过程不安全，银行将无法判断消息是否就是来自ALICE。只有在消息摘要能安全地发送，才能够使消息的完整性被确定。</P>
<P>一个安全发送消息摘要的方式是使用数字签名。</P><B><FONT class=header1>数字签名</FONT></B><BR>
<P>当Alice将消息发送给银行，银行需要确保消息真正地是从她这里发出的，以确保入侵者不能使用她的帐户进行交易。 签名就是由ALICE为实现这一目的而创建的一个专门消息。 </P>
<P>数字签名主要使用私钥来加密消息摘要和其他信息，譬如一个序列号,虽然任何人都可以使用公钥解密数字签名，只有发送方知道私钥。这意味着，只有发件人可以签署了该消息。包含了信息摘要的签名表示这个签名只对这个消息有效，而且它确保了消息的完整性，即这个消息的发送过程中没人可以改变摘要并另外对它做签名。</P>
<P>为了防止入侵者拦截，并在以后再次使用这个签名，签名包含一个唯一的序列号。 这样可以保证ALICE无法否认她曾经发送过这条消息，因为只有她可以签名这条消息（不可抵赖性）。</P>
<TABLE cellSpacing=0 cellPadding=0 width=360>
<TBODY>
<TR>
<TD width=360 background=/images/dotted_bg.gif height=1></TD></TR></TBODY></TABLE><BR><B><FONT class=header>证书</FONT></B><BR>
<P>虽然ALICE给银行发出一条经过她个人私钥签名的消息，并且可以确保她发送的消息是真实可靠的，但她依然要确保她的确是和银行在通信。这意味着她必须确保她使用的公钥是银行密钥对中的公钥，而不是入侵者的。同样道理，银行业也需要核实用于签名该消息的私钥是属于ALICE的。如何使银行和ALICE能否核实对方的身份呢？</P>
<P>如果每个人的证书都由一个大家都信任的机构签名，那么每个人都可以验证其他有该证书的人的身份。这种被大家都信任的机构，称为认证中心（CA)，他们负责认证证书。</P><B><FONT class=header1>证书的内容</FONT></B><BR>
<P>证书内容包括：公钥和真实身份识别信息，包括个人，服务器或其他实体。如表1所示，主题信息包括身份识别信息（DN）和公钥。它还包括认证和签发的CA签发这个证书的有效期，还可能有一些其他的信息（或者成为扩展信息），一般由CA自行定义使用的管理信息，譬如序列号等。</P><FONT class=header2>表一：证书信息</FONT><BR>
<TABLE style="BORDER-RIGHT: #aaa 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #aaa 1px solid; MARGIN-TOP: 0.5em; PADDING-LEFT: 2px; MARGIN-BOTTOM: 0px; PADDING-BOTTOM: 2px; BORDER-LEFT: #aaa 1px solid; PADDING-TOP: 2px; BORDER-BOTTOM: #aaa 1px solid; BORDER-COLLAPSE: collapse">
<TBODY>
<TR>
<TD><FONT class=header2>主题（证书所有人）</FONT></TD>
<TD>识别名，公钥</TD></TR>
<TR>
<TD><FONT class=header2>签发者</FONT></TD>
<TD>识别名，签名</TD></TR>
<TR>
<TD><FONT class=header2>有效期</FONT></TD>
<TD>不早于，不晚于</TD></TR>
<TR>
<TD><FONT class=header2>管理信息</FONT></TD>
<TD>版本，序列号</TD></TR>
<TR>
<TD><FONT class=header2>扩展信息</FONT></TD>
<TD>基本限制, Netscape标记等</TD></TR></TBODY></TABLE>
<P>识别名DN是用来提供对某个特定背景下的身份，例如：某个人作为公司的一个雇员而拥有一个证书。识别名DN有X.509标准定义，包括它的字段，字段名和相应的缩写表示。（如表2所示） </P><FONT class=header2>表二：识别名(DN)信息</FONT><BR>
<TABLE style="BORDER-RIGHT: #aaa 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #aaa 1px solid; MARGIN-TOP: 0.5em; PADDING-LEFT: 2px; MARGIN-BOTTOM: 1px; PADDING-BOTTOM: 2px; BORDER-LEFT: #aaa 1px solid; PADDING-TOP: 2px; BORDER-BOTTOM: #aaa 1px solid; BORDER-COLLAPSE: collapse">
<TBODY>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>DN字段</FONT></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>缩写</FONT></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>说明</FONT></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>举例</FONT></TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Common Name<BR>通用名</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">CN</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">证书颁发对象名称</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">CN=Joe Average</TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Organization or Company<BR>组织或公司</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">O</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">颁发对象所属单位</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">O=Snake Oil, Ltd.</TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Organizational Unit<BR>部门</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">OU</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">所在单位部门</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">OU=Research Institute</TD></TR>
<TR>
<TD>City/Locality<BR>城市</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">L</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">所在城市</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">L=Snake City</TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">State/Province<BR>省份</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">ST</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">所在省份</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">ST=Desert</TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Country<BR>国家</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">C</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">国家代码，见<A href="http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html" target=_blank>ISO 3166-1 A2</A></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">C=XZ</TD></TR></TBODY></TABLE>
<P>证书颁发机构可以定义一个策略，指明哪些识别名字段名是可选的，哪些是必需的。很多证书还对某些字段的内容做出要求。例如，Netsacpe浏览器要求一个服务器证书的CN能够匹配通配符样式的域名，例如：*.snakeoil.com。</P>
<P>证书的二进制格式是使用了ASN.1（抽象语法标记）定义[X208] [ PKCS]。 这种表示法定义了如何指定编码规则的内容和如何将信息转换成二进制形式。证书的二进制编码使用了区分编码规则Distinguished Encoding Rules (DER)，它是基本编码规则Basic Encoding Rules (BER)的一个子集。对于那些不能采用二进制的信息传递，二进制形式可以转化为一个ASCII形式使用Base64编码[MIME]。当证书放置在Begin和End分割线中的时候，这种编码被称为增强型安全私人邮件格式(PEM -"Privacy Enhanced Mail") 编码的证书。</P><FONT class=header2>PEM编码证书的样例（snakioil.crt)</FONT><BR><PRE>Example of a PEM-encoded certificate (snakeoil.crt)
-----BEGIN CERTIFICATE-----
MIIC7jCCAlegAwIBAgIBATANBgkqhkiG9w0BAQQFADCBqTELMAkGA1UEBhMCWFkx
FTATBgNVBAgTDFNuYWtlIERlc2VydDETMBEGA1UEBxMKU25ha2UgVG93bjEXMBUG
A1UEChMOU25ha2UgT2lsLCBMdGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhv
cml0eTEVMBMGA1UEAxMMU25ha2UgT2lsIENBMR4wHAYJKoZIhvcNAQkBFg9jYUBz
bmFrZW9pbC5kb20wHhcNOTgxMDIxMDg1ODM2WhcNOTkxMDIxMDg1ODM2WjCBpzEL
MAkGA1UEBhMCWFkxFTATBgNVBAgTDFNuYWtlIERlc2VydDETMBEGA1UEBxMKU25h
a2UgVG93bjEXMBUGA1UEChMOU25ha2UgT2lsLCBMdGQxFzAVBgNVBAsTDldlYnNl
cnZlciBUZWFtMRkwFwYDVQQDExB3d3cuc25ha2VvaWwuZG9tMR8wHQYJKoZIhvcN
AQkBFhB3d3dAc25ha2VvaWwuZG9tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQDH9Ge/s2zcH+da+rPTx/DPRp3xGjHZ4GG6pCmvADIEtBtKBFAcZ64n+Dy7Np8b
vKR+yy5DGQiijsH1D/j8HlGE+q4TZ8OFk7BNBFazHxFbYI4OKMiCxdKzdif1yfaa
lWoANFlAzlSdbxeGVHoT0K+gT5w3UxwZKv2DLbCTzLZyPwIDAQABoyYwJDAPBgNV
HRMECDAGAQH/AgEAMBEGCWCGSAGG+EIBAQQEAwIAQDANBgkqhkiG9w0BAQQFAAOB
gQAZUIHAL4D09oE6Lv2k56Gp38OBDuILvwLg1v1KL8mQR+KFjghCrtpqaztZqcDt
2q2QoyulCgSzHbEGmi0EsdkPfg6mp0penssIFePYNI+/8u9HT4LuKMJX15hxBam7
dUHzICxBVC1lnHyYGjDuAMhe396lYAn8bCld1/L4NMGBCQ==
-----END CERTIFICATE-----</PRE><FONT class=header1>证书颁发机构CA </FONT>
<P>通过在批准证书之前核实证书请求中的信息，CA可以保证密钥对的私钥所有人的身份。举例，如果Alice请求一个个人证书，证书颁发机构必须首先核实ALICE在证书申请中所提交的个人信息和资料。</P><FONT class=header2>证书链</FONT> 
<P>CA机构有时也会为另外一家CA机构颁发证书。当检查证书的时候，ALICE可能需要检查每一级证书的父亲证书，一直找到一个她所能信任的证书为止。为了降低她在检查证书链中遇到一个“坏”证书的风险，ALICE可能会设定可信证书链的深度。</P><FONT class=header2>创建一个根CA </FONT>
<P>如前所述，每个证书需要发行者来声明证书拥有者身份的有效性，一直到最顶层CA。 这就产生了一个问题：谁来保证最顶层CA的权威性，而这个CA是没有发行者。在这个独特的情况下，证书采用一种“自签名”的方式，所以证书的发行者就是证书拥有者自己。浏览器会将一些知名的CA配置成可信，将他们的根证书安装到自己的受信根证书列表中，但如果要自己添加信任的自签名证书，就需要特别当心。</P>一些公司，例如GeoTrust 和 Verisign已经建立了他们自己的证书颁发机构。这些公司提供以下服务： <BR>
<UL>
<LI>验证证书请求 
<LI>处理证书申请 
<LI>发行和管理证书 </LI></UL>用户也可以创建自己的证书颁发机构。虽然在互联网上存在比较大的风险，但它在企业内网中是很有用的，可以轻松地验证个人和服务器的身份。 <BR><FONT class=header2>证书管理 </FONT>
<P>建立一个证书机构需要有坚实的行政，技术和管理框架。证书颁发机构不仅颁发证书，他们还要管理好证书，也就是说，他们确定证书在多久的时间内仍然有效，他们有一个列表，里面列举了过去颁发的，但已经不再有效的证书，并且不断更新这个列表（证书吊销清单，或CRL）。 </P>
<P>例如：ALICE曾经作为公司的雇员获得一个证书，但她现在已经离开公司了，她的证书就需要被吊销。由于证书只在审核完当事人身份后被签发，并且被传递给需要和当事人沟通的同事，从证书本身告诉去告知它已经被吊销了是不可能的。因此要检查一个证书是否有效，就必须联系CA机构获取证书吊销清单CRL，而这通常是无法自动完成的。</P>
<P>注意：<BR>如果你需要使用一个不是浏览器缺省信任的CA机构，就必须将这个CA的根证书装入浏览器的可信根证书列表，使浏览器可以识别这个CA颁发的服务器证书，但这样做是非常危险的，因为一旦加载了这个CA的根证书，浏览器将接受所有由这个根证书签发的服务器证书。 </P><FONT class=header>Secure Sockets Layer(SSL) 安全套接字层</FONT> 
<P>SSL是工作在面对连接网络层（如TCP层）和应用层（HTTP层）之间的协议层。SSL层协议通过为客户端和服务器提供双向认证，对隐私数据的加密，和用数字签名来保证数据完整性，从而提供了一个安全的通信通道。</P>
<P>本协议被设计为支持一系列制定的算法用于加密，数据摘要和签名。这允许对特定服务器的算法选择建立在法律、出口和其他问题的基础上，并且使协议能够利用新的算法。在客户机和服务器试图建立一个对话的时候，会协商算法。</P><FONT class=header2>表4：SSL协议的版本 </FONT><BR>
<TABLE style="BORDER-RIGHT: #aaa 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #aaa 1px solid; MARGIN-TOP: 0.5em; PADDING-LEFT: 2px; MARGIN-BOTTOM: 1px; PADDING-BOTTOM: 2px; BORDER-LEFT: #aaa 1px solid; PADDING-TOP: 2px; BORDER-BOTTOM: #aaa 1px solid; BORDER-COLLAPSE: collapse">
<TBODY>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>Version</FONT></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>Source</FONT></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>Description</FONT></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid"><FONT class=header2>Browser Support</FONT></TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">SSL v2.0</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Vendor Standard (from Netscape Corp.) [<A href="http://www.myssl.cn/guide/ssl_tls_introduction.asp#SSL2">SSL2</A>]</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">First SSL protocol for which implementations exist<BR></TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">- NS Navigator 1.x/2.x<BR>- MS IE 3.x<BR>- Lynx/2.8+OpenSSL</TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">SSL v3.0</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Expired Internet Draft (from Netscape Corp.) [<A href="http://www.myssl.cn/guide/ssl_tls_introduction.asp#SSL3">SSL3</A>]</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Revisions to prevent specific security attacks, add non-RSA ciphers and support for certificate chains</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">- NS Navigator 2.x/3.x/4.x<BR>- MS IE 3.x/4.x<BR>- Lynx/2.8+OpenSSL</TD></TR>
<TR>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">TLS v1.0</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Proposed Internet Standard (from IETF) [<A href="http://www.myssl.cn/guide/ssl_tls_introduction.asp#TLS1">TLS1</A>]</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">Revision of SSL 3.0 to update the MAC layer to HMAC, add block padding for block ciphers, message order standardization and more alert messages.</TD>
<TD style="BORDER-RIGHT: #aaa 1px solid; BORDER-TOP: #aaa 1px solid; BORDER-LEFT: #aaa 1px solid; BORDER-BOTTOM: #aaa 1px solid">- Lynx/2.8+OpenSSL</TD></TR></TBODY></TABLE>
<P>如表4所示，有多个SSL协议的版本，其中SSL3.0的一个优势就是它增加了对证书链加载的支持。这项功能使服务器可以将自己的服务器证书和发行者的证书一起传给浏览器。证书链的加载，使得客户机即使没有安装过服务器的中间证书，也可以来验证服务器证书的有效性，因为服务器的中间证书被放在证书链中一起发送给了客户机。SSL 3.0是安全传输层TLS协议的基础，这项协议正由IETF负责制订开发。 
<P><FONT class=header1>建立会话</FONT> 
<P>客户机和服务器同构一种“握手”次序来建立SSL会话，如图1.这个握手次序可能会有所不同，这取决于服务器是否配置成提供服务器证书，或者需要客户机提供客户证书。虽然在其他情况下存在因对密码管理要求不同而不同的“握手”步骤，详见各种SSL协议规范，但本文总结了一个基本的握手次序。</P><IMG src="http://www.myssl.cn/images/ssl_tls_1.gif" border=1> <BR><I>图1：基本握手次序</I><BR>
<P>注意：<BR>服务器为每个SSL会话分配一个唯一的会话标识符并缓存在服务器和客户端（直到会话标识符过期），使客户在下次连接的时候减少了握手的时间。</P>在握手序列中的被客户端和服务器使用的各项要素，如下列所示：<BR>
<OL>
<LI>协商数据传输中使用的加密套接字。 
<LI>在客户机和服务器中建立并共享一个会话密钥。 
<LI>可选的服务器端身份认证 
<LI>可选的客户端身份认证 </LI></OL>首先，加密套接字协商，允许客户端和服务器选择一个他们都是支持的加密套接字方式。SSL3.0协议定义了31种加密套接字方式，每一种安全套接字由下列部分组成：<BR>
<UL>
<LI>密钥交换方法 
<LI>数据加密传输 
<LI>创建消息认证码（MAC）的消息摘要 </LI></UL>这3个要素将在下面的几节中详细描述。<BR><FONT class=header2>密钥交换方法</FONT> 
<P>密钥交换方法定义在客户端和服务器之间共享双方都同意的，被用于应用数据传输的对称加密的密钥。SSL2.0协议只适用RSA密钥交换方式，而SSL3.0不仅支持RSA密钥交换（在使用证书的情况下），还支持Diffie-Hellman密钥交换（在没有使用证书或者没有客户端和服务器之间通信密钥之前的情况下。）</P>
<P>在决定密钥交换方式中的变量是选择是否需要数字签名和使用什么样的签名。使用私钥签名可以防止在交换共享密钥的时候，遭受中间人攻击。 </P><FONT class=header1>数据加密传输 </FONT><BR>
<P>SSL在加密会话中的消息时采用传统的对称加密方法，有9种加密方式可以选择，包括也可以选择不加密。</P>
<UL>
<LI>No encryption 
<LI>Stream Ciphers 
<UL>
<LI>RC4 with 40-bit keys 
<LI>RC4 with 128-bit keys </LI></UL>
<LI>CBC Block Ciphers 
<UL>
<LI>RC2 with 40 bit key 
<LI>DES with 40 bit key 
<LI>DES with 56 bit key 
<LI>Triple-DES with 168 bit key 
<LI>Idea (128 bit key) 
<LI>Fortezza (96 bit key) </LI></UL></LI></UL>
<P><FONT class=header2>“CBC”</FONT> 是Cipher Block Chaining的缩写，意思为密码分组链接，表示前一段加密后的密文被用当前段的加密中使用。</P>
<P><FONT class=header2>"DES" </FONT>是指Data Encryption Standard，有一系列不同的变量。包括DES40和3DES_EDE</P>
<P><FONT class=header2>"Idea"</FONT> 是目前最好的，也是加密强度最高的算法。</P>
<P><FONT class=header2>"RC2"</FONT> 是RSA DSI专用的算法。 </P><FONT class=header1>摘要函数</FONT><BR>
<P>对信息摘要函数的选择决定了如何从一个记录单元创建一个摘要。SSL支持以下模式：</P>
<UL>
<LI>无摘要 
<LI>128位哈希的MD5 
<LI>160位的安全哈希算法（SHA - 1） </LI></UL>
<P>消息摘要是用来创建一个消息认证码（MAC），MAC是与消息加密，来核实消息的完整性和保护消息不受回放式攻击。</P><FONT class=header1>握手次序协议 </FONT><BR>
<P>握手次序使用三个协议： 
<P>
<UL>
<LI>SSL Handshake Protocol. SSL握手协议执行客户端和服务器SSL会话的建立过程。 
<LI>SSL Change Cipher Spec Protocol .SSL更改密码协议负责协商会话用的密码套接字。 
<LI>SSL Alert Protocol.SSL告警协议负责在客户端和服务器间传递SSL错误信息。 </LI></UL>
<P>这些协议以及应用协议数据，都被SSL记录协议封装，如图2所示。封装好的数据被不检查数据的低一层的协议传递。下一层的协议对封装协议来说是未知的。</P><IMG src="http://www.myssl.cn/images/ssl_tls_2.gif" border=1> <BR><I>图2：SSL协议栈</I> <BR>
<P>SSL控制协议对记录协议的封装，使一个正在进行的会话在需要重新协商时，控制协议能够被安全地传输。如果没有前一个会话，则使用空的密码套接字，也就是说，在会话建立以前，不会使用密码也没有验证完整性的消息摘要。</P><FONT class=header1>数据传输 </FONT>
<P>SSL记录协议,如图3所示 , 用于在客户端和服务器之间传递SSL控制协议和应用层数据，必需将这些数据分割成较小的单元，或者将多个较高层协议数据合并为一个单元。它可能会在将这些数据传递到下一层可靠的传递协议前将这些数据压缩、加密和附加一个摘要签名。（注：目前主流的SSL都没有对压缩的支持）。</P><IMG src="http://www.myssl.cn/images/ssl_tls_3.gif" border=1> <BR><I>图3：SSL记录协议</I><BR>
<P><FONT class=header1>安全HTTP通信</FONT></P>
<P>SSL最常见的一项用途就是在浏览器和WEB服务器之间加密安全的WEB HTTP通信。使用加密的HTTP（称为HTTPS），即在SSL协议上使用HTTP协议，并没有排除HTTP协议，不过在URL地址中使用HTTPS来替换原来的HTTP，并使用另外一个服务器端口（HTTPS缺省使用443，HTTP使用80）。</P>]]></description>
</item><item>
<title><![CDATA[centos安装openvpn 2.1.1]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49482</link>
<author>hongrui</author>
<pubDate>2010-7-28 20:20:00</pubDate>
<description><![CDATA[<P>以前的版本 例如redhat 4.6 盘中自带openvpn 2.0.9.而5.x就没有openvpn的rpm包。<BR>不过自己做很简单，也可以直接从网上下载，也可以直接编译。<BR>openvpn 相关的rpm包有 lzo-1.08-5.el5.rf.i386.rpm lzo-devel-1.08-5.el5.rf.i386.rpm&nbsp; kcs11-helper-1.07-2.el5.1.i386.rpm&nbsp; pkcs11-helper-devel-1.07-2.el5.1.i386.rpm。<BR>也可以直接源码安装<BR>rpmbuild -tb pkcs11-helper-1.07.tar.bz2 <BR>安装<BR>rpm -ivh /usr/src/redhat/RPMS/i386/pkcs11-helper-1.07-2rh.i386.rpm /usr/src/redhat/RPMS/i386/pkcs11-helper-devel-1.07-2rh.i386.rpm</P>
<P>下载 openvpn-2.1.1.tar.gz<BR>rpmbuild -tb openvpn-2.1.1.tar.gz <BR>rpm -ivh&nbsp; /usr/src/redhat/RPMS/i386/openvpn-2.1.1-1.i386.rpm</P>]]></description>
</item><item>
<title><![CDATA[tomcat优化-安装apr(转载)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49382</link>
<author>hongrui</author>
<pubDate>2010-7-20 10:29:50</pubDate>
<description><![CDATA[<P>(1)安装apr，这是 Apache 为了提升 Tomcat 的性能搞的一套本地化 Socket, Thread, IO 组件也就是说它有高级 IO 功能, 操作系统级别的功能调用, 以及本地进程处理等等。</P>
<P>(2)安装Tomcat Native，这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作，以提升性能。</P>
<P>(3)安装tomcat为系统服务</P>
<P>(4)优化tomcat的jvm内存池</P>
<P>(5)修改tomcat的并发连接数</P>
<P><BR>一、安装apr</P>
<P>(1)安装apr</P>
<P># tar zxvf apr-1.4.2.tar.gz</P>
<P># cd apr-1.4.2</P>
<P># ./configure --prefix=/usr/local/www/apr</P>
<P># make</P>
<P># make install</P>
<P><BR>(2)安装apr-iconv</P>
<P># tar -zxvf apr-iconv-1.2.1.tar.gz</P>
<P># cd apr-iconv-1.2.1</P>
<P># ./configure --prefix=/usr/local/www/apr-iconv --with-apr=/usr/local/www/apr</P>
<P># make</P>
<P># make install</P>
<P><BR>(3)安装apr-util</P>
<P><BR># tar zxvf apr-util-1.3.9.tar.gz</P>
<P># cd apr-util-1.3.9</P>
<P># ./configure --prefix=/usr/local/www/apr-util --with-apr=/usr/local/www/apr --with-apr-iconv=/usr/local/www/apr-iconv/bin/apriconv</P>
<P># make</P>
<P># make install</P>
<P><BR>二、安装tomcat和tomcat-native</P>
<P><BR>(1)JDK安装</P>
<P># chmod a+x jdk-6u18-linux-i586-rpm.bin</P>
<P># ./jdk-6u7-linux-i586-rpm.bin</P>
<P># ln -s /usr/java/jdk1.6.0_18 /usr/local/java</P>
<P><BR>设置环境变量</P>
<P># vi /etc/profile</P>
<P>末尾增加如下内容</P>
<P>JAVA_HOME=/usr/local/java</P>
<P>CLASSPATH=/usr/local/java/lib/dt.jar:/usr/local/java/lib/tools.jar</P>
<P>PATH=/usr/local/java/bin:$PATH</P>
<P>export PATH JAVA_HOME CLASSPATH</P>
<P># source /etc/profile</P>
<P># java –version</P>
<P>查看java版本，如果是1.6的，就是说明安装成功了。</P>
<P><BR>(2)安装Tomcat</P>
<P># tar -zxvf apache-tomcat-6.0.26.tar.gz</P>
<P># mv apache-tomcat-6.0.26 /usr/local/www/tomcat</P>
<P># vi /usr/local/www/tomcat/bin/catalina.sh</P>
<P>加入一行：</P>
<P>JAVA_HOME=/usr/local/java</P>
<P># /usr/local/www/tomcat/bin/startup.sh</P>
<P><BR>(3)安装tomcat-native</P>
<P># cp tomcat-native-1.1.20-src.tar.gz /usr/local/www/tomcat/bin/</P>
<P># cd /usr/local/www/tomcat/bin&nbsp;&nbsp; </P>
<P># tar zxvf tomcat-native-1.1.20-src.tar.gz</P>
<P># cd tomcat-native-1.1.20-src/jni/native&nbsp;&nbsp; </P>
<P># ./configure --with-apr=/usr/local/www/apr --with-java-home=/usr/local/java</P>
<P># make</P>
<P># make install</P>
<P><BR>(4)设置 apr 的环境变量：</P>
<P># vi /etc/profile&nbsp;&nbsp; </P>
<P>后面添加以下内容&nbsp;&nbsp; </P>
<P>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib&nbsp;&nbsp; </P>
<P># source /etc/profile</P>
<P>启动 tomcat 后， 看日志：</P>
<P># more /usr/local/www/tomcat/logs/catalina.out</P>
<P>Dec 5, 2009 3:25:39 PM org.apache.catalina.core.AprLifecycleListener init</P>
<P>INFO: Loaded APR based Apache Tomcat Native library 1.1.20</P>]]></description>
</item><item>
<title><![CDATA[Detecting MAC Address using C application]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49332</link>
<author>hongrui</author>
<pubDate>2010-7-9 21:09:49</pubDate>
<description><![CDATA[<P>#include &lt;stdio.h&gt;<BR>#include &lt;fcntl.h&gt;<BR>#include &lt;stdlib.h&gt;<BR>#include &lt;string.h&gt;<BR>#include &lt;unistd.h&gt;</P>
<P>#ifdef Linux<BR>#include &lt;sys/ioctl.h&gt;<BR>#include &lt;sys/types.h&gt;<BR>#include &lt;sys/socket.h&gt;<BR>#include &lt;netinet/in.h&gt;<BR>#include &lt;linux/if.h&gt;<BR>#endif</P>
<P>#ifdef HPUX<BR>#include &lt;netio.h&gt;<BR>#endif</P>
<P>#ifdef AIX<BR>#include &lt;sys/ndd_var.h&gt;<BR>#include &lt;sys/kinfo.h&gt;<BR>#endif</P>
<P>long mac_addr_sys ( u_char *addr)<BR>{<BR>/* implementation for Linux */<BR>#ifdef Linux<BR>&nbsp;&nbsp;&nbsp; struct ifreq ifr;<BR>&nbsp;&nbsp;&nbsp; struct ifreq *IFR;<BR>&nbsp;&nbsp;&nbsp; struct ifconf ifc;<BR>&nbsp;&nbsp;&nbsp; char buf[1024];<BR>&nbsp;&nbsp;&nbsp; int s, i;<BR>&nbsp;&nbsp;&nbsp; int ok = 0;</P>
<P>&nbsp;&nbsp;&nbsp; s = socket(AF_INET, SOCK_DGRAM, 0);<BR>&nbsp;&nbsp;&nbsp; if (s==-1) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; ifc.ifc_len = sizeof(buf);<BR>&nbsp;&nbsp;&nbsp; ifc.ifc_buf = buf;<BR>&nbsp;&nbsp;&nbsp; ioctl(s, SIOCGIFCONF, &amp;ifc);</P>
<P>&nbsp;&nbsp;&nbsp; IFR = ifc.ifc_req;<BR>&nbsp;&nbsp;&nbsp; for (i = ifc.ifc_len / sizeof(struct ifreq); --i &gt;= 0; IFR++) {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(ifr.ifr_name, IFR-&gt;ifr_name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ioctl(s, SIOCGIFFLAGS, &amp;ifr) == 0) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (! (ifr.ifr_flags &amp; IFF_LOOPBACK)) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ioctl(s, SIOCGIFHWADDR, &amp;ifr) == 0) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ok = 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; close(s);<BR>&nbsp;&nbsp;&nbsp; if (ok) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bcopy( ifr.ifr_hwaddr.sa_data, addr, 6);<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; else {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; return 0;<BR>#endif</P>
<P>/* implementation for HP-UX */<BR>#ifdef HPUX</P>
<P>#define LAN_DEV0 "/dev/lan0"</P>
<P>&nbsp;&nbsp;&nbsp; intfd;<BR>&nbsp;&nbsp;&nbsp; struct fisiocnt_block;<BR>&nbsp;&nbsp;&nbsp; inti;<BR>&nbsp;&nbsp;&nbsp; charnet_buf[sizeof(LAN_DEV0)+1];<BR>&nbsp;&nbsp;&nbsp; char*p;</P>
<P>&nbsp;&nbsp;&nbsp; (void)sprintf(net_buf, "%s", LAN_DEV0);<BR>&nbsp;&nbsp;&nbsp; p = net_buf + strlen(net_buf) - 1;</P>
<P>&nbsp;&nbsp;&nbsp; /*<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Get 802.3 address from card by opening the driver and interrogating it.<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; 10; i++, (*p)++) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((fd = open (net_buf, O_RDONLY)) != -1) {<BR>iocnt_block.reqtype = LOCAL_ADDRESS;<BR>ioctl (fd, NETSTAT, &amp;iocnt_block);<BR>close (fd);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (iocnt_block.vtype == 6)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; if (fd == -1 || iocnt_block.vtype != 6) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>bcopy( &amp;iocnt_block.value.s[0], addr, 6);<BR>return 0;</P>
<P>#endif /* HPUX */</P>
<P>/* implementation for AIX */<BR>#ifdef AIX</P>
<P>&nbsp;&nbsp;&nbsp; int size;<BR>&nbsp;&nbsp;&nbsp; struct kinfo_ndd *nddp;</P>
<P>&nbsp;&nbsp;&nbsp; size = getkerninfo(KINFO_NDD, 0, 0, 0);<BR>&nbsp;&nbsp;&nbsp; if (size &lt;= 0) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; nddp = (struct kinfo_ndd *)malloc(size);</P>
<P>&nbsp;&nbsp;&nbsp; if (!nddp) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; if (getkerninfo(KINFO_NDD, nddp, &amp;size, 0) &lt; 0) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free(nddp);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; bcopy(nddp-&gt;ndd_addr, addr, 6);<BR>&nbsp;&nbsp;&nbsp; free(nddp);<BR>&nbsp;&nbsp;&nbsp; return 0;<BR>#endif</P>
<P>/* Not implemented platforms */<BR>return -1;<BR>}</P>
<P>/***********************************************************************/<BR>/*<BR>&nbsp;* Main (only for testing)<BR>&nbsp;*/<BR>#ifdef MAIN<BR>int main( int argc, char **argv)<BR>{<BR>&nbsp;&nbsp;&nbsp; long stat;<BR>&nbsp;&nbsp;&nbsp; int i;<BR>&nbsp;&nbsp;&nbsp; u_char addr[6];</P>
<P>&nbsp;&nbsp;&nbsp; stat = mac_addr_sys( addr);<BR>&nbsp;&nbsp;&nbsp; if (0 == stat) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf( "MAC address = ");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0; i&lt;6; ++i) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("%2.2x", addr[i]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf( "\n");<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; else {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf( stderr, "can't get MAC address\n");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit( 1);<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; return 0;<BR>}<BR>#endif</P>
<P>E.g you want to use on Linux, save it as file.c simply compile like this:<BR>&nbsp;&nbsp; gcc -O2 -DMAIN -DLinux file.c -o file</P>
<P>And run it<BR>./file<BR>MAC address = 0008c7e9e386</P>
<P>Compare with /sbin/ifconfig result:<BR>/sbin/ifconfig eth0</P>]]></description>
</item><item>
<title><![CDATA[linux 时区设置]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49326</link>
<author>hongrui</author>
<pubDate>2010-7-9 11:23:29</pubDate>
<description><![CDATA[
<P><A>　安装过程时没有选上海，即CST，Asia/Shanghai,而是按默认的，EDT时区．得改回CST<BR>vi /etc/sysconfig/clock<BR>ZONE="Asia/Shanghai"<BR>UTC=false<BR>ARC=false</A></P>
<P>更改/etc/timezone里面的内容为:Asia/Shanghai<BR>#mv /etc/localtime /etc/localtime-2009<BR># cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</P>
<P>再用命令date看一下，就是CST,</P>]]></description>
</item><item>
<title><![CDATA[架构师的能力和职责-《架构实战—软件架构设计的过程》读后感]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49222</link>
<author>hongrui</author>
<pubDate>2010-6-12 17:02:59</pubDate>
<description><![CDATA[<A><FONT size=4>　</FONT></A> 
<P><A><FONT size=4>　读这本书前，和几个阿里的架构师聊天，讨论架构师最基本的素质，总结出两点，1是技术知识广度，2是业务行业深度。<BR>自己细化后，和这本书的架构师的定义不谋而合。<BR>1 架构师是技术领导。<BR>架构师必须要有技术，而且还是领导。架构师要带领自己团队完成自己的任务，完全凭借自己的能力做事情，完全是匹夫之勇，根本不提倡。<BR>2 架构师理解软件流程<BR>架构师必须了解软件流程，否则无法驱动整个团队前进，如果一个架构师不熟悉开发流程，无法协调产品线相关人员进行高效工作，也无法指导团队成员完成自己的工作。所以来说架构师一般不是空降兵（除非是全新的部门），因为空降兵一般不会熟悉新公司的开发流程，即使是同一个行业的，各个公司的差别还是很大。所以说听说某某去某某公司做首席架构师或者首席科学家,一般是高风险的事情，即使他对这个行业很了解。<BR>3 架构师必须熟悉业务领域<BR>如果一个架构师不熟悉自己的行业，做的架构就是纸上谈兵，熟悉业务领域的架构师，才能很好的理解需求，做出合适的方案。互联网和网络安全是完全不同的两个方向，即使你熟悉里面的各种具体技术，但是以互联网的架构来做网络安全产品，肯定是100%的失败。<BR>我做PKI的时候，项目最初的使用.net，使用微软的crytoAPI，开发的很顺利。后来来了一位新的架构师，觉得.net不能跨平台，决定使用java，做出产品后，发现找不到arm cpu的jdk，使用平台有限。再次决定使用openssl做，最后这个项目以失败而告终。后来我想过arm cpu都是嵌入式设备用的，根本没有任何嵌入式设备提供CA服务。</FONT></A></P>
<P><FONT size=4>4 架构师必须要有广度的知识<BR>架构师考虑的问题必须全面，必须了解的要广，具体的细节可以不关注，因为细节变化很快。很多具体技术人员出身的架构师，只关注于具体的细节，某些方面做的很好，整体的性能很差。<BR>下面这个项目的成功可以理解为一个笑话。某公司的两个部门都做c程序的，A部门做的平台使用的x86和mips，B部门使用平台是x86和arm，后来A部门的一个模块要给B部门用，最后发现根本不能运行。最后A部门发现arm平台使用big endian模式，这样A部门的20多名员工，检查代码中所有非零整数，经过数个月苦战，才修改完毕。其实解决方法很简单，因B部门的代码也是首先在x86做的，做的时候他们考虑了cpu的endian模式。这并不能说B部门架构师很牛，从另一个方面说他的无知。因为板子有跳线，专门切换cpu的是big endian还是little endian，这样两个部门都可以不修改程序。<BR>5 架构师必须是写程序的高手<BR>架构师一般都是开发人员出身，一般都是团队的核心。优秀的架构师应该了解团队使用各种技术，有了这些知识，才能和开发人软进行有效沟通。<BR>有一个项目架构使用xml做配置，因为病毒库很庞大，最后导致xml 达30多兆，服务端的java程序使用dom 进行过滤的时候，30兆xml加载很慢，频繁出现out of memory。这个项目后来搁浅。根据以前的经验发现 msxml加载30多M的xml 不过几秒，而且msxml的xpath速度很快，后来专门为此写了JNI处理xml的。<BR>6架构师是优秀的沟通人员<BR>架构师一定要会忽悠，至少要扯淡。架构师不但要指导本部门员工的工作，也要协调其他部门的资源，还要向用户收集需求，制定规格说明书，重要的把用户的不合理要求砍掉，合理需求遵循自己的思路。</FONT></P>]]></description>
</item><item>
<title><![CDATA[java的DNS解析问题]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49191</link>
<author>hongrui</author>
<pubDate>2010-6-9 15:09:00</pubDate>
<description><![CDATA[<A>　java应用默认将解析到dns对应的IP缓存起来，默认值是-1，永久保存，除非重启java虚拟机。因为IP会被缓存，所以第一次解析后，再次解析时，就不会访问dns服务器了。<BR>java虚拟机的设计，可以设置缓存的时间。<BR>设置一分钟，参数 "-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60"<BR>resin配置文件，修改resin.conf中 &lt;server-default&gt;<BR>&lt;jvm-arg&gt;-Dnetworkaddress.cache.ttl = 60 &lt;/ jvm-arg&gt; <BR>&lt;jvm-arg&gt;-Dsun.net.inetaddr.ttl = 60 &lt;/ jvm-arg&gt;<BR>Tomcat catalina.bat加入<BR>JAVA_OPTS = "-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60"</A>]]></description>
</item><item>
<title><![CDATA[ConcurrentHashMap也会引起死锁]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=49070</link>
<author>hongrui</author>
<pubDate>2010-5-29 21:40:13</pubDate>
<description><![CDATA[ConcurrentHashMap一般情况下是线程安全的，但是也有引起死锁可能。<BR>在使用putAll时，频繁出现get数据时死锁。如果使用put或者putIfAbsent没有问题。<BR>怀疑putAll执行时会锁住整个map，然后迭代处理，这样处理的效率不是很高。<BR>看了看jdk6的实现，putAll已经是一个put的循环，不过这个putAll并不是atomic的。]]></description>
</item><item>
<title><![CDATA[为什么会出现Exception in thread "main" java.lang.NoClassDefFoundError的错误?]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=48887</link>
<author>hongrui</author>
<pubDate>2010-5-11 11:18:04</pubDate>
<description><![CDATA[<P><A>　写一下 怕自己以后忘记<BR>运行环境: redhat linux as4.6, j2sdk1.6.13<BR>SendMessage.java的内容如下:<BR>package test;</A></P>
<P>import org.smslib.SMSLibException;<BR>import org.smslib.Service;<BR>import org.smslib.OutboundMessage;<BR>import org.smslib.AGateway;<BR>import org.smslib.modem.SerialModemGateway;</P>
<P>import java.io.IOException;</P>
<P>/**<BR>&nbsp;* Created by IntelliJ IDEA.<BR>&nbsp;* User: asiainfo<BR>&nbsp;* Date: 2010-5-10<BR>&nbsp;* Time: 16:14:30<BR>&nbsp;* To change this template use File | Settings | File Templates.<BR>&nbsp;*/<BR>public class SendMessage {<BR>&nbsp;&nbsp;&nbsp; public void doIt(String phone, String content) throws IOException,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InterruptedException, SMSLibException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Service srv;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutboundMessage msg;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srv = new Service();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SerialModemGateway gateway = new SerialModemGateway("modem.ttyUSB0",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "/dev/ttyUSB0", 9600, "WAVECOM MODEM", "W810");//采用Sony Ericsson的W810c手机发送<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gateway.setProtocol(AGateway.Protocols.PDU);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gateway.setInbound(true);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gateway.setOutbound(true);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gateway.setSimPin("0000");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srv.addGateway(gateway);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srv.startService();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Mobile Device Information: ");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" Manufacturer : " + gateway.getManufacturer());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" Model : " + gateway.getModel());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" Serial No : " + gateway.getSerialNo());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" IMSI : " + gateway.getImsi());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" S/W Version : " + gateway.getSwVersion());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" Battery Level : " + gateway.getBatteryLevel() + "%");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" Signal Level : " + gateway.getSignalLevel() + "%");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; msg = new OutboundMessage(phone, content);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srv.sendMessage(msg);</P>
<P><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srv.stopService();<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public static void main(String args[]) throws IOException,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InterruptedException, SMSLibException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SendMessage app = new SendMessage();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; app.doIt("136******", "Hello 邢红瑞");</P>
<P><BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P><BR>运行: /usr/java/jre1.6.0_13/bin/java -Dsmslib.serial.polling -classpath&nbsp; log4j-1.2.15.jar:smslib-3.4.6.jar test.SendMessage<BR>出错: Exception in thread "main" java.lang.NoClassDefFoundDrror: SendMessage</P>
<P>后来终于找到原因: java加载了SendMessage.class以后，java就试图到CLASSPATH中找类SendMessage，CLASSPATH为：<BR>$CLASSPATH=/usr/java/jre1.6.0_13/lib:/usr/java/jre1.6.0_13/jre/lib<BR>java找不到SendMessage类的定义。windows包含了当前路径，但是linux和unix没有当前路径，必须手工添加<BR>/usr/java/jre1.6.0_13/bin/java -Dsmslib.serial.polling -classpath&nbsp; log4j-1.2.15.jar:smslib-3.4.6.jar:. test.SendMessage<BR>注意最后加了一个冒号和点，冒号是linux下文件分割符。</P>]]></description>
</item><item>
<title><![CDATA[OPENSSL和java的证书验证]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=48858</link>
<author>hongrui</author>
<pubDate>2010-5-7 16:43:02</pubDate>
<description><![CDATA[
<P><A>　以前经常做，OPENSSL打不开java的keystore，java无法读入p12证书，经常使用Bouncy Castle处理。<BR>现在发现jdk6是可以的<BR>openssl pkcs12 -export -in cert.pem -inkey key.pem &gt; linai.pfx</A></P>
<P>jdk6<BR>C:\jdk1.6.0_16\bin\keytool -importkeystore -srckeystore linai.pfx -destkeystore server.jks -srcstoretype pkcs12<BR>验证<BR>C:\jdk1.6.0_16\bin\keytool -list -v -keystore server.jks </P>
<P>其实java 可以查看ssl的输出信息</P>
<P>-Djavax.net.debug=ssl:record&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;enable per-record tracing</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handshake&nbsp;&nbsp;&nbsp; print each handshake message</P>
<P>-Djavax.net.debug=all&nbsp;&nbsp;&nbsp;&nbsp; all&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; turn on all debugging<BR>&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; ssl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; turn on ssl debugging</P>
<P>&nbsp;</P>
<P>网上的例子</P>
<P>import java.io.BufferedReader;<BR>import java.io.FileInputStream;<BR>import java.io.IOException;<BR>import java.io.InputStreamReader;<BR>import java.io.UnsupportedEncodingException;<BR>import java.security.KeyStore;<BR>import java.security.SecureRandom;</P>
<P>import javax.net.ssl.KeyManager;<BR>import javax.net.ssl.KeyManagerFactory;<BR>import javax.net.ssl.SSLContext;<BR>import javax.net.ssl.SSLServerSocket;<BR>import javax.net.ssl.SSLServerSocketFactory;<BR>import javax.net.ssl.SSLSocket;<BR>import javax.net.ssl.TrustManager;<BR>import javax.net.ssl.TrustManagerFactory;</P>
<P>public class SSLServer {<BR>&nbsp;&nbsp;&nbsp; private static final int port = 8266;<BR>&nbsp;&nbsp;&nbsp; private static final String keyStore = "server.ks";<BR>&nbsp;&nbsp;&nbsp; private static final String trustStore = "server.ks";<BR>&nbsp;&nbsp;&nbsp; private static final String keyStoreType = "jks";<BR>&nbsp;&nbsp;&nbsp; private static final String trustStoreType = "jks";<BR>&nbsp;&nbsp;&nbsp; private static final String keyStorePassword = "123456";<BR>&nbsp;&nbsp;&nbsp; private static final String trustStorePassword = "123456";<BR>&nbsp;&nbsp;&nbsp; private static final String secureRandomAlgorithm = "SHA1PRNG";<BR>&nbsp;&nbsp;&nbsp; private static final String protocol = "TLSv1";</P>
<P>&nbsp;&nbsp;&nbsp; private static KeyManager[] createKeyManagersAsArray() throws Exception {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeyStore ks = KeyStore.getInstance(keyStoreType);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ks.load(new FileInputStream(keyStore), keyStorePassword.toCharArray());</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeyManagerFactory tmf = KeyManagerFactory.getInstance(KeyManagerFactory<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getDefaultAlgorithm());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmf.init(ks, keyStorePassword.toCharArray());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return tmf.getKeyManagers();<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; private static TrustManager[] createTrustManagersAsArray() throws Exception {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeyStore ks = KeyStore.getInstance(trustStoreType);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ks.load(new FileInputStream(trustStore), trustStorePassword<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .toCharArray());</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TrustManagerFactory tmf = TrustManagerFactory<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getInstance(TrustManagerFactory.getDefaultAlgorithm());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmf.init(ks);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return tmf.getTrustManagers();<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; private static SSLServerSocket getServerSocket(int thePort) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLServerSocket socket = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLContext sslContext = SSLContext.getInstance(protocol);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sslContext.init(createKeyManagersAsArray(),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createTrustManagersAsArray(), SecureRandom<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getInstance(secureRandomAlgorithm));</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLServerSocketFactory factory = sslContext<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getServerSocketFactory();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; socket = (SSLServerSocket) factory.createServerSocket(thePort);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //socket.setNeedClientAuth(true);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (socket);<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public static void main(String args[]) throws IOException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLServerSocket server = getServerSocket(port);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("在" + port + "端口等待连接...");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (true) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final SSLSocket socket = (SSLSocket) server.accept();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Thread(new Runnable() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedReader in;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in = new BufferedReader(new InputStreamReader(socket<BR>&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; .getInputStream(), "gb2312"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String msg = in.readLine();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(msg);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; socket.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (UnsupportedEncodingException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }).start();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>以及SSLClient.java：<BR>import java.io.PrintWriter;<BR>import java.net.Socket;</P>
<P>import javax.net.ssl.SSLSocketFactory;</P>
<P>public class SSLClient {<BR>&nbsp;&nbsp;&nbsp; private static String addr = "192.168.80.86";</P>
<P>&nbsp;&nbsp;&nbsp; public static void main(String args[]) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setProperty("javax.net.ssl.keyStore", "client.ks");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setProperty("javax.net.ssl.keyStorePassword", "123456");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setProperty("javax.net.ssl.keyStoreType", "jks");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setProperty("javax.net.ssl.trustStore", "client.ks");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setProperty("javax.net.ssl.trustStorePassword", "123456");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.setProperty("javax.net.ssl.trustStoreType", "jks");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getDefault();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Socket socket = factory.createSocket(addr, 8266);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrintWriter out = new PrintWriter(socket.getOutputStream(), true);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.println("hello world!");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; socket.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>]]></description>
</item><item>
<title><![CDATA[如何得到jar里面指定包名下的类文件]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=48769</link>
<author>hongrui</author>
<pubDate>2010-4-23 18:16:48</pubDate>
<description><![CDATA[<P>一开始，认为URLClassLoader可以解决，后来一想不必麻烦，其实就是路径转换的问题。</P>
<P>package test;</P>
<P>/**<BR>&nbsp;* Created by IntelliJ IDEA.<BR>&nbsp;* User: asiainfo<BR>&nbsp;* Date: 2010-4-22<BR>&nbsp;* Time: 19:23:58<BR>&nbsp;* To change this template use File | Settings | File Templates.<BR>&nbsp;*/<BR>import java.util.jar.*;<BR>import java.util.*;<BR>import java.io.*;</P>
<P>public class PackageUtils {</P>
<P>&nbsp;private static boolean debug = true;</P>
<P>&nbsp;public static List getClasseNamesInPackage<BR>&nbsp;&nbsp;&nbsp;&nbsp; (String jarName, String packageName){<BR>&nbsp;&nbsp; ArrayList classes = new ArrayList ();</P>
<P>&nbsp;&nbsp; packageName = packageName.replaceAll("\\." , "/");<BR>&nbsp;&nbsp; if (debug) System.out.println<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ("Jar " + jarName + " looking for " + packageName);<BR>&nbsp;&nbsp; try{<BR>&nbsp;&nbsp;&nbsp;&nbsp; JarInputStream jarFile = new JarInputStream<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (new FileInputStream (jarName));<BR>&nbsp;&nbsp;&nbsp;&nbsp; JarEntry jarEntry;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; while(true) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jarEntry=jarFile.getNextJarEntry ();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(jarEntry == null){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((jarEntry.getName ().startsWith (packageName)) &amp;&amp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (jarEntry.getName ().endsWith (".class")) ) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (debug) System.out.println<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ("Found " + jarEntry.getName().replaceAll("/", "\\."));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classes.add (jarEntry.getName().replaceAll("/", "\\."));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp; catch( Exception e){<BR>&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace ();<BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp; return classes;<BR>}</P>
<P>/**<BR>*<BR>*/<BR>&nbsp; public static void main (String[] args){<BR>&nbsp;&nbsp; List list =&nbsp; PackageUtils.getClasseNamesInPackage<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ("D:\\SSL VPN Proj\\bat\\Server.Box.jar", "cn");<BR>&nbsp;&nbsp; System.out.println(list);<BR>&nbsp;&nbsp; <BR>&nbsp; }<BR>}<BR></P>]]></description>
</item><item>
<title><![CDATA[iptables nat的REDIRECT]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=48529</link>
<author>hongrui</author>
<pubDate>2010-3-29 17:30:59</pubDate>
<description><![CDATA[
<P>很久以前做网站的时候，OS多使用FreeBSD，当使用pf和squid作透明代理时，没有发现什么特殊之处。后来在了linux下面开发VPN的时候，服务器在接收连接时，不知道客户端发出连接的目的IP地址和端口。无论是TDI还是linux的IPTABLES，TDI暂且不说，linux的DNAT中的REDIRECT改变了目的IP地址和端口，否则就不算DNAT了。对于squid处理是一致的，看squid代码就知道原因。<BR>squid 2.6 的client_side.c<BR>#elif LINUX_NETFILTER<BR>static int<BR>clientNatLookup(ConnStateData * conn)<BR>{<BR>&nbsp;&nbsp;&nbsp; socklen_t sock_sz = sizeof(conn-&gt;me);<BR>&nbsp;&nbsp;&nbsp; struct in_addr orig_addr = conn-&gt;me.sin_addr;<BR>&nbsp;&nbsp;&nbsp; static time_t last_reported = 0;<BR>&nbsp;&nbsp;&nbsp; /* If the call fails the address structure will be unchanged */<BR>&nbsp;&nbsp;&nbsp; if (getsockopt(conn-&gt;fd, SOL_IP, SO_ORIGINAL_DST, &amp;conn-&gt;me, &amp;sock_sz) != 0) {<BR>&nbsp;if (squid_curtime - last_reported &gt; 60) {<BR>&nbsp;&nbsp;&nbsp;&nbsp; debug(50, 1) ("clientNatLookup: NF getsockopt(SO_ORIGINAL_DST) failed: %s\n", xstrerror());<BR>&nbsp;&nbsp;&nbsp;&nbsp; last_reported = squid_curtime;<BR>&nbsp;}<BR>&nbsp;return -1;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; debug(33, 5) ("clientNatLookup: addr = %s", inet_ntoa(conn-&gt;me.sin_addr));<BR>&nbsp;&nbsp;&nbsp; if (orig_addr.s_addr != conn-&gt;me.sin_addr.s_addr)<BR>&nbsp;return 0;<BR>&nbsp;&nbsp;&nbsp; else<BR>&nbsp;return -1;<BR>}<BR>#elif PF_TRANSPARENT<BR>static int<BR>clientNatLookup(ConnStateData * conn)<BR>{<BR>&nbsp;&nbsp;&nbsp; struct pfioc_natlook nl;<BR>&nbsp;&nbsp;&nbsp; static int pffd = -1;<BR>&nbsp;&nbsp;&nbsp; static time_t last_reported = 0;<BR>&nbsp;&nbsp;&nbsp; if (pffd &lt; 0) {<BR>&nbsp;pffd = open("/dev/pf", O_RDONLY);<BR>&nbsp;if (pffd &gt;= 0)<BR>&nbsp;&nbsp;&nbsp;&nbsp; commSetCloseOnExec(pffd);<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; if (pffd &lt; 0) {<BR>&nbsp;debug(50, 1) ("clientNatLookup: PF open failed: %s\n",<BR>&nbsp;&nbsp;&nbsp;&nbsp; xstrerror());<BR>&nbsp;return -1;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; memset(&amp;nl, 0, sizeof(struct pfioc_natlook));<BR>&nbsp;&nbsp;&nbsp; nl.saddr.v4.s_addr = conn-&gt;peer.sin_addr.s_addr;<BR>&nbsp;&nbsp;&nbsp; nl.sport = conn-&gt;peer.sin_port;<BR>&nbsp;&nbsp;&nbsp; nl.daddr.v4.s_addr = conn-&gt;me.sin_addr.s_addr;<BR>&nbsp;&nbsp;&nbsp; nl.dport = conn-&gt;me.sin_port;<BR>&nbsp;&nbsp;&nbsp; nl.af = AF_INET;<BR>&nbsp;&nbsp;&nbsp; nl.proto = IPPROTO_TCP;<BR>&nbsp;&nbsp;&nbsp; nl.direction = PF_OUT;<BR>&nbsp;&nbsp;&nbsp; if (ioctl(pffd, DIOCNATLOOK, &amp;nl)) {<BR>&nbsp;if (errno != ENOENT) {<BR>&nbsp;&nbsp;&nbsp;&nbsp; if (squid_curtime - last_reported &gt; 60) {<BR>&nbsp;&nbsp;debug(50, 1) ("clientNatLookup: PF lookup failed: ioctl(DIOCNATLOOK)\n");<BR>&nbsp;&nbsp;last_reported = squid_curtime;<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; close(pffd);<BR>&nbsp;&nbsp;&nbsp;&nbsp; pffd = -1;<BR>&nbsp;}<BR>&nbsp;return -1;<BR>&nbsp;&nbsp;&nbsp; } else {<BR>&nbsp;int natted = conn-&gt;me.sin_addr.s_addr != nl.rdaddr.v4.s_addr;<BR>&nbsp;conn-&gt;me.sin_port = nl.rdport;<BR>&nbsp;conn-&gt;me.sin_addr = nl.rdaddr.v4;<BR>&nbsp;if (natted)<BR>&nbsp;&nbsp;&nbsp;&nbsp; return 0;<BR>&nbsp;else<BR>&nbsp;&nbsp;&nbsp;&nbsp; return -1;<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR>BSD和linux 处理是不一致的。<BR>找到一段代码<BR>#include &lt;stdio.h&gt;<BR>#include &lt;string.h&gt;<BR>#include &lt;stdlib.h&gt;</P>
<P>#include &lt;unistd.h&gt;<BR>#include &lt;sys/types.h&gt;<BR>#include &lt;sys/socket.h&gt;<BR>#include &lt;sys/ioctl.h&gt;<BR>#include &lt;netinet/in.h&gt;<BR>#include &lt;arpa/inet.h&gt;<BR>#include &lt;netdb.h&gt;<BR>#include &lt;errno.h&gt;<BR>#include &lt;dlfcn.h&gt;<BR>#include &lt;linux/netfilter_ipv4.h&gt;</P>
<P>#define SD_BOTH 2<BR>#define SOCKET int<BR>#define INVALID_SOCKET (SOCKET)(~0)<BR>#define SOCKET_ERROR (-1)</P>
<P>int main(void)<BR>{<BR>SOCKET listen_sock, new_sock;<BR>struct sockaddr_in client;<BR>struct sockaddr_in me;<BR>struct sockaddr_in peer;</P>
<P>unsigned long sockmode = 0;<BR>socklen_t SLen = sizeof(client);</P>
<P>if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0))== <BR>INVALID_SOCKET) {<BR>exit(1);<BR>}</P>
<P>/* Local address and port */<BR>me.sin_family = AF_INET;<BR>me.sin_port = htons(4321);<BR>inet_aton("127.0.0.1", &amp;me.sin_addr);</P>
<P>if (ioctl(listen_sock, FIONBIO, &amp;sockmode) == SOCKET_ERROR) {<BR>close(listen_sock);<BR>exit(1);<BR>}</P>
<P>if (bind(listen_sock, (struct sockaddr *)&amp;me, sizeof(me)) == <BR>SOCKET_ERROR) {<BR>close(listen_sock);<BR>exit(1);<BR>}</P>
<P>if (listen(listen_sock, SOMAXCONN) == SOCKET_ERROR) {<BR>shutdown(listen_sock, SD_BOTH);<BR>close(listen_sock);<BR>exit(1);<BR>}</P>
<P>while ((new_sock = accept(listen_sock, (struct sockaddr *)&amp;client, <BR>&amp;SLen))<BR>!= INVALID_SOCKET)<BR>{<BR>SLen = sizeof(peer);<BR>memset(&amp;peer, 0, SLen);<BR>getsockopt(new_sock, SOL_IP, SO_ORIGINAL_DST, &amp;peer, &amp;SLen);<BR>printf( "Client: %s:%hu\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));</P>
<P>if ( shutdown(new_sock, SD_BOTH) == SOCKET_ERROR ||<BR>close(new_sock) == SOCKET_ERROR )<BR>{<BR>shutdown(listen_sock, SD_BOTH);<BR>close(listen_sock);<BR>exit(1);<BR>}<BR>}<BR>if(new_sock == INVALID_SOCKET) {<BR>shutdown(listen_sock, SD_BOTH);<BR>close(listen_sock);<BR>exit(1);<BR>}</P>
<P>if (shutdown(listen_sock, SD_BOTH) == SOCKET_ERROR ||<BR>close(listen_sock) == SOCKET_ERROR)<BR>{<BR>exit(1);<BR>}</P>
<P>exit(0);<BR>}<BR>linux中输入 <BR>iptables -t nat -I OUTPUT -p tcp&nbsp; -j REDIRECT --to 4321<BR>iptables -t nat -I PREROUTING -p tcp -i eth0 --dport pop3 -j REDIRECT --to 4321<BR>然后输入 telnet 后面是随意的ip地址就行。<BR>java中的得不到socket的真实fd，感觉很诡异。</P>]]></description>
</item><item>
<title><![CDATA[sun的javac的一个bug]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=48439</link>
<author>hongrui</author>
<pubDate>2010-3-17 17:45:05</pubDate>
<description><![CDATA[
<P><A>　最近使用sun的javac编译xnio，发现<BR>public interface TcpChannel extends ConnectedStreamChannel&lt;InetSocketAddress&gt; {</A></P>
<P>&nbsp;&nbsp;&nbsp; /** <A href="mailto:%7B@inheritDoc">{@inheritDoc</A>} */<BR>&nbsp;&nbsp;&nbsp; ChannelListener.Setter&lt;? extends TcpChannel&gt; getReadSetter();</P>
<P>&nbsp;&nbsp;&nbsp; /** <A href="mailto:%7B@inheritDoc">{@inheritDoc</A>} */<BR>&nbsp;&nbsp;&nbsp; ChannelListener.Setter&lt;? extends TcpChannel&gt; getWriteSetter();</P>
<P>&nbsp;&nbsp;&nbsp; /** <A href="mailto:%7B@inheritDoc">{@inheritDoc</A>} */<BR>&nbsp;&nbsp;&nbsp; ChannelListener.Setter&lt;? extends TcpChannel&gt; getCloseSetter();<BR>}<BR>public interface ConnectedStreamChannel&lt;A&gt; extends StreamChannel, ConnectedChannel&lt;A&gt; {</P>
<P>&nbsp;&nbsp;&nbsp; /** <A href="mailto:%7B@inheritDoc">{@inheritDoc</A>} */<BR>&nbsp;&nbsp;&nbsp; ChannelListener.Setter&lt;? extends ConnectedStreamChannel&lt;A&gt;&gt; getReadSetter();</P>
<P>&nbsp;&nbsp;&nbsp; /** <A href="mailto:%7B@inheritDoc">{@inheritDoc</A>} */<BR>&nbsp;&nbsp;&nbsp; ChannelListener.Setter&lt;? extends ConnectedStreamChannel&lt;A&gt;&gt; getWriteSetter();</P>
<P>&nbsp;&nbsp;&nbsp; /** <A href="mailto:%7B@inheritDoc">{@inheritDoc</A>} */<BR>&nbsp;&nbsp;&nbsp; ChannelListener.Setter&lt;? extends ConnectedStreamChannel&lt;A&gt;&gt; getCloseSetter();<BR>}<BR>出现不兼容，两者都有都定了getCloseSetter。<BR>看了看java的代码，没有任何错误，想到xnio也是jboss的旗下的重要项目，不会出如此弱智的问题。<BR>经过12月1日老兄的提示后，认为是javac的问题，使用oracle jrockit编译运行通过,估计ECJ (Eclipse Compiler for Java)也没有问题，安装了 JRE，也可以在 eclipse 中进行编译。<BR>经过龙兄的指点，认为特别是有的包是在1.5或者在1.4下面编译过来的混在一起，容易有问题，除非你全部代码都是自己写，而且保证编译的包都是在1.6之上。<BR>sun的bug <A href="http://bugs.sun.com/view_bug.do?bug_id=6294779">http://bugs.sun.com/view_bug.do?bug_id=6294779</A><BR>05年到10年 一直有这个bug。</P>]]></description>
</item><item>
<title><![CDATA[什么叫“假学习”(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=48411</link>
<author>hongrui</author>
<pubDate>2010-3-15 12:24:27</pubDate>
<description><![CDATA[
<DIV>
<DIV>一、QQ群<BR>一天上班开始看QQ群，聊到下班。里面争论（不会的东西，你也不会争论）的火热。美其名曰在学习，实际上你永远学不到新的东西。</DIV></DIV>
<DIV>&nbsp;</DIV>
<DIV>二、看书<BR>只看自己能看懂的书。</DIV>
<DIV>&nbsp;</DIV>
<DIV>三、听课<BR>听课，记笔记。<SPAN style="COLOR: rgb(255,0,0)">真正的课程是要用来发现疑问，表达疑问，表达理解的</SPAN>，而不是只出耳朵听和记录教学内容的。 别人讲的内容是经验的精华，但是别人无法代替你大脑的运转过程，无法代替你大脑逻辑的形成的过程。</DIV>
<DIV>&nbsp;</DIV>
<DIV>四、实验<BR>单纯实验，和打字是没什么区别的，操作手册可以告诉我们结果和机理，敲1遍只是练习了命令输入，只有第2遍，才会有一些思考。</DIV>
<DIV>&nbsp;</DIV>
<DIV>五、看贴<BR>每个帖子可能都是经过很多时间研究的心得，写得再好，只看的话，也还不是自己写的。看贴不回帖，只懂顶，都是假学习。</DIV>
<DIV>&nbsp;</DIV>
<DIV>六、攻击<BR>乱喷人...<BR>先问你一个问题，你懂什么，“什么都不懂”，好，你懂不懂IP地址怎么写吗？OK，写出来，请问“为什么要用IP地址?”。连自己懂什么都不知道，知道哪些是真正要懂的。攻击不到本质，说明你在假学习。</DIV>
<DIV>&nbsp;</DIV>
<DIV>七、思考<BR>瞎YY...<BR>记住一堆概念是没有用的，你必须把数字的信息转换成抽象的信息存储在大脑里，并且逻辑和系统同步，不断训练思考才能做到。</DIV>
<DIV>&nbsp;</DIV>
<DIV>八、忘却<BR>有用的全忘了...<BR>专家的<SPAN style="COLOR: rgb(255,0,0)">大脑里只保存思路和方法，而不是细节，可以迅速解决任何问题。<BR></SPAN>真正的忘却不是因为记忆的衰退，而是放下来，<SPAN style="COLOR: rgb(255,0,0)">问题本身毫无意义</SPAN>。</DIV>
<DIV>&nbsp;</DIV>
<DIV>九、表达<BR>表达不出来...<BR><SPAN style="COLOR: rgb(255,0,0)">真正的学会，在于能够讲出来，使一个初学者也能够听得明白，才能算是学会了，不会表达，永远学不会。懂了，却举不出例子来，怎么能够叫做懂了呢？</SPAN></DIV>]]></description>
</item><item>
<title><![CDATA[递归删除svn目录]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=48277</link>
<author>hongrui</author>
<pubDate>2010-2-25 12:00:51</pubDate>
<description><![CDATA[<P>参考<A href="http://perezj.blogspot.com/2008/10/delete-svn-folders-files-recursive.html">http://perezj.blogspot.com/2008/10/delete-svn-folders-files-recursive.html</A></P>
<P>在checked out创建一个a.bat</P>
<P>写入 FOR /F "tokens=*" %%G IN ('DIR /B /AD /S *.svn*') DO RMDIR /S /Q "%%G"</P>
<P>打开command prompt，执行a.bat</P>]]></description>
</item>
</channel>
</rss>