﻿<?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-Tinysun-随笔分类-其他</title><link>http://www.blogjava.net/tinysun/category/38052.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 07 Aug 2010 06:17:29 GMT</lastBuildDate><pubDate>Sat, 07 Aug 2010 06:17:29 GMT</pubDate><ttl>60</ttl><item><title>用 Hadoop 进行分布式并行编程 转</title><link>http://www.blogjava.net/tinysun/archive/2010/08/06/328098.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 06 Aug 2010 01:42:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/08/06/328098.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/328098.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/08/06/328098.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/328098.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/328098.html</trackback:ping><description><![CDATA[Hadoop 是一个实现了 MapReduce 计算模型的开源分布式并行编程框架，借助于 Hadoop,
程序员可以轻松地编写分布式并行程序，将其运行于计算机集群上，完成海量数据的计算。本文将介绍 MapReduce
计算模型，分布式并行计算等基本概念，以及 Hadoop 的安装部署和基本运行方法。
<br />
Hadoop 简介
<br />
<br />
Hadoop
是一个开源的可运行于大规模集群上的分布式并行编程框架，由于分布式存储对于分布式编程来说是必不可少的，这个框架中还包含了一个分布式文件系统
HDFS( Hadoop Distributed File System )。也许到目前为止，Hadoop
还不是那么广为人知，其最新的版本号也仅仅是 0.16，距离 1.0 似乎都还有很长的一段距离，但提及 Hadoop 一脉相承的另外两个开源项目
Nutch 和 Lucene ( 三者的创始人都是 Doug Cutting ),那绝对是大名鼎鼎。Lucene 是一个用 Java
开发的开源高性能全文检索工具包，它不是一个完整的应用程序，而是一套简单易用的 API 。在全世界范围内，已有无数的软件系统，Web 网站基于
Lucene 实现了全文检索功能，后来 Doug Cutting 又开创了第一个开源的 Web 搜索引擎(<a href="http://www.nutch.org/" target="_blank">http://www.nutch.org</a>)
Nutch, 它在 Lucene 的基础上增加了网络爬虫和一些和 Web 相关的功能，一些解析各类文档格式的插件等，此外，Nutch
中还包含了一个分布式文件系统用于存储数据。从 Nutch 0.8.0 版本之后，Doug Cutting 把 Nutch
中的分布式文件系统以及实现 MapReduce 算法的代码独立出来形成了一个新的开源项 Hadoop。Nutch 也演化为基于 Lucene
全文检索以及 Hadoop 分布式计算平台的一个开源搜索引擎。
<br />
<br />
基于
Hadoop,你可以轻松地编写可处理海量数据的分布式并行程序，并将其运行于由成百上千个结点组成的大规模计算机集群上。从目前的情况来
看，Hadoop 注定会有一个辉煌的未来："云计算"是目前灸手可热的技术名词，全球各大 IT 公司都在投资和推广这种新一代的计算模式，而
Hadoop 又被其中几家主要的公司用作其"云计算"环境中的重要基础软件，如:雅虎正在借助 Hadoop 开源平台的力量对抗 Google,
除了资助 Hadoop 开发团队外，还在开发基于 Hadoop 的开源项目 Pig, 这是一个专注于海量数据集分析的分布式计算程序。Amazon
公司基于 Hadoop 推出了 Amazon S3 ( Amazon Simple Storage Service
)，提供可靠，快速，可扩展的网络存储服务，以及一个商用的云计算平台 Amazon EC2 ( Amazon Elastic Compute
Cloud )。在 IBM 公司的云计算项目--"蓝云计划"中，Hadoop 也是其中重要的基础软件。Google
正在跟IBM合作，共同推广基于 Hadoop 的云计算。
<br />
<br />
<br />
迎接编程方式的变革
<br />
<br />
在摩尔定律的作用下，以前程序员根本不用考虑计算机的性能会跟不上软件的发展，因为约每隔 18 个月，CPU
的主频就会增加一倍，性能也将提升一倍，软件根本不用做任何改变，就可以享受免费的性能提升。然而，由于晶体管电路已经逐渐接近其物理上的性能极限，摩尔
定律在 2005 年左右开始失效了，人类再也不能期待单个 CPU 的速度每隔 18 个月就翻一倍，为我们提供越来越快的计算性能。Intel,
AMD, IBM 等芯片厂商开始从多核这个角度来挖掘 CPU
的性能潜力，多核时代以及互联网时代的到来，将使软件编程方式发生重大变革，基于多核的多线程并发编程以及基于大规模计算机集群的分布式并行编程是将来软
件性能提升的主要途径。
<br />
<br />
许多人认为这种编程方式的重大变化将带来一次软件的并发危机，因为我们传统的软件方式基本上是单指令单数据流的顺序执行，这种顺序执行十分符合人
类的思考习惯，却与并发并行编程格格不入。基于集群的分布式并行编程能够让软件与数据同时运行在连成一个网络的许多台计算机上,这里的每一台计算机均可以
是一台普通的 PC 机。这样的分布式并行环境的最大优点是可以很容易的通过增加计算机来扩充新的计算结点，并由此获得不可思议的海量计算能力,
同时又具有相当强的容错能力，一批计算结点失效也不会影响计算的正常进行以及结果的正确性。Google 就是这么做的，他们使用了叫做
MapReduce 的并行编程模型进行分布式并行编程，运行在叫做 GFS ( Google File System
)的分布式文件系统上，为全球亿万用户提供搜索服务。
<br />
<br />
Hadoop 实现了 Google 的 MapReduce 编程模型，提供了简单易用的编程接口，也提供了它自己的分布式文件系统
HDFS,与 Google 不同的是，Hadoop
是开源的，任何人都可以使用这个框架来进行并行编程。如果说分布式并行编程的难度足以让普通程序员望而生畏的话，开源的 Hadoop
的出现极大的降低了它的门槛，读完本文，你会发现基于 Hadoop
编程非常简单，无须任何并行开发经验，你也可以轻松的开发出分布式的并行程序，并让其令人难以置信地同时运行在数百台机器上，然后在短时间内完成海量数据
的计算。你可能会觉得你不可能会拥有数百台机器来运行你的并行程序，而事实上，随着"云计算"的普及，任何人都可以轻松获得这样的海量计算能力。例如现在
Amazon 公司的云计算平台 Amazon EC2
已经提供了这种按需计算的租用服务，有兴趣的读者可以去了解一下，这篇系列文章的第三部分将有所介绍。
<br />
<br />
掌握一点分布式并行编程的知识对将来的程序员是必不可少的，Hadoop 是如此的简便好用，何不尝试一下呢？也许你已经急不可耐的想试一下基于
Hadoop 的编程是怎么回事了，但毕竟这种编程模型与传统的顺序程序大不相同，掌握一点基础知识才能更好地理解基于 Hadoop
的分布式并行程序是如何编写和运行的。因此本文会先介绍一下 MapReduce 的计算模型，Hadoop 中的分布式文件系统 HDFS,
Hadoop 是如何实现并行计算的，然后才介绍如何安装和部署 Hadoop 框架，以及如何运行 Hadoop 程序。
<br />
<br />
MapReduce 计算模型
<br />
<br />
MapReduce 是 Google 公司的核心计算模型，它将复杂的运行于大规模集群上的并行计算过程高度的抽象到了两个函数，Map 和
Reduce, 这是一个令人惊讶的简单却又威力巨大的模型。适合用 MapReduce 来处理的数据集(或任务)有一个基本要求:
待处理的数据集可以分解成许多小的数据集，而且每一个小数据集都可以完全并行地进行处理。
<br />
<br />
<br />
图 1. MapReduce 计算流程
<br />
<img src="http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop1/figure1.jpg"  alt="" />
<br />
图一说明了用 MapReduce 来处理大数据集的过程, 这个 MapReduce
的计算过程简而言之，就是将大数据集分解为成百上千的小数据集，每个(或若干个)数据集分别由集群中的一个结点(一般就是一台普通的计算机)进行处理并生
成中间结果，然后这些中间结果又由大量的结点进行合并, 形成最终结果。
<br />
<br />
计算模型的核心是 Map 和 Reduce 两个函数，这两个函数由用户负责实现，功能是按一定的映射规则将输入的 &lt;key, value&gt; 对转换成另一个或一批 &lt;key, value&gt; 对输出。
<br />
<br />
<br />
表一 Map 和 Reduce 函数
<br />
函数 输入 输出 说明
<br />
Map &lt;k1, v1&gt; List(&lt;k2,v2&gt;) 1. 将小数据集进一步解析成一批 &lt;key,value&gt; 对，输入 Map 函数中进行处理。
<br />
2. 每一个输入的 &lt;k1,v1&gt; 会输出一批 &lt;k2,v2&gt;。 &lt;k2,v2&gt; 是计算的中间结果。&nbsp;
<br />
Reduce &lt;k2,List(v2)&gt; &lt;k3,v3&gt; 输入的中间结果 &lt;k2,List(v2)&gt; 中的 List(v2) 表示是一批属于同一个 k2 的 value
<br />
<br />
以一个计算文本文件中每个单词出现的次数的程序为例，&lt;k1,v1&gt; 可以是 &lt;行在文件中的偏移位置,
文件中的一行&gt;，经 Map 函数映射之后，形成一批中间结果 &lt;单词，出现次数&gt;, 而 Reduce
函数则可以对中间结果进行处理，将相同单词的出现次数进行累加，得到每个单词的总的出现次数。
<br />
<br />
基于 MapReduce 计算模型编写分布式并行程序非常简单，程序员的主要编码工作就是实现 Map 和 Reduce
函数，其它的并行编程中的种种复杂问题，如分布式存储，工作调度，负载平衡，容错处理，网络通信等，均由 MapReduce 框架(比如 Hadoop
)负责处理，程序员完全不用操心。
<br />
<br />
四 集群上的并行计算
<br />
<br />
MapReduce 计算模型非常适合在大量计算机组成的大规模集群上并行运行。图一中的每一个 Map 任务和每一个 Reduce 任务均可以同时运行于一个单独的计算结点上，可想而知其运算效率是很高的，那么这样的并行计算是如何做到的呢？
<br />
<br />
数据分布存储
<br />
<br />
Hadoop 中的分布式文件系统 HDFS 由一个管理结点 ( NameNode )和N个数据结点 ( DataNode
)组成，每个结点均是一台普通的计算机。在使用上同我们熟悉的单机上的文件系统非常类似，一样可以建目录，创建，复制，删除文件，查看文件内容等。但其底
层实现上是把文件切割成 Block，然后这些 Block 分散地存储于不同的 DataNode 上，每个 Block 还可以复制数份存储于不同的
DataNode 上，达到容错容灾之目的。NameNode 则是整个 HDFS
的核心，它通过维护一些数据结构，记录了每一个文件被切割成了多少个 Block，这些 Block 可以从哪些 DataNode 中获得，各个
DataNode 的状态等重要信息。如果你想了解更多的关于 HDFS 的信息，可进一步阅读参考资料： [url]The Hadoop
Distributed File System:Architecture and Design [/url]
<br />
分布式并行计算
<br />
<br />
Hadoop 中有一个作为主控的 JobTracker，用于调度和管理其它的 TaskTracker, JobTracker
可以运行于集群中任一台计算机上。TaskTracker 负责执行任务，必须运行于 DataNode 上，即 DataNode
既是数据存储结点，也是计算结点。 JobTracker 将 Map 任务和 Reduce 任务分发给空闲的 TaskTracker,
让这些任务并行运行，并负责监控任务的运行情况。如果某一个 TaskTracker 出故障了，JobTracker
会将其负责的任务转交给另一个空闲的 TaskTracker 重新运行。
<br />
<br />
本地计算
<br />
<br />
数据存储在哪一台计算机上，就由这台计算机进行这部分数据的计算，这样可以减少数据在网络上的传输，降低对网络带宽的需求。在 Hadoop
这样的基于集群的分布式并行系统中，计算结点可以很方便地扩充，而因它所能够提供的计算能力近乎是无限的，但是由是数据需要在不同的计算机之间流动，故网
络带宽变成了瓶颈，是非常宝贵的，&#8220;本地计算&#8221;是最有效的一种节约网络带宽的手段，业界把这形容为&#8220;移动计算比移动数据更经济&#8221;。
<br />
<br />
图 2. 分布存储与并行计算
<br />
<img src="http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop1/figure2.jpg"  alt="" />
<br />
<br />
任务粒度
<br />
<br />
把原始大数据集切割成小数据集时，通常让小数据集小于或等于 HDFS 中一个 Block 的大小(缺省是
64M)，这样能够保证一个小数据集位于一台计算机上，便于本地计算。有 M 个小数据集待处理，就启动 M 个 Map 任务，注意这 M 个 Map
任务分布于 N 台计算机上并行运行，Reduce 任务的数量 R 则可由用户指定。
<br />
<br />
Partition
<br />
<br />
把 Map 任务输出的中间结果按 key 的范围划分成 R 份( R 是预先定义的 Reduce 任务的个数)，划分时通常使用 hash
函数如: hash(key) mod R，这样可以保证某一段范围内的 key，一定是由一个 Reduce 任务来处理，可以简化 Reduce
的过程。
<br />
<br />
Combine
<br />
<br />
在 partition 之前，还可以对中间结果先做 combine，即将中间结果中有相同 key的 &lt;key, value&gt;
对合并成一对。combine 的过程与 Reduce 的过程类似，很多情况下就可以直接使用 Reduce 函数，但 combine 是作为
Map 任务的一部分，在执行完 Map 函数后紧接着执行的。Combine 能够减少中间结果中 &lt;key, value&gt;
对的数目，从而减少网络流量。
<br />
<br />
Reduce 任务从 Map 任务结点取中间结果
<br />
<br />
Map 任务的中间结果在做完 Combine 和 Partition 之后，以文件形式存于本地磁盘。中间结果文件的位置会通知主控
JobTracker, JobTracker 再通知 Reduce 任务到哪一个 DataNode 上去取中间结果。注意所有的 Map
任务产生中间结果均按其 Key 用同一个 Hash 函数划分成了 R 份，R 个 Reduce 任务各自负责一段 Key 区间。每个
Reduce 需要向许多个 Map 任务结点取得落在其负责的 Key 区间内的中间结果，然后执行 Reduce 函数，形成一个最终的结果文件。
<br />
<br />
任务管道
<br />
<br />
有 R 个 Reduce 任务，就会有 R 个最终结果，很多情况下这 R 个最终结果并不需要合并成一个最终结果。因为这 R 个最终结果又可以做为另一个计算任务的输入，开始另一个并行计算任务。
<br />
<br />
五 Hadoop 初体验
<br />
<br />
Hadoop 支持 Linux 及 Windows 操作系统, 但其官方网站声明 Hadoop 的分布式操作在 Windows
上未做严格测试，建议只把 Windows 作为 Hadoop 的开发平台。在 Windows 环境上的安装步骤如下( Linux
平台类似，且更简单一些):
<br />
<br />
(1)在 Windows 下，需要先安装 Cgywin, 安装 Cgywin 时注意一定要选择安装 openssh (在 Net
category )。安装完成之后，把 Cgywin 的安装目录如 c:\cygwin\bin 加到系统环境变量 PATH 中，这是因为运行
Hadoop 要执行一些 linux 环境下的脚本和命令。
<br />
<br />
(2)安装 Java 1.5.x，并将 JAVA_HOME 环境变量设置为 Java 的安装根目录如 C:\Program Files\Java\jdk1.5.0_01。
<br />
<br />
(3)到 Hadoop 官方网站[url] http://hadoop.apache.org[/url]下载Hadoop Core, 最新的稳定版本是 0.16.0. 将下载后的安装包解压到一个目录，本文假定解压到 c:\hadoop-0.16.0。
<br />
<br />
4)修改 conf/hadoop-env.sh 文件，在其中设置 JAVA_HOME 环境变量： export
JAVA_HOME="C:\Program Files\Java\jdk1.5.0_01&#8221; (因为路径中 Program Files
中间有空格，一定要用双引号将路径引起来)
<br />
<br />
至此，一切就绪，可以运行 Hadoop 了。以下的运行过程，需要启动 cygwin, 进入模拟 Linux 环境。在下载的 Hadoop
Core 包中，带有几个示例程序并且已经打包成了 hadoop-0.16.0-examples.jar。其中有一个 WordCount
程序，功能是统计一批文本文件中各个单词出现的次数，我们先来看看怎么运行这个程序。Hadoop 共有三种运行模式:
单机(非分布式)模式，伪分布式运行模式，分布式运行模式，其中前两种运行模式体现不了 Hadoop
分布式计算的优势，并没有什么实际意义，但对程序的测试及调试很有帮助，我们先从这两种模式入手，了解基于 Hadoop
的分布式并行程序是如何编写和运行的。
<br />
<br />
单机(非分布式)模式
<br />
<br />
这种模式在一台单机上运行，没有分布式文件系统，而是直接读写本地操作系统的文件系统。
<br />
<br />
<br />
代码清单1
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <embed src="http://mintelong.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=%24%20cd%20%2Fcygdrive%2Fc%2Fhadoop-0.16.0%0A%24%20mkdir%20test-in%20%20%0A%24%20cd%20test-in%0A%23%E5%9C%A8%20test-in%20%E7%9B%AE%E5%BD%95%E4%B8%8B%E5%88%9B%E5%BB%BA%E4%B8%A4%E4%B8%AA%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%2C%20WordCount%20%E7%A8%8B%E5%BA%8F%E5%B0%86%E7%BB%9F%E8%AE%A1%E5%85%B6%E4%B8%AD%E5%90%84%E4%B8%AA%E5%8D%95%E8%AF%8D%E5%87%BA%E7%8E%B0%E6%AC%A1%E6%95%B0%0A%24%20echo%20%22hello%20world%20bye%20world%22%20%3Efile1.txt%20%20%20%0A%24%20echo%20%22hello%20hadoop%20goodbye%20hadoop%22%20%3Efile2.txt%0A%24%20cd%20..%0A%24%20bin%2Fhadoop%20jar%20hadoop-0.16.0-examples.jar%20wordcount%20test-in%20test-out%0A%23%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%EF%BC%8C%E4%B8%8B%E9%9D%A2%E6%9F%A5%E7%9C%8B%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%24%20cd%20test-out%0A%24%20cat%20part-00000%0Abye%20%20%20%20%201%0Agoodbye%20%201%0Ahadoop%20%202%0Ahello%20%20%20%202%0Aworld%20%20%202" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="14" height="15"></div>
</div>
<ol class="dp-j" start="1">
    <li><span><span>$&nbsp;cd&nbsp;/cygdrive/c/hadoop-</span><span class="number">0.16</span><span>.</span><span class="number">0</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>$&nbsp;mkdir&nbsp;test-in&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;cd&nbsp;test-in&nbsp;&nbsp;</span></li>
    <li><span>#在&nbsp;test-in&nbsp;目录下创建两个文本文件,&nbsp;WordCount&nbsp;程序将统计其中各个单词出现次数&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;echo&nbsp;<span class="string">"hello&nbsp;world&nbsp;bye&nbsp;world"</span><span>&nbsp;&gt;file1.txt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li>
    <li><span>$&nbsp;echo&nbsp;<span class="string">"hello&nbsp;hadoop&nbsp;goodbye&nbsp;hadoop"</span><span>&nbsp;&gt;file2.txt&nbsp;&nbsp;</span></span></li>
    <li><span>$&nbsp;cd&nbsp;..&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;bin/hadoop&nbsp;jar&nbsp;hadoop-<span class="number">0.16</span><span>.</span><span class="number">0</span><span>-examples.jar&nbsp;wordcount&nbsp;test-in&nbsp;test-out&nbsp;&nbsp;</span></span></li>
    <li><span>#执行完毕，下面查看执行结果：&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;cd&nbsp;test-out&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;cat&nbsp;part-<span class="number">00000</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>bye&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">1</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>goodbye&nbsp;&nbsp;<span class="number">1</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>hadoop&nbsp;&nbsp;<span class="number">2</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>hello&nbsp;&nbsp;&nbsp;&nbsp;<span class="number">2</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>world&nbsp;&nbsp;&nbsp;<span class="number">2</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="java">$ cd /cygdrive/c/hadoop-0.16.0
$ mkdir test-in
$ cd test-in
#在 test-in 目录下创建两个文本文件, WordCount 程序将统计其中各个单词出现次数
$ echo "hello world bye world" &gt;file1.txt
$ echo "hello hadoop goodbye hadoop" &gt;file2.txt
$ cd ..
$ bin/hadoop jar hadoop-0.16.0-examples.jar wordcount test-in test-out
#执行完毕，下面查看执行结果：
$ cd test-out
$ cat part-00000
bye     1
goodbye  1
hadoop  2
hello    2
world   2</pre>
<br />
<br />
注意事项：运行 bin/hadoop jar hadoop-0.16.0-examples.jar wordcount test-in
test-out 时，务必注意第一个参数是 jar, 不是 -jar, 当你用 -jar
时，不会告诉你是参数错了，报告出来的错误信息是：Exception in thread "main"
java.lang.NoClassDefFoundError: org/apache/hadoop/util/ProgramDriver,
笔者当时以为是 classpath 的设置问题，浪费了不少时间。通过分析 bin/hadoop 脚本可知，-jar 并不是 bin/hadoop
脚本定义的参数，此脚本会把 -jar 作为 Java 的参数，Java 的-jar 参数表示执行一个 Jar 文件(这个 Jar
文件必须是一个可执行的 Jar,即在 MANIFEST 中定义了主类), 此时外部定义的 classpath 是不起作用的，因而会抛出
java.lang.NoClassDefFoundError 异常。而 jar 是 bin/hadoop 脚本定义的参数，会调用 Hadoop
自己的一个工具类 RunJar，这个工具类也能够执行一个 Jar 文件，并且外部定义的 classpath 有效。
<br />
<br />
伪分布式运行模式
<br />
<br />
这种模式也是在一台单机上运行，但用不同的 Java 进程模仿分布式运行中的各类结点 ( NameNode, DataNode,
JobTracker, TaskTracker, Secondary NameNode )，请注意分布式运行中的这几个结点的区别：
<br />
<br />
从分布式存储的角度来说，集群中的结点由一个 NameNode 和若干个 DataNode 组成, 另有一个 Secondary
NameNode 作为 NameNode 的备份。从分布式应用的角度来说，集群中的结点由一个 JobTracker 和若干个
TaskTracker 组成，JobTracker 负责任务的调度，TaskTracker 负责并行执行任务。TaskTracker 必须运行在
DataNode 上，这样便于数据的本地计算。JobTracker 和 NameNode 则无须在同一台机器上。
<br />
<br />
(1) 按代码清单2修改 conf/hadoop-site.xml。注意 conf/hadoop-default.xml 中是
Hadoop 缺省的参数，你可以通过读此文件了解 Hadoop 中有哪些参数可供配置，但不要修改此文件。可通过修改
conf/hadoop-site.xml 改变缺省参数值，此文件中设置的参数值会覆盖 conf/hadoop-default.xml
的同名参数。
<br />
<br />
<br />
代码清单 2
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <embed src="http://mintelong.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=%3Cconfiguration%3E%0A%20%20%3Cproperty%3E%0A%20%20%20%20%3Cname%3Efs.default.name%3C%2Fname%3E%0A%20%20%20%20%3Cvalue%3Elocalhost%3A9000%3C%2Fvalue%3E%0A%20%20%3C%2Fproperty%3E%0A%20%20%3Cproperty%3E%0A%20%20%20%20%3Cname%3Emapred.job.tracker%3C%2Fname%3E%0A%20%20%20%20%3Cvalue%3Elocalhost%3A9001%3C%2Fvalue%3E%0A%20%20%3C%2Fproperty%3E%0A%20%20%3Cproperty%3E%0A%20%20%20%20%3Cname%3Edfs.replication%3C%2Fname%3E%0A%20%20%20%20%3Cvalue%3E1%3C%2Fvalue%3E%0A%20%20%3C%2Fproperty%3E%0A%3C%2Fconfiguration%3E" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="14" height="15"></div>
</div>
<ol class="dp-j" start="1">
    <li><span><span>&lt;configuration&gt;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&lt;property&gt;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;fs.<span class="keyword">default</span><span>.name&lt;/name&gt;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;localhost:<span class="number">9000</span><span>&lt;/value&gt;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&lt;/property&gt;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&lt;property&gt;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;mapred.job.tracker&lt;/name&gt;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;localhost:<span class="number">9001</span><span>&lt;/value&gt;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&lt;/property&gt;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&lt;property&gt;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;dfs.replication&lt;/name&gt;&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;<span class="number">1</span><span>&lt;/value&gt;&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&lt;/property&gt;&nbsp;&nbsp;</span></li>
    <li><span>&lt;/configuration&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="java">&lt;configuration&gt;
&lt;property&gt;
&lt;name&gt;fs.default.name&lt;/name&gt;
&lt;value&gt;localhost:9000&lt;/value&gt;
&lt;/property&gt;
&lt;property&gt;
&lt;name&gt;mapred.job.tracker&lt;/name&gt;
&lt;value&gt;localhost:9001&lt;/value&gt;
&lt;/property&gt;
&lt;property&gt;
&lt;name&gt;dfs.replication&lt;/name&gt;
&lt;value&gt;1&lt;/value&gt;
&lt;/property&gt;
&lt;/configuration&gt;</pre>
<br />
<br />
参数 fs.default.name 指定 NameNode 的 IP 地址和端口号。缺省值是 file:///, 表示使用本地文件系统, 用于单机非分布式模式。此处我们指定使用运行于本机 localhost 上的 NameNode。
<br />
<br />
参数 mapred.job.tracker 指定 JobTracker 的 IP 地址和端口号。缺省值是 local, 表示在本地同一
Java 进程内执行 JobTracker 和 TaskTracker, 用于单机非分布式模式。此处我们指定使用运行于本机 localhost
上的 JobTracker ( 用一个单独的 Java 进程做 JobTracker )。
<br />
<br />
参数 dfs.replication 指定 HDFS 中每个 Block 被复制的次数，起数据冗余备份的作用。在典型的生产系统中，这个数常常设置为3。
<br />
<br />
(2)配置 SSH,如代码清单3所示:
<br />
<br />
<br />
代码清单 3
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <embed src="http://mintelong.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=%24%20ssh-keygen%20-t%20dsa%20-P%20''%20-f%20~%2F.ssh%2Fid_dsa%20%0A%24%20cat%20~%2F.ssh%2Fid_dsa.pub%20%3E%3E%20~%2F.ssh%2Fauthorized_keys" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="14" height="15"></div>
</div>
<ol class="dp-j" start="1">
    <li><span><span>$&nbsp;ssh-keygen&nbsp;-t&nbsp;dsa&nbsp;-P&nbsp;</span><span class="string">''</span><span>&nbsp;-f&nbsp;~/.ssh/id_dsa&nbsp;&nbsp;&nbsp;</span></span></li>
    <li><span>$&nbsp;cat&nbsp;~/.ssh/id_dsa.pub&nbsp;&gt;&gt;&nbsp;~/.ssh/authorized_keys&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="java">$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
$ cat ~/.ssh/id_dsa.pub &gt;&gt; ~/.ssh/authorized_keys</pre>
<br />
<br />
配置完后，执行一下 ssh localhost, 确认你的机器可以用 SSH 连接，并且连接时不需要手工输入密码。
<br />
<br />
(3)格式化一个新的分布式文件系统, 如代码清单4所示:
<br />
<br />
<br />
代码清单 4
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <embed src="http://mintelong.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=%24%20cd%20%2Fcygdrive%2Fc%2Fhadoop-0.16.0%0A%24%20bin%2Fhadoop%20namenode%20%E2%80%93format%20" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="14" height="15"></div>
</div>
<ol class="dp-j" start="1">
    <li><span><span>$&nbsp;cd&nbsp;/cygdrive/c/hadoop-</span><span class="number">0.16</span><span>.</span><span class="number">0</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>$&nbsp;bin/hadoop&nbsp;namenode&nbsp;&#8211;format&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="java">$ cd /cygdrive/c/hadoop-0.16.0
$ bin/hadoop namenode &#8211;format </pre>
<br />
<br />
(4) 启动 hadoop 进程, 如代码清单5所示。控制台上的输出信息应该显示启动了 namenode, datanode,
secondary namenode, jobtracker, tasktracker。启动完成之后，通过 ps &#8211;ef
应该可以看到启动了5个新的 java 进程。
<br />
<br />
代码清单 5
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <embed src="http://mintelong.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=%24%20bin%2Fstart-all.sh%20%20%0A%24%20ps%20%E2%80%93ef" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="14" height="15"></div>
</div>
<ol class="dp-j" start="1">
    <li><span><span>$&nbsp;bin/start-all.sh&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li>
    <li><span>$&nbsp;ps&nbsp;&#8211;ef&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="java">$ bin/start-all.sh
$ ps &#8211;ef</pre>
<br />
<br />
(5) 运行 wordcount 应用, 如代码清单6所示:
<br />
<br />
代码清单 6
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <embed src="http://mintelong.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard=%24%20bin%2Fhadoop%20dfs%20-put%20.%2Ftest-in%20input%20%20%0A%23%E5%B0%86%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B8%8A%E7%9A%84%20.%2Ftest-in%20%E7%9B%AE%E5%BD%95%E6%8B%B7%E5%88%B0%20HDFS%20%E7%9A%84%E6%A0%B9%E7%9B%AE%E5%BD%95%E4%B8%8A%EF%BC%8C%E7%9B%AE%E5%BD%95%E5%90%8D%E6%94%B9%E4%B8%BA%20input%0A%23%E6%89%A7%E8%A1%8C%20bin%2Fhadoop%20dfs%20%E2%80%93help%20%E5%8F%AF%E4%BB%A5%E5%AD%A6%E4%B9%A0%E5%90%84%E7%A7%8D%20HDFS%20%E5%91%BD%E4%BB%A4%E7%9A%84%E4%BD%BF%E7%94%A8%E3%80%82%0A%24%20bin%2Fhadoop%20jar%20hadoop-0.16.0-examples.jar%20wordcount%20input%20output%0A%23%E6%9F%A5%E7%9C%8B%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%3A%0A%23%E5%B0%86%E6%96%87%E4%BB%B6%E4%BB%8E%20HDFS%20%E6%8B%B7%E5%88%B0%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%86%8D%E6%9F%A5%E7%9C%8B%EF%BC%9A%0A%24%20bin%2Fhadoop%20dfs%20-get%20output%20output%20%0A%24%20cat%20output%2F*%0A%23%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E6%9F%A5%E7%9C%8B%0A%24%20bin%2Fhadoop%20dfs%20-cat%20output%2F*%0A%24%20bin%2Fstop-all.sh%20%23%E5%81%9C%E6%AD%A2%20hadoop%20%E8%BF%9B%E7%A8%8B" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="14" height="15"></div>
</div>
<ol class="dp-j" start="1">
    <li><span><span>$&nbsp;bin/hadoop&nbsp;dfs&nbsp;-put&nbsp;./test-in&nbsp;input&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li>
    <li><span>#将本地文件系统上的&nbsp;./test-in&nbsp;目录拷到&nbsp;HDFS&nbsp;的根目录上，目录名改为&nbsp;input&nbsp;&nbsp;</span></li>
    <li><span>#执行&nbsp;bin/hadoop&nbsp;dfs&nbsp;&#8211;help&nbsp;可以学习各种&nbsp;HDFS&nbsp;命令的使用。&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;bin/hadoop&nbsp;jar&nbsp;hadoop-<span class="number">0.16</span><span>.</span><span class="number">0</span><span>-examples.jar&nbsp;wordcount&nbsp;input&nbsp;output&nbsp;&nbsp;</span></span></li>
    <li><span>#查看执行结果:&nbsp;&nbsp;</span></li>
    <li><span>#将文件从&nbsp;HDFS&nbsp;拷到本地文件系统中再查看：&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;bin/hadoop&nbsp;dfs&nbsp;-get&nbsp;output&nbsp;output&nbsp;&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;cat&nbsp;output/*&nbsp;&nbsp;</span></li>
    <li><span>#也可以直接查看&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;bin/hadoop&nbsp;dfs&nbsp;-cat&nbsp;output/*&nbsp;&nbsp;</span></li>
    <li><span>$&nbsp;bin/stop-all.sh&nbsp;#停止&nbsp;hadoop&nbsp;进程&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none;" name="code" class="java">$ bin/hadoop dfs -put ./test-in input
#将本地文件系统上的 ./test-in 目录拷到 HDFS 的根目录上，目录名改为 input
#执行 bin/hadoop dfs &#8211;help 可以学习各种 HDFS 命令的使用。
$ bin/hadoop jar hadoop-0.16.0-examples.jar wordcount input output
#查看执行结果:
#将文件从 HDFS 拷到本地文件系统中再查看：
$ bin/hadoop dfs -get output output
$ cat output/*
#也可以直接查看
$ bin/hadoop dfs -cat output/*
$ bin/stop-all.sh #停止 hadoop 进程</pre>
<br />
<br />
故障诊断
<br />
<br />
(1) 执行 $ bin/start-all.sh 启动 Hadoop 进程后，会启动5个 java 进程, 同时会在 /tmp
目录下创建五个 pid 文件记录这些进程 ID 号。通过这五个文件，可以得知 namenode, datanode, secondary
namenode, jobtracker, tasktracker 分别对应于哪一个 Java 进程。当你觉得 Hadoop
工作不正常时，可以首先查看这5个 java 进程是否在正常运行。
<br />
<br />
(2) 使用 web 接口。访问 http://localhost:50030 可以查看 JobTracker 的运行状态。访问
http://localhost:50060 可以查看 TaskTracker 的运行状态。访问 http://localhost:50070
可以查看 NameNode 以及整个分布式文件系统的状态，浏览分布式文件系统中的文件以及 log 等。
<br />
<br />
(3) 查看 ${HADOOP_HOME}/logs 目录下的 log 文件，namenode, datanode, secondary
namenode, jobtracker, tasktracker 各有一个对应的 log 文件，每一次运行的计算任务也有对应用 log
文件。分析这些 log 文件有助于找到故障原因。
<br />
<br />
<br />
结束语
<br />
<br />
现在，你已经了解了 MapReduce 计算模型，分布式文件系统 HDFS，分布式并行计算等的基本原理, 并且有了一个可以运行的 Hadoop 环境，运行了一个基于 Hadoop 的并行程序。
<img src ="http://www.blogjava.net/tinysun/aggbug/328098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-08-06 09:42 <a href="http://www.blogjava.net/tinysun/archive/2010/08/06/328098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OOP遵照：Liskov替换原则--LSP </title><link>http://www.blogjava.net/tinysun/archive/2010/04/13/318154.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Tue, 13 Apr 2010 06:00:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/04/13/318154.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/318154.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/04/13/318154.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/318154.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/318154.html</trackback:ping><description><![CDATA[ <img src ="http://www.blogjava.net/tinysun/aggbug/318154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-04-13 14:00 <a href="http://www.blogjava.net/tinysun/archive/2010/04/13/318154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>轻松学习两台笔记本无线互联 转</title><link>http://www.blogjava.net/tinysun/archive/2010/01/07/308561.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 07 Jan 2010 08:05:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/01/07/308561.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/308561.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/01/07/308561.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/308561.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/308561.html</trackback:ping><description><![CDATA[<strong><font color="#004080"><a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>双机互连配置</font></strong>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们在一台机子的网上邻居，右键点击选择&#8220;属性&#8221;如下图。</p>
<p align="center"><img src="http://www.9orange.com/uploadpic/20059794852890.jpg" border="0"  alt="" /></p>
<p><font color="#0000ff"><strong>&nbsp;&nbsp;&nbsp;&nbsp; 1）</strong></font><font color="#000000">选中要来设置的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网卡的连接&#8220;网络连接&#8221;窗口，右击打算用来共享的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网卡并且选择&#8220;属性&#8221;，会弹出以下的窗口。</font></p>
<p align="center"><img src="http://www.9orange.com/uploadpic/20059794928316.jpg" border="0"  alt="" /></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设置笔记本电脑（也可能是台式机）的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网卡TCP/<a href="http://www.9orange.com/immobile_info.asp?typeid=000100220023" target="_blank"><strong>IP</strong></a>属性。在<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络连接项属性对话框的 &#8220;常规&#8221;选项卡中设置<a href="http://www.9orange.com/immobile_info.asp?typeid=000100220023" target="_blank"><strong>IP</strong></a>地址。两台机子设置成同网段的，例如：&#8220;192.168.1.X&#8221;（X是代表一个数值，从0到255，都可以），子网掩码设置为255.255.255.0。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff">2）</font></strong>选择&#8220;<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络配置&#8221;选项卡。选择&#8220;用Windows配置我的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络设置&#8221;复选项，以激活下面的其他配置选项。</p>
<p align="center"><img src="http://www.9orange.com/uploadpic/20059795010307.jpg" border="0"  alt="" /></p>
<p>&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff"> 3）</font></strong>如果要添加新的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络，可单击&#8220;添加&#8221;按钮，在打开的如下图所示对话框中进行。在下方选择&#8220;添加&#8221;按钮，会弹出下图的窗口，在服务名(SSID)中填写你喜欢的名称，注意不能用中文，其他电脑在寻找这个点对点连接的时候就会看到这个名字，我们在此写grfwgr。然后在打开的页面里进行相关设置。</p>
<p align="center"><img src="http://www.9orange.com/uploadpic/20059795043431.jpg" border="0"  alt="" /></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先要配置的是<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络SSID，一定要与对应的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网卡所配置的SSID一致。然后在下面的&#8220;<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络密钥&#8221;项下配置与对应<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网卡相同的安全选项。并要选择&#8220;这是一个计算机到计算机（特定的）网络；没有使用<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>访问点（C）&#8221;复选项。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff">4）</font></strong>如果想要配置IEEE 802.1x身份验证，则单击如（<font color="#0000ff">第2步</font>）所示对话框中的&#8220;验证&#8221;选项卡，如下图所示。</p>
<p align="center"><img src="http://www.9orange.com/uploadpic/2005979519935.jpg" border="0"  alt="" /></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在其中就可以选择两种IEEE 802.1x身份验证方法。当然如果选择的是&#8220;智能卡或其它证书&#8221;选项，则一定安装了智能卡或计算机证书，通常不用配置IEEE 802.1x身份验证。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff"><strong>5）</strong></font>在&#8220;连接&#8221;选项卡中仅配置是否允许计算机当所配置的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络在有效区域中即自动连接，非常简单，不作详细介绍。配置好后单击&#8220;确定&#8221;按钮返回到如（<font color="#0000ff">第1步</font>）所示对话框。</p>
&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff">6）</font></strong>在（<font color="#0000ff">第1步</font>）所示对话框中单击&#8220;高级&#8221;按钮，打开如下图所示对话框。
<p align="center"><img src="http://www.9orange.com/uploadpic/20059795815215.jpg" border="0"  alt="" /></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在此对话框中要指定客户端所连接的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络类型，将&#8220;任何可用的网络&#8221;更改为&#8220;仅计算机到计算机&#8221;，并关闭&#8220;自动连接到非首选的网络&#8221;选项。完成后单击&#8220;确定&#8221;按钮返回到如（<font color="#0000ff">第1步</font>）所示对话框。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff">7）</font></strong>在另一台笔记本电脑上，再次用鼠标右键单击任务栏右侧的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络连接状态指示图标，这时可以发现在弹出的&#8220;连接到<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络&#8221;对话框中已经有了一个另一台我们设置的标志，本文里为&#8220;grfwgz&#8221;的可用<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络，选中它并在&#8220;允许我连接到选择的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络，即使它是不安全的&#8221;选项前打上&#8220;&#8730;&#8221;，然后点击&#8220;连接&#8221;按钮。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这时，如果把鼠标指针指向任务栏上的<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络连接状态指示图标，可以看到两台笔记本电脑<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>连接的有关情况，如速度、信号强度等。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff">8）</font></strong>为了使用方便，把两台笔记本电脑设置成同一工作组。打开网上邻居，两台笔记本电脑均可看到包括对方在内的两台机器的图标。把需要交换数据的硬盘或文件夹设成共享之后，两台笔记本电脑就可以交换资料了。</p>
<p>&nbsp;&nbsp;&nbsp;<font color="#ff0000"><strong> 注：</strong></font><font color="#ff0000">如果是Windows XP之前的操作系统，还需要将两个<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网络适配器的通道设置统一。Windows 2000就需要在网络适配器的属性里面修改channel的值。</font></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其实也可以在<a href="http://www.9orange.com/wifi_index.asp" target="_blank"><strong>无线</strong></a>网卡连接属性配置对话框中的&#8220;高级&#8221;选项卡中选择&#8220;自动连接非首选网络&#8221;复选框。这样笔记本会自动搜索可用网络进行连接。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong><font style="background-color: #ffff66">两台</font></strong>机器都有无线网卡话，直接启用无线网卡的对接模式（只限<strong style="color: black; background-color: #ffff66">两台</strong>）就可以了,这种方式不用路由器的，一般的无线网卡都有这种功能。 <br />
对接成功后，就是标准的局域网，所有的功能都可用，更别说简单的玩游戏了.方法如下 <br />
1在<strong style="color: black; background-color: #ffff66">两台</strong>机器的无线网络连接上单击右键，开启它的属性窗口，双击TCP/IP协议。 <br />
2. 输入第一台电脑的IP地址192.168.0.1和子网掩码255.255.255.0。同理另外一台设置为192.168.0.2、255.255.255.0，网关和DNS参数不填。 <br />
3. 切换到&#8220;无线网络配置&#8221;标签，单击&#8220;高级&#8221;按钮，在&#8220;高级&#8221;窗口选择&#8220;仅计算机到计算机（特定）&#8221;选项，单击&#8220;关闭&#8221;按钮返回上一个窗口。 <br />
4. 在第一台电脑的&#8220;无线网络配置&#8221;标签中单击&#8220;添加&#8221;按钮添加一个可用网络，输入服务名（SSID），这个名称与在&#8220;网上邻居&#8221;中的工作组名称一样可让其他电脑检测到，其他参数用默认的即可。完成此操作后确认关闭所有窗口。 <br />
5. 在第二台&#8220;网络连接&#8221;窗口选择无线网络连接，单击右键执行&#8220;查看可用的无线连接&#8221;功能，Windows便可检测到第一台电脑创建的无线网络,加入即可。</p>
<img src ="http://www.blogjava.net/tinysun/aggbug/308561.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-01-07 16:05 <a href="http://www.blogjava.net/tinysun/archive/2010/01/07/308561.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大端法、小端法、网络字节序  转</title><link>http://www.blogjava.net/tinysun/archive/2009/12/31/307952.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 31 Dec 2009 13:33:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/31/307952.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/307952.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/31/307952.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/307952.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/307952.html</trackback:ping><description><![CDATA[<div class="motadou_spec_line"><font class="title">关于字节序(大端法、小端法)的定义</font></div>
《UNXI网络编程》定义：术语&#8220;小端&#8221;和&#8220;大端&#8221;表示多字节值的哪一端(小端或大端)存储在该值的起始地址。小端存在起始地址，即是小端字节序；大端存在起始地址，即是大端字节序。
<p>&nbsp;</p>
<p>也可以说： <br />
1.小端法(Little-Endian)就是低位字节排放在内存的低地址端即该值的起始地址，高位字节排放在内存的高地址端。 <br />
2.大端法(Big-Endian)就是高位字节排放在内存的低地址端即该值的起始地址，低位字节排放在内存的高地址端。</p>
<p>举个简单的例子，对于整形0x12345678。它在大端法和小端法的系统内中，分别如图1所示的方式存放。</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/motadou/WindowsLiveWriter/029908e67cac_BAC0/zijiexu_pic_1_2.jpg"><img title="zijiexu_pic_1" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="378" alt="zijiexu_pic_1" src="http://images.cnblogs.com/cnblogs_com/motadou/WindowsLiveWriter/029908e67cac_BAC0/zijiexu_pic_1_thumb.jpg" width="603" border="0" /></a>&nbsp;</p>
<p>&nbsp;</p>
<div class="motadou_spec_line"><font class="title">网络字节序</font></div>
<p>我们知道网络上的数据流是字节流，对于一个多字节数值，在进行网络传输的时候，先传递哪个字节？也就是说，当接收端收到第一个字节的时候，它是将这个字节作为高位还是低位来处理呢？ <br />
网络字节序定义：收到的第一个字节被当作高位看待，这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时，发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前，在内存中数值应该以大端法存放。 <br />
网络字节序说是大端字节序。 <br />
比如我们经过网络发送0x12345678这个整形，在80X86平台中，它是以小端法存放的，在发送前需要使用系统提供的htonl将其转换成大端法存放，如图2所示。 </p>
<p><a href="http://images.cnblogs.com/cnblogs_com/motadou/WindowsLiveWriter/029908e67cac_BAC0/zijiexu_pic_2_2.jpg"><img title="zijiexu_pic_2" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="378" alt="zijiexu_pic_2" src="http://images.cnblogs.com/cnblogs_com/motadou/WindowsLiveWriter/029908e67cac_BAC0/zijiexu_pic_2_thumb.jpg" width="605" border="0" /></a> </p>
<p>&nbsp;</p>
<div class="motadou_spec_line"><font class="title">字节序测试程序 <br />
</font></div>
不同cpu平台上字节序通常也不一样，下面写个简单的C程序，它可以测试不同平台上的字节序。
<div style="font-size: 12px; line-height: 16px; font-family: courier new">
<table style="border-top-width: 0px; padding-right: 0px; padding-left: 0px; border-left-width: 0px; border-bottom-width: 0px; padding-bottom: 0px; width: 100%; padding-top: 0px; border-right-width: 0px" cellspacing="0">
    <tbody>
        <tr>
            <td style="color: teal" valign="top" width="42">1&nbsp; </td>
            <td width="700"><span style="color: #0000ff">#include</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">&lt;</span><span style="color: #000000">stdio</span><span style="color: #000000">.</span><span style="color: #000000">h</span><span style="color: #800000">&gt;</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">2&nbsp; </td>
            <td width="700"><span style="color: #0000ff">#include</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">&lt;</span><span style="color: #000000">netinet</span><span style="color: #000000">/</span><span style="color: #000000">in</span><span style="color: #000000">.</span><span style="color: #000000">h</span><span style="color: #800000">&gt;</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">3&nbsp; </td>
            <td width="700"><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">main()</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">4&nbsp; </td>
            <td width="700"><span style="color: #800000">{</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">5&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">0x12345678</span><span style="color: #000000">;</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">6&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[0]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">0</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">7&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[1]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">1</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">8&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[2]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">2</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">9&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[3]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">3</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">10&nbsp; </td>
            <td width="700">&nbsp;</td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">11&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">htonl(i_num);</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">12&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[0]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">0</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">13&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[1]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">1</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">14&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[2]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">2</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">15&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">printf</span><span style="color: #000000">(</span><span style="color: #800000">"</span><span style="color: #800000">[3]:0x%x\n</span><span style="color: #800000">"</span><span style="color: #000000">,</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">i_num</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">3</span><span style="color: #000000">));</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">16&nbsp; </td>
            <td width="700">&nbsp;</td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">17&nbsp; </td>
            <td width="700"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">0</span><span style="color: #000000">;</span></td>
        </tr>
        <tr>
            <td style="color: teal" valign="top" width="42">18&nbsp; </td>
            <td width="700"><span style="color: #800000">}</span><span style="color: #000000">&nbsp;</span></td>
        </tr>
    </tbody>
</table>
</div>
<p><br />
在80X86CPU平台上，执行该程序得到如下结果： <br />
[0]:0x78 <br />
[1]:0x56 <br />
[2]:0x34 <br />
[3]:0x12 </p>
<p>[0]:0x12 <br />
[1]:0x34 <br />
[2]:0x56 <br />
[3]:0x78 </p>
<p>分析结果，在80X86平台上，系统将多字节中的低位存储在变量起始地址，使用小端法。htonl将i_num转换成网络字节序，可见网络字节序是大端法。</p>
<p><font color="#ff0000"><strong>总结点：80X86使用小端法，网络字节序使用大端法。</strong></font></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/307952.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-31 21:33 <a href="http://www.blogjava.net/tinysun/archive/2009/12/31/307952.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何编写单元测试用例（白盒测试）</title><link>http://www.blogjava.net/tinysun/archive/2009/12/05/304842.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sat, 05 Dec 2009 04:50:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/05/304842.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/304842.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/05/304842.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/304842.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/304842.html</trackback:ping><description><![CDATA[转<br />
<p><font style="background-color: #cce8cf">一、 单元测试的概念 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 单元通俗的说就是指一个实现简单功能的函数。单元测试就是只用一组特定的输入(测试用例)测试函数是否功能正常，并且返回了正确的输出。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试的覆盖种类 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.语句覆盖：语句覆盖就是设计若干个测试用例，运行被测试程序，使得每一条可执行语句至少执行一次。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.判定覆盖（也叫分支覆盖）：设计若干个测试用例，运行所测程序，使程序中每个判断的取真分支和取假分支至少执行一次。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.条件覆盖：设计足够的测试用例，运行所测程序，使程序中每个判断的每个条件的每个可能取值至少执行一次。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.判定——条件覆盖：设计足够的测试用例，运行所测程序，使程序中每个判断的每个条件的每个可能取值至少执行一次，并且每个可能的判断结果也至少执行一次。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.条件组合测试：设计足够的测试用例，运行所测程序，使程序中每个判断的所有条件取值组合至少执行一次。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6.路径测试：设计足够的测试用例，运行所测程序，要覆盖程序中所有可能的路径。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用例的设计方案主要的有下面几种：条件测试，基本路径测试，循环测试。通过上面的方法可以实现测试用例对程序的逻辑覆盖，和路径覆盖。 <br />
二、开始测试前的准备 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在开始测试时，要先声明一下，无论你设计多少测试用例，无论你的测试方案多么完美，都不可能完全100%的发现所有BUG，我们所需要做的是用最少的资源，做最多测试检查，寻找一个平衡点保证程序的正确性。穷举测试是不可能的。&nbsp;&nbsp; 所以现在进行单元测试我选用的是现在一般用的比较多的基本路径测试法。 <br />
三、开始测试 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基本路径测试法：设计出的测试用例要保证每一个基本独立路径至少要执行一次。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 函数说明 ：当i_flag=0；返回&nbsp;&nbsp;&nbsp;&nbsp; i_count+100 <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;&nbsp;&nbsp;&nbsp;&nbsp; 当i_flag=1；返回&nbsp;&nbsp; i_count&nbsp; *10 <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;&nbsp;&nbsp;&nbsp;&nbsp; 否则&nbsp; 返回&nbsp;&nbsp; i_count&nbsp; *20 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输入参数：int i_count ，&nbsp;&nbsp; <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; int i_flag <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输出参数： int&nbsp; i_return;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 代码：</font></p>
<p><font style="background-color: #cce8cf">1 int Test(int i_count, int i_flag) <br />
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
3 int i_temp = 0; <br />
4 while (i_count&gt;0) <br />
5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
6 if (0 == i_flag) <br />
7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_temp = i_count + 100; <br />
9 break; <br />
10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
11 else <br />
12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
13 if (1 == i_flag) <br />
14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_temp = i_temp + 10; <br />
16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
17 else <br />
18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_temp = i_temp + 20; <br />
20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_count--; <br />
23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
24 return i_temp; <br />
25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.画出程序控制流程图 <br />
&nbsp;&nbsp;&nbsp; 图例： <br />
&nbsp;<br />
事例程序流程图： <br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 圈中的数字代表的是语句的行号，也许有人问为什么选4,6,13,8......作为结点，第2行，第3行为什么不是结点，因为选择结点是有规律的。让我们看程序中；第2行，第3行是按顺序执行下来的。直到第4行才出现了循环操作。而2，3行没有什么判断，选择等分支操作，所以我们把2，3，4全部合并成一个结点。其他的也是照这个规则合并，然后就有了上面的流程图。</font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.计算圈复杂度 <br />
&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;&nbsp;&nbsp;&nbsp;&nbsp; 圈复杂度是一种为程序逻辑复杂性提供定量测试的软件度量。将该度量用于计算程序的基本独立路径数目。为确保所有语句至少执行一次的测试数量的上界。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 公式圈复杂度V（G）=E-N+2，E是流图中边的数量，N是流图中结点的数量。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 公式圈复杂度V（G）=P+1 ，P是流图G中判定结点的数量。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通俗的说圈负责度就是判断单元是不是复杂，是不是好测试的标准。一般来说如果圈复杂度如果大于20就表示这个单元的可测试性不好，太复杂（也许有人觉得无所谓，但是如果你们公司实行了CMMI5的话，对这个是有规定的）。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从图中我们可以看到， <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; V（G）=10条边-8结点+2=4 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; V（G）=3个判定结点+1=4 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上图的圈复杂图是4。这个结果对我们来说有什么意义呢？它表示我们只要最多4个测试用例就可以达到基本路径覆盖。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.导出程序基本路径。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在我们知道了起码要写4个测试用例，但是怎么设计这4个测试用例？ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 导出程序基本路径，根据程序基本路径设计测试用例子。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 程序基本路径：基本独立路径就是从程序的开始结点到结束可以选择任何的路径遍历，但是每条路径至少应该包含一条已定义路径不曾用到的边。（看起来不好理解，让我们看例子）。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 让我们看上面的流程图：从结点4到24有几条路径呢？ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 B（4，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 C，E，J（4，6，8，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 C，D，F，H，A，B（4，6，13，15，22，4，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 C，D，G，I，A，B（4，6，13，19，22，4，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 还有吗？？ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5 C，D，C，I，A，C，E，J（4，6，13，19，22，4，6，8，24）算吗？ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不算，为什么？因为上面的4条路径已经包括了所有的边。第5条路径已经不包含没有用过的边了。所有的路径都遍历过了。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 好了，现在我们有了4条基本独立路径根据独立路径我们可以设计测试用例。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 B（4，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输入数据：i_flag=0，或者是i_flag&lt;0的某一个值。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 预期结果：i_temp=0. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 C，E，J（4，6，8，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输入数据： i_count =1;i_flag=0&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 预期结果：i_temp=101. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 C，D，F，H，A，B（4，6，13，15，22，4，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输入数据： i_count =1;i_flag=1&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 预期结果：i_temp=10. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 C，D，G，I，A，B（4，6，13，19，22，4，24） <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输入数据： i_count =1;i_flag=2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 预期结果：i_temp=20. <br />
这里的输入数据是由路径和程序推论出来的。而要注意的是预期结果是从函数说明中导出，不能根据程序结构中导出。 <br />
为什么这么说？ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 让我们看程序中的第3行。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i_temp=0;假如开发人员一不小心写错了，变成了int i_temp=1;根据程序导出的预期结果就会是一个错误的值，但是单元测试不出来问题。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那单元测试就失去了意义。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有人也许会问这么简单的函数就有4个测试用例，如果还复杂一些的怎么办？上面的测试用例还可以简化吗？答案是可以。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们来看 路径&nbsp;&nbsp;&nbsp; 1 B（4，24）和&nbsp;&nbsp; 4 C，D，G，I，A，B（4，6，13，19，22，4，24），路径1是路径4的真子集，&nbsp;&nbsp;&nbsp;&nbsp; 所以1是可以不必要的。上图的圈复杂度是4。这个结果对我们来说有什么意义呢？它表示我们只要最多4个测试用例就可以达到基本路径覆盖。所以说圈复杂度标示是最多的测试用例个数，不是一定要4个测试用例才可以。不过有一点要申明的是测试用例越简化代表你的测试越少，这样程序的安全性就越低了。 <br />
四、完成测试 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来根据测试用例使用工具测试NUNIT，VS2005都可以。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来根据测试结果编写测试报告，测试人，时间，结果，用例，是否通过，格式网上一大把，每个公司的格式也不一样就不说了。（来自cnblogs）</font></p>
<p><font style="background-color: #cce8cf"></font>&nbsp;</p>
<p><font style="background-color: #cce8cf">本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/Joe_wang/archive/2009/11/23/4857371.aspx</font></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/304842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-05 12:50 <a href="http://www.blogjava.net/tinysun/archive/2009/12/05/304842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORM技术概念与实例</title><link>http://www.blogjava.net/tinysun/archive/2009/04/23/267150.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 23 Apr 2009 07:02:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/04/23/267150.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/267150.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/04/23/267150.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/267150.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/267150.html</trackback:ping><description><![CDATA[对象关系映射（<span style="font-size: 10pt; font-family: 新宋体">Object Relational Mapping</span><span style="font-size: 10pt; font-family: 新宋体">，简称</span><span style="font-size: 10pt; font-family: 新宋体">ORM</span><span style="font-size: 10pt; font-family: 新宋体">）是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说，</span><span style="font-size: 10pt; font-family: 新宋体">ORM</span><span style="font-size: 10pt; font-family: 新宋体">是通过使用描述对象和数据库之间映射的元数据，将程序中的对象自动持久化到关系数据库中。</span><span style="font-size: 10pt; font-family: 新宋体">本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示者额外的执行开销；然而，如果ORM作为一种中间件实现，则会有很多机会做优化，而这些在手写的持久层并不存在。 </span><span style="font-size: 10pt; font-family: 新宋体">更重要的是用于控制转换的元数据需要提供和管理；但是同样，这些花费要比维护手写的方案要少</span><span style="font-size: 10pt; font-family: 新宋体">.</span>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 新宋体">对象</span><span style="font-size: 10pt; font-family: 新宋体">-</span><span style="font-size: 10pt; font-family: 新宋体">关系映射（</span><span style="font-size: 10pt; font-family: 新宋体">Object/Relation Mapping</span><span style="font-size: 10pt; font-family: 新宋体">，简称</span><span style="font-size: 10pt; font-family: 新宋体">ORM</span><span style="font-size: 10pt; font-family: 新宋体">），是随着面向对象的软件开发方法发展而产生的</span><span style="font-size: 10pt; font-family: 新宋体">,</span><span style="font-size: 10pt; font-family: 新宋体">面向对象的开发方法是当今企业级应用开发环境中的主流开发方法，关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。</span><span style="font-size: 10pt; font-family: 新宋体">对象和关系数据是业务实体的两种表现形式，业务实体在内存中表现为对象，在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系，而在数据库中，关系数据无法直接表达多对多关联和继承关系。因此，对象-关系映射(ORM)系统一般以中间件的形式存在，主要实现程序对象到关系数据库数据的映射。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 新宋体">面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的，而关系数据库则是从数学理论发展而来的，两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 新宋体">让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面，都存在对象和关系数据库。在业务逻辑层和用户界面层中，我们是面向对象的。当对象信息发生变化的时候，我们需要把对象的信息保存在关系数据库中。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10pt; font-family: 新宋体">当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码，用来从数据库保存，删除，读取对象信息，等等。你在DAL中写了很多的方法来读取对象数据，改变状态对象等等任务。而这些代码写起来总是重复的。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">&nbsp;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">　　如果打开你最近的程序，看看DAL代码，你肯定会看到很多近似的通用的模式。我们以保存对象的方法为例，你传入一个对象，为SqlCommand对象添加SqlParameter，把所有属性和对象对应，设置SqlCommand的CommandText属性为存储过程，然后运行SqlCommand。对于每个对象都要重复的写这些代码。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">　　除此之外，还有更好的办法吗？有，引入一个O/R Mapping。实质上，一个O/R Mapping会为你生成DAL。与其自己写DAL代码，不如用O/R Mapping。你用O/R Mapping保存，删除，读取对象，O/R Mapping负责生成SQL，你只需要关心对象就好。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 24pt"><span style="font-size: 10pt; font-family: 新宋体">一般的ORM包括以下四部分：</span></p>
<p style="margin: 0cm 0cm 0pt 60pt; text-indent: -24pt; tab-stops: list 60.0pt"><span style="font-size: 10pt; font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 10pt; font-family: 新宋体">一个对持久类对象进行</span><span style="font-size: 10pt; font-family: 新宋体">CRUD</span><span style="font-size: 10pt; font-family: 新宋体">操作的</span><span style="font-size: 10pt; font-family: 新宋体">API</span><span style="font-size: 10pt; font-family: 新宋体">；</span></p>
<p style="margin: 0cm 0cm 0pt 60pt; text-indent: -24pt; tab-stops: list 60.0pt"><span style="font-size: 10pt; font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 10pt; font-family: 新宋体">一个语言或</span><span style="font-size: 10pt; font-family: 新宋体">API</span><span style="font-size: 10pt; font-family: 新宋体">用来规定与类和类属性相关的查询；</span></p>
<p style="margin: 0cm 0cm 0pt 60pt; text-indent: -24pt; tab-stops: list 60.0pt"><span style="font-size: 10pt; font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 10pt; font-family: 新宋体">一个规定</span><span style="font-size: 10pt; font-family: 新宋体">mapping metadata</span><span style="font-size: 10pt; font-family: 新宋体">的工具；</span></p>
<p style="margin: 0cm 0cm 0pt 60pt; text-indent: -24pt; tab-stops: list 60.0pt"><span style="font-size: 10pt; font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 10pt; font-family: 新宋体">一种技术可以让</span><span style="font-size: 10pt; font-family: 新宋体">ORM</span><span style="font-size: 10pt; font-family: 新宋体">的实现同事务对象一起进行</span><span style="font-size: 10pt; font-family: 新宋体">dirty checking, lazy association fetching</span><span style="font-size: 10pt; font-family: 新宋体">以及其他的优化操作。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 10pt; font-family: 新宋体">事例</span></p>
<p style="margin: 0cm 0cm 0pt 24pt"><span style="font-size: 10pt; font-family: 新宋体">极致业务基础平台采用</span><span style="font-size: 10pt; font-family: 新宋体">ORM</span><span style="font-size: 10pt; font-family: 新宋体">技术实现数据的持久化</span><span style="font-size: 10pt; font-family: 新宋体">,</span><span style="font-size: 10pt; font-family: 新宋体">并提供了完整的实体定义工具</span><span style="font-size: 10pt; font-family: 新宋体">,</span><span style="font-size: 10pt; font-family: 新宋体">元数据管理机制</span><span style="font-size: 10pt; font-family: 新宋体">,</span><span style="font-size: 10pt; font-family: 新宋体">自动生成关系数据库表结构</span><span style="font-size: 10pt; font-family: 新宋体">.</span></p>
<p style="margin: 0cm 0cm 0pt 24pt"><span style="font-size: 10pt; font-family: 新宋体">平台下载地址</span><span style="font-size: 10pt; font-family: 新宋体">:</span></p>
<p style="margin: 0cm 0cm 0pt 24pt"><span style="font-family: 新宋体"><font size="3"><font color="#000000"><a href="http://www.jeez.com.cn/jbf"><font face="宋体"><a href="http://www.jeez.com.cn/jbf"><u>http://www.jeez.com.cn/</u></font><u>jbf</u></a></a></font></font></span></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/267150.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-04-23 15:02 <a href="http://www.blogjava.net/tinysun/archive/2009/04/23/267150.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用OpenVPN实现网通、电信机房间快速、安全通信</title><link>http://www.blogjava.net/tinysun/archive/2009/04/23/267118.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 23 Apr 2009 04:38:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/04/23/267118.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/267118.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/04/23/267118.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/267118.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/267118.html</trackback:ping><description><![CDATA[转<br />
<p><font color="blue">上半年为公司的南北互通工程研究实现的方式，最后决定使用openvpn来实现多个机房直接的互通。当时写了一份 很详细的文档，现在终于有时间发出来了。这份文档是完全根据openvpn官方网站上的文档以及我的实际配置写成。<br />
<font color="#666666"><strong><br />
</strong></font></font><font color="#666666"><strong><span style="font-size: 13px">目录：<br />
1 现状<br />
2 网络结构<br />
3 服务器信息以及网络安全<br />
3.1 服务器信息<br />
3.2 网络安全<br />
4 使用openvpn实现南北互通<br />
4.1 Openvpn简介<br />
4.2 下载<br />
4.3 安装<br />
4.4 你的操作系统支持tun吗？<br />
4.5 配置C/S结构的VPN网络<br />
4.5.1 如何生成ca和cert/key?<br />
4.5.1.1 产生MASTER Certificate Authority(CA) 的公钥(certificate)和私钥(key)<br />
4.5.1.2 创建server端的cert和key文件<br />
4.5.1.3 创建3个client端cert和key文件<br />
4.5.1.4 建立 Diffie Hellman文件<br />
4.5.1.5 所有文件的列表及使用的主机<br />
4.5.2 OpenVPN Server端的配置<br />
4.5.3 OpenVPN Client端的配置<br />
4.5.4 运行OpenVPN<br />
5 其它配置<br />
5.1 让多个client的子网间互通<br />
5.2 控制运行中的openvpn进程<br />
5.3 windows下的配置：<br />
6 实际应用情况<br />
7 参考文档 </span></strong></font><br />
<span style="font-size: 13px"><font color="blue"></span></p>
<p><span style="font-size: 13px"><big><strong>1 现状</strong></big><br />
假设现在的某公司的服务器存放在广州、河北、杭州三个机房中，每个机房使用不用的子网：<br />
</span><span style="font-size: 13px"><font color="#3333ff">机房 子网（内部）<br />
广州 10.1.0.0/16<br />
河北 10.2.0.0/16<br />
杭州 10.3.0.0/16</font></span></p>
<p><span style="font-size: 13px">各机房使用不同的网段，为使用vpn连接创造了有利条件。</span></p>
<p>由于电信至网通间的网络速度是否缓慢，对广州与河北机房间的数据同步带来非常大的困难。我们找到一台即连接了网通的线路，又连接了电信线路的服务器，但却不能直接用其作为路由。如果使用porxy的方式或转发的方式又会降低同步的效率。<br />
采用C/S结构的vpn方式，即解决了同步的问题，又不会影响同步的效率。</p>
<p><big><strong>2 网络结构</strong></big><br />
下图是三个机房实现互连互通后的拓扑图：<br />
<img src="http://www.joecen.com/images/openvpn-topu.jpg"  alt="" /></p>
<p>从上图可以看到，该VPN系统是一个C/S的结构。中间为VPN SERVER；广州、河北、杭州三个机房各取出一台服务器作为VPN CLIENT。</p>
<p>VPN SERVER拥有两块网卡和两条线路（电信和网通），两个网卡均需要设置公网IP。根据实际的情况设置路由，这里我是设置电信的线路为默认路由，设置到河北机房网段的走网通的路由。</p>
<p>VPN CLIENT可以有两块网卡也可以只用一块网卡，如果是电信的线路则连接vpn server的电信的IP；如果是网通的线路则连接网通的vpn server 的网通方面的IP。</p>
<p><big><strong>3 服务器信息以及网络安全</strong></big><br />
3.1 服务器信息<br />
在本文中我们使用了4台服务器分别作为vpn server和client。由于使用vpn传输数据对服务器的负载不大，所以除了vpn server需要一台新的服务器外，各机房的client服务器只需要找一台负载轻的服务器来担当即可。</p>
<p>本文使用的四台服务器的详细信息：<br />
<font color="#3333ff"><span style="font-size: 13px">机房 Vpn 模式 操作系统 服务器IP<br />
Vpn server RedHat 9.0 公网IP1 (网通) /公网IP2(电信)<br />
广州机房 Vpn client FreeBSD4.9 10.1.0.1<br />
河北机房 Vpn client RedHat9.0 10.2.0.1<br />
杭州机房 Vpn client FreeBsd4.9 10.3.0.1</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">3.2 网络安全<br />
除vpn server外，其它的机房中的vpn client均无需公网IP，所以vpn server需要加强安全方面的设置。<br />
该服务器是RedHat9.0的操作系统，登陆界面使用的是grub，并设置的grub密码，保证物理上的安全。<br />
使用Iptables设置包过滤防火墙，只允许你的服务器对其进行访问：<br />
</span><font color="#3333ff"><span style="font-size: 13px">iptables &#8211;F<br />
iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT<br />
iptables -A INPUT -s YOURNETWORK -j ACCEPT<br />
iptables -A INPUT -p udp --dport 1194 &#8211;j DROP</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px"><big><strong>4 使用openvpn实现南北互通</strong></big><br />
4.1 Openvpn简介<br />
OpenVPN 是一个强大、高度可配置、基于ssl的 VPN （Virtual Private Network）Open Source 软件。它具有多种的验证方式以及许多强大的功能。</span></p>
<p>OpenVPN工作在OSI模型的第2或第3层，使用SSL/TLS协议进行网络传输。支持多种客户认证方法，如证书、smart cards，加上用户名密码的证书认证等。除此以外，还有强大的ACL功能限制客户的信息交换。</p>
<p>OpenVPN可以运行在多种操作系统中，包括：<br />
Linux, Windows 2000/XP and higher, OpenBSD, FreeBSD, NetBSD, Mac OS X, and Solaris.</p>
<p>使用OpenVpn，可以实现:<br />
● 使用特定udp或tcp端口实现两台主机的之间的vpn连接。<br />
● 实现C/S结构，实现多台client通过server服务器互连互通。<br />
● 通过TLS/SSL加密保证数据传输的安全。<br />
● 通过数据的压缩，提高数据传输的速度。</p>
<p>（由于其它功能在本文中并不需要使用，如想要详细了解请访问http://openvpn.net）</p>
<p>4.2 下载</p>
<p>从以下网址下载最新版本的openvpn source包。<br />
http://nchc.dl.sourceforge.net/sourceforge/openvpn/openvpn-2.0_rc16.tar.gz</p>
<p>由于openvpn需要使用数据压缩，所以还需要安装lzo包：<br />
http://www.oberhumer.com/opensource/lzo/download/lzo-1.08.tar.gz</p>
<p>4.3 安装<br />
Linux：</p>
<blockquote>
<p><span style="font-size: 13px">软件 编译安装 </span><br />
<span style="font-size: 13px">Lzo ./configure &amp;&amp; Make &amp;&amp; make install </span><br />
<br />
<span style="font-size: 13px">Openvpn ./configure -prefix=/opt/openvpn&amp;&amp;Make &amp;&amp; make install</span></p>
</blockquote>
<p><span style="font-size: 13px">FreeBSD：</span></p>
<blockquote>
<p><span style="font-size: 13px">Lzo ./configure &amp;&amp;Make &amp;&amp; make install </span><br />
<br />
<span style="font-size: 13px">Openvpn ./configure -prefix=/opt/openvpn --with-lzo－headers=/usr/local/include --with-lzo-headers=/usr/local/include&amp;&amp; Make &amp;&amp; make install</span></p>
</blockquote>
<p><span style="font-size: 13px">参照上面的安装方法分别在linux和freebsd主机上安装好openvpn。</span></p>
<p>4.4 你的操作系统支持tun吗？<br />
从我安装过的操作系统看，RedHat9.0和FreeBSD4.9的内核默认已经支持TUN，并且已经安装tun模块。RedHat AS3则没有该模块，需要重新编译内核支持。</p>
<p>加载tun模块：<br />
●Linux 2.4 or higher (with integrated TUN/TAP driver):<br />
(1) make device node: mknod /dev/net/tun c 10 200<br />
(2a) add to /etc/modules.conf: alias char-major-10-200 tun<br />
(2b) load driver: modprobe tun<br />
(3) enable routing: echo 1 &gt;; /proc/sys/net/ipv4/ip_forward</p>
<p>●FreeBSD 4.1.1+:<br />
kldload if_tap</p>
<p><span style="font-size: 13px">4.5 配置C/S结构的VPN网络<br />
4.5.1 如何生成ca和cert/key?</span></p>
<p><font color="#3333ff"><span style="font-size: 13px">Ca certificate<br />
authority（认证授权），所有的server和client均使用同一个ca文件。<br />
cert certificate（证书）。公钥，每一个server和client各自独立生成的公钥。<br />
key 私钥，每一个server和client工作独立生成的私钥。</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">◎ server端只需要知道它自己的cert和key。它不需要知道每一个可以连接到它的client的cert。<br />
◎ server端接受的client必须拥有以server的CA产生的cert。server能使用它自己的CA私钥来确认client的cert中是否带有其CA的记号。</span></p>
<p>4.5.1.1 产生MASTER Certificate Authority(CA) 的公钥(certificate)和私钥(key)<br />
#######<br />
In this section we will generate a master CA certificate/key, a server certificate/key, and certificates/keys for 3 separate clients<br />
#######</p>
<p>在本节，我们会尝试建立一对master CA的cert和key，一对server端的cert和key，和3个不同client的年的cert和keys。</p>
<p>UNIX：<br />
在openvpn的源码中可以找到easy-rsa文件夹。</p>
<p>cd easy-rsa<br />
. ./vars 建立环境变量<br />
./clean-all 清除以前的<br />
./build-ca 建立CA</p>
<p>最后一个命令会调用openssl来创建CA的公钥和私钥:<br />
<span style="font-size: 13px"><br />
</span><font color="#3333ff"><span style="font-size: 13px">Country Name (2 letter code) [KG]:<br />
State or Province Name (full name) [NA]:<br />
Locality Name (eg, city) [BISHKEK]:<br />
Organization Name (eg, company) [OpenVPN-TEST]:yourcorp 在此输入公司名<br />
Organizational Unit Name (eg, section) []:<br />
Common Name (eg, your name or your server's hostname) []:hbroute 在此输入主机名或随便输一个名字<br />
Email Address [me@myhost.mydomain]:</span></font></p>
<p><font color="#3333ff">其它的按默认即可。</font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">完成后会在keys目录中创建ca.crt ca.key index.txt serial四个文件。</span></p>
<p>4.5.1.2 创建server端的cert和key文件</p>
<blockquote>
<p><span style="font-size: 13px">cd easy-rsa</span><br />
<span style="font-size: 13px">./build-key-server server</span></p>
</blockquote>
<p><font color="#3333ff"><span style="font-size: 13px"><br />
</span><span style="font-size: 13px">Country Name (2 letter code) [KG]:<br />
State or Province Name (full name) [NA]:<br />
Locality Name (eg, city) [BISHKEK]:<br />
Organization Name (eg, company) [OpenVPN-TEST]:yourcorp 输入公司名<br />
Organizational Unit Name (eg, section) []:<br />
Common Name (eg, your name or your server's hostname) []:hbrouteserver 输入主机名或随便一个名字<br />
Email Address [me@myhost.mydomain]:</span></font></p>
<p><font color="#3333ff">Please enter the following 'extra' attributes<br />
to be sent with your certificate request<br />
A challenge password []:<br />
An optional company name []:</font></p>
<p><font color="#3333ff">Sign the certificate? [y/n]:y 输入y</font></p>
<p><font color="#3333ff">1 out of 1 certificate requests certified, commit? [y/n]y 输入y<br />
Write out database with 1 new entries<br />
Data Base Updated<br />
其它的按回车。</font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">4.5.1.3 创建3个client端cert和key文件<br />
与创建server端的非常相似.</span></p>
<blockquote>
<p><span style="font-size: 13px">./build-key gz</span><br />
<span style="font-size: 13px">./build-key hb</span><br />
<span style="font-size: 13px">./build-key hz</span><br />
<span style="font-size: 13px"></p>
</blockquote>
<p><span style="font-size: 13px"><br />
注意gz、hb和hz不能一样，否则两个相同名字的client只能有一个能连接进来。<br />
如果想使用带密码的client key，可以使用build-key-pass脚本。</span></p>
<p>如建立广州的：</p>
<p><font color="#3333ff"><span style="font-size: 13px">./build-key gz<br />
Country Name (2 letter code) [KG]:<br />
State or Province Name (full name) [NA]:<br />
Locality Name (eg, city) [BISHKEK]:<br />
Organization Name (eg, company) [OpenVPN-TEST]:mycorp<br />
Organizational Unit Name (eg, section) []:<br />
Common Name (eg, your name or your server's hostname) []:gz 键入"gz"<br />
Email Address [me@myhost.mydomain]:</span></font></p>
<p><font color="#3333ff">Certificate is to be certified until Mar 14 08:15:16 2015 GMT (3650 days)<br />
Sign the certificate? [y/n]:y 键入&#8220;y&#8221;</font></p>
<p><font color="#3333ff">1 out of 1 certificate requests certified, commit? [y/n]y 键入&#8220;y&#8221;<br />
Write out database with 1 new entries<br />
Data Base Updated<br />
</font><span style="font-size: 13px"><font color="#3333ff"><br />
</font></span><span style="font-size: 13px">4.5.1.4 建立 Diffie Hellman文件<br />
Diffie Hellman参数必须要在openvpn server中使用。</span></p>
<p>./build-dh</p>
<p>4.5.1.5 所有文件的列表及使用的主机</p>
<p><font color="#3333ff"><span style="font-size: 13px"><font color="#cc6600"><strong>Filename Needed By Purpose Secret</strong></font><br />
ca.crt server + all clients Root CA certificate NO<br />
ca.key key signing machine only Root CA key YES<br />
Dh{n}.pem server only Diffie Hellman parameters NO<br />
server.crt server only Server Certificate NO<br />
server.key server only Server Key YES<br />
gz.crt 广州 only gz Certificate NO<br />
Gz.key 广州 only gz Key YES<br />
hcrt 河北 only hb Certificate NO<br />
hb.key 河北 only hb Key YES<br />
hz.crt 杭州 only hz Certificate NO<br />
hz.key 杭州 only hz Key YES</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">根据上表，将所有的文件拷贝到需要这些文件的主机上。</span></p>
<p>4.5.2 OpenVPN Server端的配置<br />
刚安装完openvpn的时候，/opt/openvpn目录下只有sbin和man两个文件夹，为方便起见，我们可以在该目录下建立其它的文件夹。</p>
<p><font color="#3333ff"><span style="font-size: 13px">目录名 作用<br />
Sbin 放置openvpn的主程序&#8220;openvpn&#8221;<br />
Conf 放置配置文件<br />
Ccd 放置各client的独立配置文件<br />
Log 放置server的日志文件<br />
Keys 放置认证文件<br />
Man 放置man文档</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">配置文件：./conf/server.conf</span><br />
<font color="#3333ff"><span style="font-size: 13px"><br />
</span><span style="font-size: 13px">port 1194<br />
proto udp<br />
dev tun<br />
ca /opt/openvpn/keys/ca.crt<br />
cert /opt/openvpn/keys/server.crt<br />
key /opt/openvpn/keys/server.key<br />
dh /opt/openvpn/keys/dh1024.pem<br />
server 10.99.0.0 255.255.255.0<br />
ifconfig-pool-persist /opt/openvpn/log/ipp.txt<br />
client-config-dir ccd<br />
route 10.1.0.0 255.255.0.0<br />
route 10.2.0.0 255.255.0.0<br />
route 10.3.0 255.255.0.0<br />
push "route 10.10.0 255.255.0.0"<br />
push "route 10.2.0.0 255.255.0.0"<br />
push "route 10.3.0.0 255.255.0.0"<br />
client-to-client<br />
keepalive 10 120<br />
comp-lzo<br />
user nobody<br />
group nobody<br />
persist-key<br />
persist-tun<br />
status /opt/openvpn/log/openvpn-status.log<br />
log /opt/openvpn/log/openvpn.log<br />
verb 6<br />
mute 20<br />
writepid /opt/openvpn/log/server.pid</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">Client的自定义配置：./ccd/<br />
<font color="#3333ff"><br />
</font></span><font color="#3333ff"><span style="font-size: 13px">gz:<br />
iroute 10.1.0.0 255.255.0.0</span></font></p>
<p><font color="#3333ff">hz:<br />
iroute 10.3.0.0 255.255.0.0</font></p>
<p><font color="#3333ff">hb:<br />
iroute 10.2.0.0 255.255.0.0</font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">配置文件解释：</span><br />
<span style="font-size: 13px"><br />
</span><font color="#3333ff"><span style="font-size: 13px">;local a,b,c,d listen的IP<br />
port 1194 listen的端口<br />
proto udp 使用UDP协议<br />
dev tun 使用tunnel的模块</span></font></p>
<p><font color="#3333ff">ca ca.crt 公钥（s端和c端使用相同的ca）<br />
cert server.crt server的公钥<br />
key server.key server的私钥（要保管好）（s端和c端使用各自的cert和key）<br />
dh dh1024.pem 产生方法：openssl dhparam -out dh1024.pem 1024</font></p>
<p><font color="#3333ff">server 10.99.0.0 255.255.255.0 设置为server模式，并指定子网的IP段，server端默认会设为.1的地址。<br />
ifconfig-pool-persist ipp.txt 当vpn断开或重启后，可以利用该文件重新建立相同IP地址的连接。<br />
push "route 10.1.0.0 255.255.0.0" 让client端建立到另一个子网的路由。</font></p>
<p><font color="#3333ff">client-to-client 让不同的client之间可以互相&#8220;看到&#8221;。<br />
;max-clients 100 最多的client数量。</font></p>
<p><font color="#3333ff">keepalive 10 120 每10秒ping一次，如果120秒没有回应则认为对方已经down。</font></p>
<p><font color="#3333ff">user nobody<br />
group nobody 指定运行openvpn的用户和组。（减少危险）。</font></p>
<p><font color="#3333ff">persist-key<br />
persist-tun</font></p>
<p><font color="#3333ff">status openvpn-status.log 每分钟记录一次连接的状态。</font></p>
<p><font color="#3333ff">log openvpn.log 将log记录到指定文件中</font></p>
<p><font color="#3333ff">verb 3 设置日志要记录的级别。<br />
0只记录错误信息。<br />
4能记录普通的信息。<br />
5和6在连接出现问题时能帮助调试<br />
9是极端的，所有信息都会显示，甚至连包头等信息都显示（像tcpdump）</font></p>
<p><font color="#3333ff">mute 20 相同信息的数量，如果连续出现20条相同的信息，将不记录到日志中。</font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">4.5.3 OpenVPN Client端的配置</span></p>
<p><font color="#3333ff"><span style="font-size: 13px">目录名 作用<br />
Sbin 放置openvpn的主程序&#8220;openvpn&#8221;<br />
Conf 放置配置文件<br />
Keys 放置认证文件<br />
Man 放置man文档</span><br />
</font><span style="font-size: 13px"><br />
</span><span style="font-size: 13px">配置文件：./conf/client.conf<br />
广州：</span><br />
<font color="#3333ff"><span style="font-size: 13px">Client<br />
dev tun<br />
proto udp<br />
remote VPNSERVERIP11194<br />
resolv-retry infinite<br />
nobind<br />
user nobody<br />
group nobody<br />
persist-key<br />
persist-tun<br />
ca /opt/openvpn/keys/ca.crt<br />
cert /opt/openvpn/keys/gz.crt<br />
key /opt/openvpn/keys/gz.key<br />
comp-lzo<br />
verb 3<br />
mute 20</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">杭州：</span><br />
<font color="#3333ff"><span style="font-size: 13px">client<br />
dev tun<br />
proto udp<br />
remote VPNSERVERIP1 1194<br />
resolv-retry infinite<br />
nobind<br />
user nobody<br />
group nobody<br />
persist-key<br />
persist-tun<br />
ca /opt/openvpn/keys/ca.crt<br />
cert /opt/openvpn/keys/hz.crt<br />
key /opt/openvpn/keys/hz.key<br />
comp-lzo<br />
verb 3<br />
mute 20</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">河北：</span><br />
<font color="#3333ff"><span style="font-size: 13px">client<br />
dev tun<br />
proto udp<br />
remote VPNSERVERIP2 1194<br />
resolv-retry infinite<br />
nobind<br />
user nobody<br />
group nobody<br />
persist-key<br />
persist-tun<br />
ca /opt/openvpn/keys/ca.crt<br />
cert /opt/openvpn/keys/hb.crt<br />
key /opt/openvpn/keys/hb.key<br />
comp-lzo<br />
verb 3<br />
mute 20</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">4.5.4 运行OpenVPN<br />
建立脚本：<br />
Server端：</span><br />
<font color="#3333ff"><span style="font-size: 13px">#!/bin/sh<br />
OPENVPN=/opt/openvpn/sbin/openvpn<br />
CFG=/opt/openvpn/conf/server.conf<br />
PID=`cat /opt/openvpn/log/server.pid`<br />
case "$1" in<br />
start)<br />
$OPENVPN --config $CFG &amp;<br />
;;<br />
stop)<br />
kill $PID<br />
;;<br />
restart)<br />
kill $PID<br />
sleep 5<br />
$OPENVPN --config $CFG &amp;<br />
;;<br />
*)<br />
echo "Usage: `basename $0` {start|stop|restart}"<br />
;;<br />
esac</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">Client端:</span><br />
<font color="#3333ff"><span style="font-size: 13px">#!/bin/sh<br />
/opt/openvpn/sbin/openvpn --config /opt/openvpn/conf/client.conf &amp;</span></font><br />
<span style="font-size: 13px"></p>
<p><span style="font-size: 13px"><big><strong>5 其它配置</strong></big><br />
5.1 让多个client的子网间互通<br />
●client-config-dir ccd<br />
添加一个ccd的文件夹，里面的文件名为client的名字（如gz，hb）。当一个新client连接到server上时，程序会检查ccd文件夹，看 是否有一个文件的名字与client的名字一致。如果有，进程会读该文件里面的指令并将这些指令应用于该名字的client。</span></p>
<p>●在ccd文件夹中创建一个文件hz，该文件中包括：<br />
iroute 10.3.0.0 255.255.0.0 这会告诉hz client，不要在本机添加10.3.0.0网段（因为杭州本来就是10.23/16网段）。</p>
<p>●在server的配置文件中加入：<br />
route 10.3.0.0 255.255.0.0</p>
<p>如果想两个client可以互通，请在server的配置文件中加入：<br />
client-to-client<br />
push "route 10.3.0.0 255.255.0.0"</p>
<p>记得在各子网内的机器上设置路由（如果server和client机器不是作为默认网关的话）。</p>
<p>5.2 控制运行中的openvpn进程<br />
在配置文件中加入writepid参数指定pid文件。<br />
SIGUSR1--以非root的身份重启openvpn进程。<br />
SIGHUP--重启<br />
SIGUSR2--输出连接统计到log文件<br />
SIGTERM,SIGINT--exit。</p>
<p>5.3 windows下的配置：<br />
windows版本的openvpn下载地址：<br />
http://nchc.dl.sourceforge.net/sourceforge/openvpn/openvpn-2.0_rc17-install.exe</p>
<p>安装方法很简单，和其它windows下的软件无异。<br />
我安装到c:\program file\openvpn下。<br />
在config中建立配置文件win.ovpn<br />
<font color="#3333ff"><span style="font-size: 13px">Client<br />
dev tun<br />
proto udp<br />
remote VPNSERVER1 1194<br />
resolv-retry infinite<br />
nobind<br />
persist-key<br />
persist-tun<br />
ca ../keys/ca.crt<br />
cert ../keys/win.crt<br />
key ../keys/win.key<br />
comp-lzo<br />
verb 3<br />
mute 20</span></font><br />
<span style="font-size: 13px"><br />
</span><span style="font-size: 13px">从server中生成ca.crt ,win.crt,win.key文件并拷贝到windows上。生成文件的方法请参考章节5.5.1.3。<br />
在命令行运行：<br />
openvpn --config win.ovpn</span></p>
<p>如果要将openvpn做成服务，运行：<br />
openvpnsev.exe -install<br />
这样就可以在服务中找到openvpn服务了。<br />
当openvpn作为服务时，会到config文件夹寻找ovpn后缀的配置文件。生成的日志会放在log文件夹中。</p>
<p><strong>6 实际应用情况</strong></p>
<p>从实际应用的情况看，VPN采用的加密的方式并没有影响到数据传输的速度，从流量图中可以看出，流量最大可以达到14Mbits/s（电信的线路只有10Mbits/s）。</p>
<p><img height="386" src="http://www.joecen.com/images/openvpn_traffic.jpg" width="591"  alt="" /></p>
<p><strong>7 参考文档</strong><br />
OpenVPN Howto(2.0) <a href="http://openvpn.net/howto.html" target="_blank">http://openvpn.net/howto.html</a><br />
OpenVPN Install <a href="http://openvpn.net/install.html" target="_blank">http://openvpn.net/install.html</a><br />
OpenVPN Install(Win32) <a href="http://openvpn.net/INSTALL-win32.html" target="_blank">http://openvpn.net/INSTALL-win32.html</a><br />
OpenVPN Man Pages <a href="http://openvpn.net/man.html" target="_blank">http://openvpn.net/man.html</a><br />
OpenVPN FAQ <a href="http://openvpn.net/faq.html" target="_blank">http://openvpn.net/faq.html</a><br />
<span style="font-size: 13px"></p>
<br />
<!-- You can start editing here. --><!-- If comments are open, but there are no comments. --></span></span></span></font>
<img src ="http://www.blogjava.net/tinysun/aggbug/267118.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-04-23 12:38 <a href="http://www.blogjava.net/tinysun/archive/2009/04/23/267118.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>整数除法(转)</title><link>http://www.blogjava.net/tinysun/archive/2009/04/12/265134.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sun, 12 Apr 2009 08:30:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/04/12/265134.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/265134.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/04/12/265134.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/265134.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/265134.html</trackback:ping><description><![CDATA[<a href="http://www.china-pub.com/computers/common/info.asp?id=18801" target="_blank">《高效程序的奥秘》</a>(Henry S.Warren,Jr.著)第9章&#8220;整数除法&#8221;中说：<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 除法运算是一个复杂的过程，含有除法的算法通常都不很精巧。甚至连如何定义整数除法都是一个值得研究的问题。大多数高级语言和大多数计算指令集将其定义为有理数结果的向零截取。这一定义以及其他两种可能的定义叙述如下：<br />
<pre>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> --------- ---截取-- ---模--- --地板--<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 /&nbsp;<wbr> 3 =&nbsp;<wbr> 2 余&nbsp;<wbr> 1&nbsp;<wbr>&nbsp;<wbr> 2 余 1&nbsp;<wbr>&nbsp;<wbr> 2 余&nbsp;<wbr> 1<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> -7 /&nbsp;<wbr> 3 = -2 余 -1&nbsp;<wbr> -3 余 2&nbsp;<wbr> -3 余&nbsp;<wbr> 2<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 / -3 = -2 余&nbsp;<wbr> 1&nbsp;<wbr> -2 余 1&nbsp;<wbr> -3 余 -2<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> -7 / -3 =&nbsp;<wbr> 2 余 -1&nbsp;<wbr>&nbsp;<wbr> 3 余 2&nbsp;<wbr>&nbsp;<wbr> 2 余 -1<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> --------- --------- -------- --------</pre>
<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 对于所有三种可能的定义，关系&#8220;被除数＝商&#215;除数＋余数&#8221;都成立。在定义&#8220;模&#8221;(modulus)除法时，要求余数是非负数。在定义&#8220;地板&#8221;(floor)除法时，要求商是有理数除法的结果的&#8220;地板&#8221;。对于除数是正的情况，模除法和地板除法等价。很少使用的第四种可能定义是向最接近的整数舍入。<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 所以，&#8220;装配脑袋&#8221;所说的&#8220;数学上规定&#8221;实际上是指&#8220;地板&#8221;除法。而现有的高级语言(如C、C++、C#、Java、Fortran、Ada、Pascal等)大多数都使用&#8220;截取&#8221;除法，IBM的PL.8语言使用&#8220;模&#8221;除法，Knuth的MMIX计算机的除指令使用&#8220;地板&#8221;除法。
<div>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> <a href="http://msdn2.microsoft.com/zh-cn/library/ms228593.aspx" target="_blank">[C#语言规范 7.7.2]</a>中说：(整数)除法将结果舍入到零，并且结果的绝对值是小于两个操作数的商的绝对值的最大可能整数。当两个操作数符号相同时，结果为零或正；当两个操作数符号相反时，结果为零或负。</div>
<img src ="http://www.blogjava.net/tinysun/aggbug/265134.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-04-12 16:30 <a href="http://www.blogjava.net/tinysun/archive/2009/04/12/265134.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个不错的轻量级UML建模工具</title><link>http://www.blogjava.net/tinysun/archive/2009/03/03/257647.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Tue, 03 Mar 2009 12:08:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/03/03/257647.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/257647.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/03/03/257647.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/257647.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/257647.html</trackback:ping><description><![CDATA[<p>用Violet UML 画的类图：<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/tinysun/uml.JPG" border="0" /><br />
效果还不错，简单易用。</p>
 <img src ="http://www.blogjava.net/tinysun/aggbug/257647.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-03-03 20:08 <a href="http://www.blogjava.net/tinysun/archive/2009/03/03/257647.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>