<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Thinking In Linux</title>
	<atom:link href="http://www.linuxsong.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.linuxsong.org</link>
	<description>KISS-Keep It Simple, Stupid!</description>
	<lastBuildDate>Wed, 16 Nov 2011 07:18:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Linux下配置rdate时间服务器</title>
		<link>http://www.linuxsong.org/2011/11/time-server/</link>
		<comments>http://www.linuxsong.org/2011/11/time-server/#comments</comments>
		<pubDate>Wed, 16 Nov 2011 07:18:32 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=481</guid>
		<description><![CDATA[配置多台服务器时，经常需要让各个服务器之间的时间保持同步，如果服务器有外网环境，可以直接同外部的时间服务器更新时间，可以采用rdate命令更新时间. <a href="http://www.linuxsong.org/2011/11/time-server/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>配置多台服务器时，经常需要让各个服务器之间的时间保持同步，如果服务器有外网环境，可以直接同外部的时间服务器更新时间，可以采用rdate命令更新时间:</p>
<p>rdate -s ﻿tick.greyware.com</p>
<p>可以写个脚本放在/etc/cron.hourly中每小时校正一下时间。</p>
<p>如果是内网环境下，可以自己配置一个时间服务器，以CentOS为例，配置时间服务器的方法如下：</p>
<p>1.先安装xinetd : sudo yum install -y xinetd</p>
<p>2.修改/etc/xinetd.d/time-stream, 修改：</p>
<p>disable     = yes  改为</p>
<p>disable = no</p>
<p>3.启动xinetd</p>
<p>service xinetd start</p>
<p>这样其它机器就可以通过rdate 与该机器进行时间同步</p>
<p>rdate -s ip</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2011/11/time-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux下常用文本处理命令</title>
		<link>http://www.linuxsong.org/2011/07/linux-text-tool/</link>
		<comments>http://www.linuxsong.org/2011/07/linux-text-tool/#comments</comments>
		<pubDate>Thu, 07 Jul 2011 07:13:57 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=475</guid>
		<description><![CDATA[Linux下面有很多经典的非常有用的命令，其中处理文本的命令就有很多。这些小工具经过了几十年时间的洗礼，现在已经变成了经典，已经变成了Linux下面的标准，其实它们一直是遵循着Linux的标准。下面就让我们一起看看这些经典的Linux文本处理命令。 <a href="http://www.linuxsong.org/2011/07/linux-text-tool/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.linuxsong.org/category/linux/">Linux</a>下面有很多经典的非常有用的命令，其中处理文本的命令就有很多。这些小工具经过了几十年时间的洗礼，现在已经变成了经典，已经变成了Linux下面的标准，其实它们一直是遵循着Linux的标准。下面就让我们一起看看这些经典的Linux文本处理命令。</p>
<h3>一. sort</h3>
<p>文件排序, 通常用在管道中当过滤器来使用. 这个命令可以依据指定的关键字或指定的字符位置, 对文件行进行排序. 使用-m选项, 它将会合并预排序的输入文件. 想了解这个命令的全部参数请参考这个命令的info页.</p>
<p><span id="more-475"></span></p>
<h3>二. tsort</h3>
<p>拓扑排序, 读取以空格分隔的有序对, 并且依靠输入模式进行排序.</p>
<h3>三. uniq</h3>
<p>这个过滤器将会删除一个已排序文件中的重复行. 这个命令经常出现在sort命令的管道后边.</p>
<h3>四. expand, unexpand</h3>
<p>expand命令将会把每个tab转化为一个空格. 这个命令经常用在管道中.</p>
<p>unexpand命令将会把每个空格转化为一个tab. 效果与expand命令相反.</p>
<h3>五. cut</h3>
<p>一个从文件中提取特定域的工具. 这个命令与awk中使用的print $N命令很相似, 但是更受限. 在脚本中使用cut命令会比使用awk命令来得容易一些. 最重要的选项就是-d(字段定界符)和-f(域分隔符)选项.</p>
<h3>六. paste</h3>
<p>将多个文件, 以每个文件一列的形式合并到一个文件中, 合并后文件中的每一列就是原来的一个文件. 与cut结合使用, 经常用于创建系统log文件.</p>
<h3>七. join</h3>
<p>这个命令与paste命令属于同类命令. 但是它能够完成某些特殊的目地. 这个强力工具能够以一种特殊的形式来合并两个文件, 这种特殊的形式本质上就是一个关联数据库的简单版本.</p>
<p>join命令只能够操作两个文件. 它可以将那些具有特定标记域(通常是一个数字标签)的行合并起来, 并且将结果输出到stdout. 被加入的文件应该事先根据标记域进行排序以便于能够正确的匹配.</p>
<h3>八. head</h3>
<p>把文件的头部内容打印到stdout上(默认为10行, 可以自己修改). 这个命令有一些比较有趣的选项.</p>
<h3>九. tail</h3>
<p>将一个文件结尾部分的内容输出到stdout中(默认为10行). 通常用来跟踪一个系统logfile的修改情况, 如果使用-f选项的话, 这个命令将会继续显示添加到文件中的行.</p>
<h3>十. wc</h3>
<p>wc可以统计文件或I/O流中的&quot;单词数量&quot;:</p>
<h3>十一. fold</h3>
<p>将输入按照指定宽度进行折行. 这里有一个非常有用的选项-s, 这个选项可以使用空格进行断行(译者: 事实上只有外文才需要使用空格断行, 中文是不需要的)(请参考例子 12-23和例子 A-1).</p>
<h3>十二. fmt</h3>
<p>一个简单的文件格式器, 通常用在管道中, 将一个比较长的文本行输出进行&quot;折行&quot;.</p>
<h3>十三. col</h3>
<p>这个命令用来滤除标准输入的反向换行符号. 这个工具还可以将空白用等价的tab来替换. col工具最主要的应用还是从特定的文本处理工具中过滤输出, 比如groff和tbl. (译者: 主要用来将man页转化为文本.)</p>
<h3>十四. column</h3>
<p>列格式化工具. 通过在合适的位置插入tab, 这个过滤工具会将列类型的文本转化为&quot;易于打印&quot;的表格式进行输出.</p>
<h3>十五. colrm</h3>
<p>列删除过滤器. 这个工具将会从文件中删除指定的列(列中的字符串)并且写到文件中, 如果指定的列不存在, 那么就回到stdout. colrm 2 4 &lt;filename将会删除filename文件中每行的第2到第4列之间的所有字符.</p>
<p>Caution: 如果这个文件包含tab和不可打印字符, 那将会引起不可预期的行为. 在这种情况下, 应该通过管道的手段使用expand和unexpand来预处理colrm.</p>
<h3>十六. nl</h3>
<p>计算行号过滤器. nl filename将会把filename文件的所有内容都输出到stdout上, 但是会在每个非空行的前面加上连续的行号. 如果没有filename参数, 那么就操作stdin.</p>
<p>nl命令的输出与cat -n非常相似, 然而, 默认情况下nl不会列出空行.</p>
<h3>十七. pr</h3>
<p>格式化打印过滤器. 这个命令会将文件(或stdout)分页, 将它们分成合适的小块以便于硬拷贝打印或者在屏幕上浏览. 使用这个命令的不同的参数可以完成好多任务, 比如对行和列的操作, 加入行, 设置页边, 计算行号, 添加页眉, 合并文件等等. pr命令集合了许多命令的功能, 比如nl, paste, fold, column, 和expand.</p>
<p>pr -o 5 --width=65 fileZZZ | more 这个命令对fileZZZ进行了比较好的分页, 并且打印到屏幕上. 文件的缩进被设置为5, 总宽度设置为65.</p>
<p>一个非常有用的选项-d, 强制隔行打印(与sed -G效果相同).</p>
<h3>十八. gettext</h3>
<p>GNU gettext包是专门用来将程序的输出翻译或者本地化为不同国家语言的工具集. 在最开始的时候仅仅支持C语言, 现在已经支持了相当数量的其它程序语言和脚本语言.</p>
<p>想要查看gettext程序如何在shell脚本中使用. 请参考info页.</p>
<h3>十九. msgfmt</h3>
<p>一个产生二进制消息目录的程序. 这个命令主要用来本地化.</p>
<h3>二十. iconv</h3>
<p>一个可以将文件转化为不同编码格式(字符集)的工具. 这个命令主要用来本地化.</p>
<h3>二十一. recode</h3>
<p>可以认为这个命令是上边iconv命令的专业版本. 这个非常灵活的并可以把整个文件都转换为不同编码格式的工具并不是Linux标准安装的一部分.</p>
<h3>二十二. TeX, gs</h3>
<p>TeX和Postscript都是文本标记语言, 用来对打印和格式化的视频显示进行预拷贝.</p>
<p>TeX是Donald Knuth精心制作的排版系统. 通常情况下, 通过编写脚本的手段来把所有的选项和参数封装起来一起传到标记语言中是一件很方便的事情.</p>
<p>Ghostscript (gs) 是一个 遵循GPL的Postscript解释器.</p>
<h3>二十三. enscript</h3>
<p>将纯文本文件转换为PostScript的工具</p>
<p>比如, enscript filename.txt -p filename.ps 产生一个 PostScript 输出文件filename.ps.</p>
<h3>二十四. groff, tbl, eqn</h3>
<p>另一种文本标记和显示格式化语言是groff. 这是一个对传统UNIX roff/troff显示和排版包的GNU增强版本. Man页使用的就是groff.</p>
<p>tbl表处理工具可以认为是groff的一部分, 它的功能就是将表标记转化到groff命令中.</p>
<p>eqn等式处理工具也是groff的一部分, 它的功能是将等式标记转化到groff命令中.</p>
<h3>二十五. lex, yacc</h3>
<p>lex是用于模式匹配的词汇分析产生程序. 在Linux系统上这个命令已经被flex取代了.</p>
<p>yacc工具基于一系列的语法规范, 产生一个语法分析器. 在Linux系统上这个命令已经被bison取代了.</p>
<h3>二十六. tr</h3>
<p>字符转换过滤器.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2011/07/linux-text-tool/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>【分布式系统工程实现】如何检测一台机器是否宕机？</title>
		<link>http://www.linuxsong.org/2011/02/check_system_down/</link>
		<comments>http://www.linuxsong.org/2011/02/check_system_down/#comments</comments>
		<pubDate>Tue, 22 Feb 2011 03:17:24 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=473</guid>
		<description><![CDATA[检测一台机器是否宕机的应用场景如下：

1, 工作机器宕机，总控节点需要能够检测到并且将原有服务迁移到集群中的其它节点。

2, 总控节点宕机，总控节点的备份节点（一般称为Slave）需要能够检测到并替换成主节点继续对外服务。 <a href="http://www.linuxsong.org/2011/02/check_system_down/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>原文地址： <a href="http://rdc.taobao.com/blog/cs/?p=708" target="_blank">http://rdc.taobao.com/blog/cs/?p=708</a></p>
<p>检测一台机器是否宕机的应用场景如下：</p>
<p>1, 工作机器宕机，总控节点需要能够检测到并且将原有服务迁移到集群中的其它节点。</p>
<p>2, 总控节点宕机，总控节点的备份节点（一般称为Slave）需要能够检测到并替换成主节点继续对外服务。</p>
<p>检测一台机器是否宕机必须是可靠的。在大规模集群中，机器可能出现各种异常，比如停电，磁盘故障，过于繁忙导致假死等。对于机器假死，如果总控节点认为机器宕机并将服务迁移到其它节点，假死的机器又认为自己还可以提供服务，则会出现多个节点服务同一份数据而导致数据不一致的情况。</p>
<p><span id="more-473"></span>首先必须明确，理论上检测另外一台机器是否宕机是无法做到的，有兴趣的同学可以参考<a href="http://courses.ece.illinois.edu/ece428/papers/flp_JACM85.pdf">Fischer的论文</a>。可以简单理解如下：A机器往B机器发送心跳包，如果B机器不发送响应，A无法确定B机器是宕机了还是过于繁忙，由于A和B两台机器的时钟可能不同步，B机器也无法确定多久没有收到A机器的心跳包可以认为必须停止服务。因此，A机器没有办法确定B机器已经宕机或者采取措施强制B机器停止服务。</p>
<p>当然，工程实践中，由于机器之间会进行时钟同步，我们总是假设A和B两台机器的本地时钟相差不大，比如相差不超过0.5秒。这样，我们可以通过Lease机制进行宕机检测。Lease机制就是带有超时时间的一种授权。假设总控节点需要检测工作节点是否宕机，总控节点可以给工作节点发放Lease授权，工作节点持有有效期内的Lease才允许提供服务，否则主动下线停止服务。工作节点的Lease快要到期的时候向总控节点重新申请Lease（一般称为renewLease），总控节点定时检测所有工作机的Lease授权是否合法，如果发现某台工作机Lease失效，可以将工作机上的服务迁移到集群中的其它机器，这时因为工作机发现自己Lease失效会主动停止服务。当然，这里需要注意，由于总控节点和工作机的时钟可能不一致且有网络延迟，总控节点上的Lease超时时间要长，也就是说，如果工作节点的Lease超时时间是12秒，总控节点可能需要13秒后才能确认工作节点已经停止了服务，从而避免数据不一致问题。</p>
<p>同构节点之间的选主也有一个宕机检测问题。比如总控节点宕机，备份节点需要能够检测并升级为主节点继续对外服务。<a title="Mysql" href="http://www.linuxsong.org/tag/mysql/">Mysql</a>数据库经常采用Heartbeat + DRBD (Distributed Replicated Block Device) + Mysql的高可用性方案，据说能够达到3个9的高可用性，主节点和备节点维持Heartbeat心跳，当提供服务的主节点出现故障时，备节点的Heartbeat检测到主节点没有心跳（例如，Ping不通主节点），备节点自动接管虚拟IP，升级为主节点提供Mysql读写服务。由于Heartbeat检测机器主节点宕机不可靠，这个方案存在众所周知的脑裂问题，即集群中可能同时存在多个主节点同时提供服务。解决这个问题本质上还是需要引入仲裁节点，比如Heartbeat + DRBD方案中引入Fence节点使出现问题的节点从集群中脱离，或者引入分布式锁服务，比如Chubby的开源实现Zookeeper服务。分布式锁服务实现主节点选举大致如下：主节点和备节点到Chubby中抢锁，抢到锁的节点在锁的有效期(Lease期)内提供服务，当主节点锁的Lease快要到期时，主节点申请延长锁的超时时间，正常情况下分布式锁服务总是优先满足主节点的请求，当主节点出现故障时，备节点能够抢到锁切换为主节点提供服务。</p>
<p>最后还有一个问题，假设总控节点通过Lease机制检测工作节点是否宕机，这种方案是可靠的，不过当总控节点宕机时，如果不采取任何措施，集群中的所有工作节点都将因为无法重新申请Lease而停止服务，这就是带有总控节点的设计固有的脆弱性，某个设计或者编码的错误都有可能造成严重的影响。解决这个问题一般会有一个叫做Grace Period的机制，工作节点Lease超时时将停止服务，但是工作节点并不一开始就重启或者下线，而是处于一种危险状态(称为Jeopardy)，这种状态持续一个Grace Period，比如45秒。如果在Grace Period 内总控节点重启，工作节点和总控节点重新联系上从而可以切换为正常状态继续提供服务。</p>
<p>如果需要较好地理解宕机及选举相关的问题，可以阅读并思考Paxos相关的论文，比如Paxos made simple, The Part-time Parliament, Paxos made live, Paxos made practical, Chubby等。有任何问题，欢迎讨论。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2011/02/check_system_down/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>linux 技巧：使用 screen 管理你的远程会话</title>
		<link>http://www.linuxsong.org/2011/01/linux-scree/</link>
		<comments>http://www.linuxsong.org/2011/01/linux-scree/#comments</comments>
		<pubDate>Thu, 13 Jan 2011 16:35:47 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=465</guid>
		<description><![CDATA[你是不是经常需要 SSH 或者 telent 远程登录到 Linux 服务器？你是不是经常为一些长时间运行的任务而头疼，比如系统备份、ftp 传输等等。通常情况下我们都是为每一个这样的任务开一个远程终端窗口，因为他们执行的时间太长了。必须等待它执行完毕，在此期间可不能关掉窗口或者断开连接，否则这个任务就会被杀掉，一切半途而废了。 <a href="http://www.linuxsong.org/2011/01/linux-scree/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>你是不是经常需要 SSH 或者 telent 远程登录到 <a title="linux" href="http://www.linuxsong.org/category/linux/">Linux</a> 服务器？你是不是经常为一些长时间运行的任务而头疼，比如系统备份、ftp 传输等等。通常情况下我们都是为每一个这样的任务开一个远程终端窗口，因为他们执行的时间太长了。必须等待它执行完毕，在此期间可不能关掉窗口或者断开连接，否则这个任务就会被杀掉，一切半途而废了。</p>
<p><span id="more-465"></span>让我们来看看为什么关掉窗口/断开连接会使得正在运行的程序死掉。</p>
<p>在Linux/Unix中，有这样几个概念：</p>
<ul>
<li>进程组（process group）：一个或多个进程的集合，每一个进程组有唯一一个进程组ID，即进程组长进程的ID。</li>
<li>会话期（session）：一个或多个进程组的集合，有唯一一个会话期首进程（session leader）。会话期ID为首进程的ID。</li>
<li>会话期可以有一个单独的控制终端（controlling terminal）。与控制终端连接的会话期首进程叫做控制进程（controlling process）。当前与终端交互的进程称为前台进程组。其余进程组称为后台进程组。</li>
</ul>
<p>根据POSIX.1定义：</p>
<ul>
<li>挂断信号（SIGHUP）默认的动作是终止程序。</li>
<li>当终端接口检测到网络连接断开，将挂断信号发送给控制进程（会话期首进程）。</li>
<li>如果会话期首进程终止，则该信号发送到该会话期前台进程组。</li>
<li>一个进程退出导致一个孤儿进程组中产生时，如果任意一个孤儿进程组进程处于STOP状态，发送SIGHUP和SIGCONT信号到该进程组中所有进程。</li>
</ul>
<p>因此当网络断开或终端窗口关闭后，控制进程收到SIGHUP信号退出，会导致该会话期内其他进程退出。</p>
<p>我们来看一个例子。打开两个SSH终端窗口，在其中一个运行top命令。</p>
<pre>[root@tivf09 root]# top</pre>
<p>在另一个终端窗口，找到top的进程ID为5180，其父进程ID为5128，即登录shell。</p>
<pre class="displaycode">[root@tivf09 root]# ps -ef|grep top
root      5180  5128  0 01:03 pts/0    00:00:02 top
root      5857  3672  0 01:12 pts/2    00:00:00 grep top</pre>
<p>使用pstree命令可以更清楚地看到这个关系：</p>
<pre class="displaycode">[root@tivf09 root]# pstree -H 5180|grep top
|-<strong>sshd-+-sshd---bash---top</strong></pre>
<p>使用ps-xj命令可以看到，登录shell（PID 5128）和top在同一个会话期，shell为会话期首进程，所在进程组PGID为5128，top所在进程组PGID为5180，为前台进程组。</p>
<pre class="displaycode">[root@tivf09 root]# ps -xj|grep 5128
 5126  5128  5128  5128 pts/0     5180 S        0   0:00 -bash
 5128  5180  5180  5128 pts/0     5180 S        0   0:50 top
 3672 18095 18094  3672 pts/2    18094 S        0   0:00 grep 5128</pre>
<p>关闭第一个SSH窗口，在另一个窗口中可以看到top也被杀掉了。</p>
<pre class="displaycode">[root@tivf09 root]# ps -ef|grep 5128
root     18699  3672  0 04:35 pts/2    00:00:00 grep 5128</pre>
<p>如果我们可以忽略SIGHUP信号，关掉窗口应该就不会影响程序的运行了。nohup命令可以达到这个目的，如果程序的标准输出/标准错误是终端，nohup默认将其重定向到nohup.out文件。值得注意的是nohup命令只是使得程序忽略SIGHUP信号，还需要使用标记<strong>&amp;</strong>把它放在后台运行。</p>
<pre class="displaycode">nohup &lt;command&gt; [argument…] &amp;</pre>
<p>虽然nohup很容易使用，但还是比较“简陋”的，对于简单的命令能够应付过来，对于复杂的需要人机交互的任务就麻烦了。</p>
<p>其实我们可以使用一个更为强大的实用程序screen。流行的Linux发行版（例如Red Hat Enterprise Linux 4）通常会自带screen实用程序，如果没有的话，可以从GNU screen的官方网站下载。</p>
<pre class="displaycode">[root@tivf06 ~]# rpm -qa|grep screen
xscreensaver-4.18-5.rhel4.11</pre>
<p>简单来说，Screen是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。Screen中有会话的概念，用户可以在一个screen会话中创建多个screen窗口，在每一个screen窗口中就像操作一个真实的telnet/SSH连接窗口那样。在screen中创建一个新的窗口有这样几种方式：</p>
<p>1．直接在命令行键入screen命令</p>
<pre class="displaycode">[root@tivf06 ~]# screen</pre>
<p>Screen将创建一个执行shell的全屏窗口。你可以执行任意shell程序，就像在ssh窗口中那样。在该窗口中键入exit退出该窗口，如果这是该screen会话的唯一窗口，该screen会话退出，否则screen自动切换到前一个窗口。</p>
<p>2．Screen命令后跟你要执行的程序。</p>
<pre class="displaycode">[root@tivf06 ~]# screen vi test.c</pre>
<p>Screen创建一个执行vi test.c的单窗口会话，退出vi将退出该窗口/会话。</p>
<p>3．以上两种方式都创建新的screen会话。我们还可以在一个已有screen会话中创建新的窗口。在当前screen窗口中键入<code>C-a c</code>，即Ctrl键+a键，之后再按下c键，screen 在该会话内生成一个新的窗口并切换到该窗口。</p>
<p>screen还有更高级的功能。你可以不中断screen窗口中程序的运行而暂时断开（detach）screen会话，并在随后时间重新连接（attach）该会话，重新控制各窗口中运行的程序。例如，我们打开一个screen窗口编辑/tmp/abc文件：</p>
<pre class="displaycode">[root@tivf06 ~]# screen vi /tmp/abc</pre>
<p>之后我们想暂时退出做点别的事情，比如出去散散步，那么在screen窗口键入<code>C-a d</code>，Screen会给出detached提示：</p>
<p><a name="N100EB"><strong>暂时中断会话</strong></a><br />
<a href="http://www.linuxsong.org/wp-content/uploads/2011/01/vi.jpg"><img class="alignnone size-full wp-image-466" title="vi" src="http://www.linuxsong.org/wp-content/uploads/2011/01/vi.jpg" alt="" width="572" height="307" /></a></p>
<p>半个小时之后回来了，找到该screen会话：</p>
<pre class="displaycode">[root@tivf06 ~]# screen -ls
There is a screen on:
        16582.pts-1.tivf06      (Detached)
1 Socket in /tmp/screens/S-root.</pre>
<p>重新连接会话：</p>
<pre class="displaycode">[root@tivf06 ~]# screen -r 16582</pre>
<p>看看出现什么了，太棒了，一切都在。继续干吧。</p>
<p>你可能注意到给screen发送命令使用了特殊的键组合C-a。这是因为我们在键盘上键入的信息是直接发送给当前screen窗口，必须用其他方式向screen窗口管理器发出命令，默认情况下，screen接收以C-a开始的命令。这种命令形式在screen中叫做键绑定（key binding），C-a叫做命令字符（command character）。</p>
<p>可以通过<code>C-a ?</code>来查看所有的键绑定，常用的键绑定有：</p>
<table class="ibm-data-table" border="0" cellspacing="0" cellpadding="0" width="50%">
<tbody>
<tr>
<th class="tb-row" scope="row">C-a ?</th>
<td>显示所有键绑定信息</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">C-a w</th>
<td>显示所有窗口列表</td>
</tr>
<tr>
<th class="tb-row" scope="row">C-a C-a</th>
<td>切换到之前显示的窗口</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">C-a c</th>
<td>创建一个新的运行shell的窗口并切换到该窗口</td>
</tr>
<tr>
<th class="tb-row" scope="row">C-a n</th>
<td>切换到下一个窗口</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">C-a p</th>
<td>切换到前一个窗口(与C-a n相对)</td>
</tr>
<tr>
<th class="tb-row" scope="row">C-a 0..9</th>
<td>切换到窗口0..9</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">C-a a</th>
<td>发送 C-a到当前窗口</td>
</tr>
<tr>
<th class="tb-row" scope="row">C-a d</th>
<td>暂时断开screen会话</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">C-a k</th>
<td>杀掉当前窗口</td>
</tr>
<tr>
<th class="tb-row" scope="row">C-a [</th>
<td>进入拷贝/回滚模式</td>
</tr>
</tbody>
</table>
<p>使用键绑定C-a ?命令可以看到, 默认的命令字符（Command key）为C-a，转义C-a（literal ^a）的字符为a：</p>
<p><a name="N101AF"><strong>Screen 常用选项</strong></a></p>
<p><a href="http://www.linuxsong.org/wp-content/uploads/2011/01/keybindings.jpg"><img class="alignnone size-full wp-image-467" title="keybindings" src="http://www.linuxsong.org/wp-content/uploads/2011/01/keybindings.jpg" alt="" width="572" height="308" /></a></p>
<p>因为screen把C-a看作是screen命令的开始，所以如果你想要screen窗口接收到C-a字符，就要输入C-a a。Screen也允许你使用-e选项设置自己的命令字符和转义字符，其格式为：</p>
<p>-exy		x为命令字符，y为转义命令字符的字符</p>
<p>下面命令启动的screen会话指定了命令字符为C-t，转义C-t的字符为t，通过C-t ?命令可以看到该变化。</p>
<pre class="displaycode">[root@tivf18 root]# screen -e^tt</pre>
<p><a name="N101CC"><strong>自定义命令字符和转义字符</strong></a><br />
<a href="http://www.linuxsong.org/wp-content/uploads/2011/01/newkeybinding.jpg"><img class="alignnone size-full wp-image-468" title="newkeybinding" src="http://www.linuxsong.org/wp-content/uploads/2011/01/newkeybinding.jpg" alt="" width="572" height="309" /></a></p>
<p>其他常用的命令选项有：</p>
<table class="ibm-data-table" border="0" cellspacing="0" cellpadding="0" width="80%">
<tbody>
<tr>
<th class="tb-row" scope="row">-c file</th>
<td>使用配置文件file，而不使用默认的$HOME/.screenrc</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">-d|-D [pid.tty.host]</th>
<td>不开启新的screen会话，而是断开其他正在运行的screen会话</td>
</tr>
<tr>
<th class="tb-row" scope="row">-h num</th>
<td>指定历史回滚缓冲区大小为num行</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">-list|-ls</th>
<td>列出现有screen会话，格式为pid.tty.host</td>
</tr>
<tr>
<th class="tb-row" scope="row">-d -m</th>
<td>启动一个开始就处于断开模式的会话</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">-r sessionowner/ [pid.tty.host]</th>
<td>重新连接一个断开的会话。多用户模式下连接到其他用户screen会话需要指定sessionowner，需要setuid-root权限</td>
</tr>
<tr>
<th class="tb-row" scope="row">-S sessionname</th>
<td>创建screen会话时为会话指定一个名字</td>
</tr>
<tr class="alt-row">
<th class="tb-row" scope="row">-v</th>
<td>显示screen版本信息</td>
</tr>
<tr>
<th class="tb-row" scope="row">-wipe [match]</th>
<td>同-list，但删掉那些无法连接的会话</td>
</tr>
</tbody>
</table>
<p>下例显示当前有两个处于detached状态的screen会话，你可以使用screen -r &lt;screen_pid&gt;重新连接上：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">[root@tivf18 root]# screen –ls
There are screens on:
        8736.pts-1.tivf18       (Detached)
        8462.pts-0.tivf18       (Detached)
2 Sockets in /root/.screen.

[root@tivf18 root]# screen –r 8736</pre>
</td>
</tr>
</tbody>
</table>
<p>如果由于某种原因其中一个会话死掉了（例如人为杀掉该会话），这时screen -list会显示该会话为dead状态。使用screen -wipe命令清除该会话：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">[root@tivf18 root]# kill -9 8462
[root@tivf18 root]# screen -ls
There are screens on:
        8736.pts-1.tivf18       (Detached)
        8462.pts-0.tivf18       (Dead ???)
Remove dead screens with 'screen -wipe'.
2 Sockets in /root/.screen.

[root@tivf18 root]# screen -wipe
There are screens on:
        8736.pts-1.tivf18       (Detached)
        8462.pts-0.tivf18       (Removed)
1 socket wiped out.
1 Socket in /root/.screen.

[root@tivf18 root]# screen -ls
There is a screen on:
        8736.pts-1.tivf18       (Detached)
1 Socket in /root/.screen.

[root@tivf18 root]#</pre>
</td>
</tr>
</tbody>
</table>
<p>-d –m 选项是一对很有意思的搭档。他们启动一个开始就处于断开模式的会话。你可以在随后需要的时候连接上该会话。有时候这是一个很有用的功能，比如我们可以使用它调试后台程序。该选项一个更常用的搭配是：-dmS sessionname</p>
<p>启动一个初始状态断开的screen会话：</p>
<pre class="displaycode">[root@tivf06 tianq]# screen -dmS mygdb gdb execlp_test</pre>
<p>连接该会话：</p>
<pre class="displaycode">[root@tivf06 tianq]# screen -r mygdb</pre>
<p>先来看看如何使用screen解决SIGHUP问题，比如现在我们要ftp传输一个大文件。如果按老的办法，SSH登录到系统，直接ftp命令开始传输，之后。。如果网络速度还可以，恭喜你，不用等太长时间了；如果网络不好，老老实实等着吧，只能传输完毕再断开SSH连接了。让我们使用screen来试试。</p>
<p>SSH登录到系统，在命令行键入screen。</p>
<pre class="displaycode">[root@tivf18 root]# screen</pre>
<p>在screen shell窗口中输入ftp命令，登录，开始传输。不愿意等了？OK，在窗口中键入C-a d：</p>
<p><a name="N1028D"><strong>管理你的远程会话</strong></a></p>
<p><a href="http://www.linuxsong.org/wp-content/uploads/2011/01/ftp.jpg"><img class="alignnone size-full wp-image-469" title="ftp" src="http://www.linuxsong.org/wp-content/uploads/2011/01/ftp.jpg" alt="" width="572" height="306" /></a></p>
<p>然后。。退出SSH登录？随你怎样，只要别杀掉screen会话。</p>
<p>是不是很方便？更进一步，其实我们可以利用screen这种功能来管理你的远程会话，保存你所有的工作内容。你是不是每次登录到系统都要开很多窗口，然后每天都要重复打开关闭这些窗口？让screen来帮你“保存”吧，你只需要打开一个ssh窗口，创建需要的screen窗口，退出的时候C-a d“保存”你的工作，下次登录后直接screen -r &lt;screen_pid&gt;就可以了。</p>
<p>最好能给每个窗口起一个名字，这样好记些。使用C-a A给窗口起名字。使用C-a w可以看到这些窗口名字，可能名字出现的位置不同。使用putty：</p>
<p><a name="N102A5"><strong>putty</strong></a></p>
<p><strong><a href="http://www.linuxsong.org/wp-content/uploads/2011/01/putty.jpg"><img class="alignnone size-full wp-image-470" title="putty" src="http://www.linuxsong.org/wp-content/uploads/2011/01/putty.jpg" alt="" width="572" height="318" /></a></strong></p>
<p>使用telnet：</p>
<p><a name="N102B7"><strong>telnet</strong></a></p>
<p><strong><a href="http://www.linuxsong.org/wp-content/uploads/2011/01/telnet.jpg"><img class="alignnone size-full wp-image-471" title="telnet" src="http://www.linuxsong.org/wp-content/uploads/2011/01/telnet.jpg" alt="" width="572" height="383" /></a></strong></p>
<p>Screen提供了丰富强大的定制功能。你可以在Screen的默认两级配置文件/etc/screenrc和$HOME/.screenrc中指定更多，例如设定screen选项，定制绑定键，设定screen会话自启动窗口，启用多用户模式，定制用户访问权限控制等等。如果你愿意的话，也可以自己指定screen配置文件。</p>
<p>以多用户功能为例，screen默认是以单用户模式运行的，你需要在配置文件中指定multiuser on 来打开多用户模式，通过acl*（acladd,acldel,aclchg...）命令，你可以灵活配置其他用户访问你的screen会话。更多配置文件内容请参考screen的man页。</p>
<ul>
<li>“Advanced Programming in the UNIX® Environment: Second Edition” W. Richard Stevens, Stephen A. Rago 提供了更多关于Linux/Unix进程关系、信号的知识。</li>
<li>GNU Screen的官方网站：<a href="http://www.gnu.org/software/screen/" target="_blank">http://www.gnu.org/software/screen/</a></li>
<li>Screen的man page提供了最详细的信息：<a href="http://www.slac.stanford.edu/comp/unix/package/epics/extensions/iocConsole/screen.1.html" target="_blank">http://www.slac.stanford.edu/comp/unix/package/epics/extensions/iocConsole/screen.1.html</a></li>
</ul>
<div class="ibm-container ibm-portrait-module ibm-alternate-two">
<div class="ibm-container-body">
<p><a name="author">关于作者</a></p>
<p><a name="author"></a>田强，中国软件开发中心 Tivoli 部门软件工程师，负责 IBM 产品TMF(Tivoli Management Framework)的维护和客户支持工作，热爱 Linux。</p>
<p>原文地址：<a title="screen" href="http://www.ibm.com/developerworks/cn/linux/l-cn-screen/" target="_blank">http://www.ibm.com/developerworks/cn/linux/l-cn-screen/</a></p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2011/01/linux-scree/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>phpQuery占用过多内存的解决方法</title>
		<link>http://www.linuxsong.org/2011/01/phpquery-memory-leak/</link>
		<comments>http://www.linuxsong.org/2011/01/phpquery-memory-leak/#comments</comments>
		<pubDate>Fri, 07 Jan 2011 15:36:12 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=461</guid>
		<description><![CDATA[phpQuery是一个用php实现的类似jQuery的开源项目，可以在服务器端以jQuery的语法形式解析网页元素。 相对于正则或其它方式匹配网页方式，phpQuery使用起来要方便的多。
在使用phpQuery采集网页时，遇到一个问题：在处理大量网页之后，phpQuery占用的内存数量非常惊人（很快就超过了1G)， <a href="http://www.linuxsong.org/2011/01/phpquery-memory-leak/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>phpQuery是一个用<a title="php" href="http://www.linuxsong.org/category/php/">php</a>实现的类似jQuery的开源项目，可以在服务器端以jQuery的语法形式解析网页元素。 相对于正则或其它方式匹配网页方式，phpQuery使用起来要方便的多。</p>
<p>在使用phpQuery采集网页时，遇到一个问题：在处理大量网页之后，phpQuery占用的内存数量非常惊人（很快就超过了1G)，</p>
<p>比如这段代码：</p>
<pre class="brush: plain;">

while (true) {
    phpQuery::newDocumentFile($htmlFile);
    // 处理网页元素...
    echo memory_get_usage() . &quot;\n&quot;;
}
</pre>
<p>谨慎运行上面这段代码，它会很快用光你的内存。</p>
<p>经过查看phpQuery的源代码终于发现了问题所在，phpQuery在每处理一个网页就会产生一个DOMDocumentWrapper 对象，而每个DOMDocumentWrapper 对象会被保存在静态成员$documents中（phpQuery::createDocumentWrapper中），这个变量是一个数组，每解析一个网页数组元素就增加一个。</p>
<p>phpQuery::$documents[$wrapper-&gt;id] = $wrapper;</p>
<p>找到问题后，解决就很容易了，每次解析完一个网页，把phpQuery::$documents置空即可。</p>
<pre class="brush: plain;">

while (true) {
    phpQuery::newDocumentFile($htmlFile);
    // 处理网页元素...
    phpQuery::$documents = array();
    echo memory_get_usage() . &quot;\n&quot;;
}
</pre>
<p>内存占用稳定了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2011/01/phpquery-memory-leak/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vim中快速插入序列</title>
		<link>http://www.linuxsong.org/2010/12/vim-insert-sequence/</link>
		<comments>http://www.linuxsong.org/2010/12/vim-insert-sequence/#comments</comments>
		<pubDate>Thu, 30 Dec 2010 16:25:25 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=455</guid>
		<description><![CDATA[Vim编辑文本时经常会遇到需要插入一个序列（比如从10到20），或者与此类似的相关序列问题，原来没有仔细想过这个问题，总是一个个的敲。时间久了觉得这样实在太麻烦，Vim这么强大的编辑器一定要更好的方法可以解决这个问题。于时花时间思考了一下，总结了以下几种快速处理序列的方法。 <a href="http://www.linuxsong.org/2010/12/vim-insert-sequence/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.linuxsong.org/tag/vim/">Vim</a>编辑文本时经常会遇到需要插入一个序列（比如从10到20），或者与此类似的相关序列问题，原来没有仔细想过这个问题，总是一个个的敲。时间久了觉得这样实在太麻烦，Vim这么强大的编辑器一定要更好的方法可以解决这个问题。于时花时间思考了一下，总结了以下几种快速处理序列的方法。</p>
<p>例如，在第5行文本后面插入一个序列10到20（每行一个）.</p>
<p>方法1：</p>
<p>将光标移到第5行，在命令模式下输入</p>
<p>11o&lt;ESC&gt;  (插入11个空行）</p>
<p>:let i=10|g/\%&gt;5l\%&lt;17l/s/^/\=i/|let i+=1  (\%&gt;5l\%&lt;17l 意思是从第6行到16行）</p>
<p>这样就会得到我们想要的结果（从第6行到16行）：</p>
<p>10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
20</p>
<p>如果你想认内容在一行上，那么就将光标移到第6后，然后在命令模式下输入 1J即可。</p>
<p>另外一种方法 是利用宏录制与 &lt;c-a&gt; ：</p>
<p>在第6行插入10,然后在命令模式下依次输入：</p>
<p>qq</p>
<p>yyp</p>
<p>&lt;c-a&gt; (ctrl+a)</p>
<p>q</p>
<p>9@q</p>
<p>利用这两种方法，我们可以方便生成需要的序列，以及快速处理其它一些与序列相关的问题。</p>
<p>另外，如果你是在<a href="http://www.linuxsong.org/tag/linux/">Linux</a>系统下，有一种更为方便的方法，就是在Vim中直接调用Linux的seq命令</p>
<p>:r !seq 10 20 （多行）</p>
<p>或</p>
<p>:r !echo {10..20} (单行）</p>
<p><a href="http://www.linuxsong.org/tag/vim/">Vim</a>真的挺强大的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/12/vim-insert-sequence/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux中彻底删除文件</title>
		<link>http://www.linuxsong.org/2010/12/shred-file/</link>
		<comments>http://www.linuxsong.org/2010/12/shred-file/#comments</comments>
		<pubDate>Sun, 26 Dec 2010 04:14:37 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=451</guid>
		<description><![CDATA[我们知道在Linux中删除文件一般使用rm, 但是rm命令并不会真的清空保存该文件的数据块的内容，而只是释放了该文件所占用的索引节点和数据块。因此用rm删除的文件是可以通过一些方法恢复的(比如可以用debugfs恢复，具体方法Google之)。

有些时候我们要彻底删除一些文件，可以使用shred命令来实现，shred是coreutils的一部分，所以Linux中基本都会有这个命令。 <a href="http://www.linuxsong.org/2010/12/shred-file/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>我们知道在<a href="http://www.linuxsong.org/tag/linux/">Linux</a>中删除文件一般使用rm, 但是rm命令并不会真的清空保存该文件的数据块的内容，而只是释放了该文件所占用的索引节点和数据块。因此用rm删除的文件是可以通过一些方法恢复的(比如可以用debugfs恢复，具体方法Google之)。</p>
<p>有些时候我们要彻底删除一些文件，可以使用shred命令来实现，shred是coreutils的一部分，所以<a href="http://www.linuxsong.org/tag/linux/">Linux</a>中基本都会有这个命令。</p>
<p>shred彻底删除文件的方法:</p>
<p>$ shred -u file</p>
<p>shred会用一些随机内容覆盖文件所在的节点和数据块，并删除文件(-u参数)。</p>
<p>如果想清除的更彻底一点可以加-z 参数，意思是先用随机数据填充，最后再用0填充。</p>
<p>$ shred -u -z file</p>
<p>另外shred还可以清除整个分区或磁盘，比如想彻底清除/dev/sdb1分区的内容可以这样:</p>
<p>$ shred /dev/sdb1   (注意不要加-u参数)</p>
<p>shred的详细参数：<br />
-f, --force   更改权限允许写入(如有必要)</p>
<p>-n, --iterations=N   重写N次，默认为3次</p>
<p>--random-source=FILE 从指定文件读取数据</p>
<p>-s, --size=N  将文件粉碎为固定大小 (可使用后缀如K、M、C等)</p>
<p>-u, --remove   重写后截短并移除文件</p>
<p>-v, --verbose   显示进度</p>
<p>-z, --zero - add  用0覆盖数据</p>
<p>–help  显示帮助</p>
<p>–version   显示版本信息</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/12/shred-file/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scheme的一些学习资源</title>
		<link>http://www.linuxsong.org/2010/12/scheme-resource/</link>
		<comments>http://www.linuxsong.org/2010/12/scheme-resource/#comments</comments>
		<pubDate>Sat, 04 Dec 2010 05:23:59 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[lisp]]></category>
		<category><![CDATA[scheme]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=443</guid>
		<description><![CDATA[最近正在学习Scheme，Scheme 是 LISP 的一种方言（或者说是变种），一门非常有趣的语言，语法结构非常简单。最新的Scheme标准定义（R5RS)才50页左右。Scheme设计非常简单，但是功能非常强大。 <a href="http://www.linuxsong.org/2010/12/scheme-resource/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>最近正在学习Scheme，Scheme 是 LISP 的一种方言（或者说是变种），一门非常有趣的语言，语法结构非常简单。最新的Scheme标准定义（R5RS)才50页左右。Scheme设计非常简单，但是功能非常强大。</p>
<p>下面介绍一些<a title="Scheme" href="http://www.linuxsong.org/tag/scheme/">Scheme</a>的学习资源，方便查阅。</p>
<h3><strong>Scheme 教程</strong></h3>
<p>1. Sheme语言修订报告：<a href="http://www.linuxsong.org/wp-content/uploads/2010/12/scheme-r5rs.pdf">scheme-r5rs</a>(英文），<a href="http://www.linuxsong.org/wp-content/uploads/2010/12/schem-r5rscn.pdf">schem-r5rs</a>(王咏刚翻译的中文版）</p>
<p>2. <a href="http://mitpress.mit.edu/sicp/" target="_blank">Structure and Interpretation of Computer Programs</a></p>
<p>简称： SICP，非常著名的一本书（中译本叫《计算机程序的解释与构造》，由裘宗燕老师翻译的），Scheme 的鼻祖 Gerald Jay Sussman 和计算机教育专家 Hal Abelson 合写的，20 年来影响整个计算机科学教育的著作，著名的 MIT 课程 6.001（计算机科学专业的入门课程） 的教材，全世界有超过100所大学在使用这本书做为教材。</p>
<p>3. 《<a title="How to Design Programs" href="http://www.htdp.org/2003-09-26/Book/" target="_blank">How to design programs</a>》(中译本《程序设计方法》，好像已经绝版了，我没买到:( )</p>
<h3><strong>Scheme 解释器和编译器</strong></h3>
<p><a title="Scheme" href="http://www.linuxsong.org/tag/scheme/">Scheme</a>的解释器非常多，而且基本都是自由软件。</p>
<p>我觉得比较好用的是<a title="drracket" href="http://racket-lang.org/" target="_blank">DrScheme</a>(现在改名叫DrRacket了,Fedora仓库中有，叫plt-scheme，但是版本比较老，可以直接从官网上下载最新版本，也有Windows版本）,带有图形界面，有语法高亮，调试，单步执行等功能。</p>
<p><a title="guile" href="http://www.gnu.org/software/guile/guile.html">Guile</a>,适合做嵌入式解释器，及插件扩展语言,它是 GNU 项目的官方扩展语言，很多开源应用程序中都使 Guile 来编写脚本（比如Emacs,Gimp等)</p>
<p>另外<a href="http://www-sop.inria.fr/mimosa/fp/Bigloo/" target="_blank">bigloo</a>, Gambit-C 和 Chicken 可以把 Scheme 编译成机器代码，提高执行速度。</p>
<p>Fedora中bigloo和Gambit-C可以直接yum 安装。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/12/scheme-resource/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>大型高性能Web站点的十项规则</title>
		<link>http://www.linuxsong.org/2010/11/high-performance-web-site/</link>
		<comments>http://www.linuxsong.org/2010/11/high-performance-web-site/#comments</comments>
		<pubDate>Thu, 11 Nov 2010 06:10:34 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=432</guid>
		<description><![CDATA[总结了国内网络和游戏公司运行后端服务器过程中所得到的实践经验和教训。这些规则适用于日访问量从一万到上百万的大型系统。

在我们公司ChinaNetCloud，见过多种不同类型的网站和系统，有好也有差。其中有些系统拥有良好的服务器/网络架构，并且进行了合理的调整和监控 ；然而一般的系统都会有安全和性能上的问题，不能良好运行，也无法变得更流行。 <a href="http://www.linuxsong.org/2010/11/high-performance-web-site/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>作者：Steve Mushero  译者：侯伯薇</p>
<p>总结了国内网络和游戏公司运行后端服务器过程中所得到的实践经验和教训。这些规则适用于日访问量从一万到上百万的大型系统。</p>
<p>在我们公司ChinaNetCloud，见过多种不同类型的网站和系统，有好也有差。其中有些系统拥有良好的服务器/网络架构，并且进行了合理的调整和监控 ；然而一般的系统都会有安全和性能上的问题，不能良好运行，也无法变得更流行。</p>
<p>在中国，开源的LAMP栈是最流行的网络架构，它使用<a title="php" href="http://www.linuxsong.org/tag/php/">PHP</a>开发，运行在Apache服务器上，以MySQL作为数据库，所有这些都运行在<a title="linux" href="http://www.linuxsong.org/tag/linux/">Linux</a>上。它是个可靠的平台，运行良好，是现在全球最流行的Internet系统架构。然而，我们很难对其规模进行正确的扩展并保持安全性，因为每个应用层都有其自身的问题、缺陷和最佳实践。我们的工作就是帮助企业用最低的操作成本来创建并运行高性能的、可伸缩的、安全的系统，因此对于这类问题我们有很丰富的经验。</p>
<p>当前的实际情况是，很多网站都是由开发人员快速而廉价地创建，通常没有任何IT人员或者经理，只是由程序员来管理系统。造成的结果是，虽然花费很低的成本网站就可以开始运行，但是当拥有大量用户、需要扩展规模的时候，通常就会面临真正的问题。毕竟，中国拥有三亿八千万的Internet用户，如果其中的0.01%访问这个站点，就很容易引发25万~50万的页面访问量。这些问题在各个级别上都会产生，下面总结的规则是对最一般的问题进行概述，并且说明为什么这些规则如此重要，以及最好采用什么方法来修正它们。遵循这些建议的站点会提高它的可伸缩性、安全性以及操作上的稳定性。</p>
<p><strong><span id="more-432"></span>1.使用合适的会话管理</strong></p>
<p>第一个想到的扩展系统的方法就是添加更多硬件。例如，使用两台服务器而不是一台。这听着合理，但会产生潜在问题：会话管理。这对Java程序来说是很严重的问题，在PHP中也会产生可延展性问题，对于数据库的负载尤其如此。</p>
<p>会话被定义为单独的最终用户登录或者连接一段时间，其中通常会包含多个TCP/IP的HTTP连接、几个Web页面，通常还包括几十个甚至上百个页面元素，如框架、菜单、Ajax更新等。所有这些HTTP请求都需要知道用户是谁，才能满足安全的要求，并向用户传送适当的内容，因为这些都是会话的组成部分。通常每个会话都会包括相互关联的会话数据，如用户名、用户ID、历史、购物车、统计资料等等信息。</p>
<p>问题在于，在有两台Web服务器和多个HTTP连接的情况下，用户流量会在两台服务器之间分配和移动，服务器很难知道用户是谁，并对所有数据进行跟踪，因为每个页面或者页面的组成部分都可能来自不同的服务器。在<a title="php" href="http://www.linuxsong.org/tag/php/">PHP</a>中，通常是这样解决的，在第一次连接或登录的时候就创建一个会话ID并将其放在Cookie中，然后这个Cookie会和每个HTTP请求一起发送。</p>
<p>这样做带来一个问题，接下来每段PHP脚本都需要基于ID来查找会话数据。由于PHP无法在执行过程之间保持状态（这与Java不同），这个会话数据需要存储在某个地方，通常是在数据库中。但是，如果复杂的页面需要在每个页面载入过程中对其进行十次查找（这是经常要做的），那就意味着每个页面都要执行10次SQL查询，这会导致数据库上很大的负载。</p>
<p>在前面所举的中国Internet用户0.01%的例子中，可能很容易在每秒内仅仅为了管理会话就生成上百个查询。解决方法是一直使用位于Cookie中的会话ID，并且使用像Memcached之类的服务来缓存会话数据以获得高性能。</p>
<p>还要注意其中存在安全性的问题，因为黑客可以伪造另一个用户的会话ID，这是很容易找到或看到的，特别是在公用的Wi-Fi中。解决方法是对会话ID进行恰当的加密或者签名，并将其与时间区间、IP地址以及其他关键信息 像浏览器或者其他细节相绑定。在Internet上有很多不错的关于良好的会话管理的例子，你可以根据需要找到最适合的。</p>
<p><strong>2.总是要考虑安全性</strong></p>
<p>尽管编写像防止SQL注入和登录安全之类的代码涉及很多安全问题，但不幸的是，几乎没有人考虑过安全性，而那些考虑到的人也没有对其进行很好地理解。而本文要关注的是操作性的系统安全。对于这类安全，我们的焦点集中在三个安全领域：防火墙、运行的用户以及文件访问权限。</p>
<p>除了配置专门的硬件防火墙（像Cisco的ASA）之外，所有服务器都还应该运行像Iptables之类的防火墙，它会保护服务器免受其他威胁和攻击。这些威胁和攻击可能来自公共的Internet、其他服务器或本地服务器，也包括使用VPN或者SSH通道的开发和操作人员。我们仅对指定的IP开放确实需要的端口。Iptables可能会很复杂，但是有很多不错的模板，我们通常可以使用它们来帮助客户创建Iptables。例如，默认的RedHat或者CentOS防火墙的配置说明只有10行，显然并不实用。我们最佳实践的Iptables配置大概有5页，这其中包含了Linux所能提供的最高级的安全防范。</p>
<p>所有公用的服务，都应该运行在专门的用户下，如Apache。切记永远都不要使用Root用户运行，因为这会让任何闯入到Apache的用户接管整个服务器。如果Apache只是运行在Apache用户下或者运行在Nobody下，那么闯入Apache就不是一件容易的事情了。</p>
<p>Web服务器运行或者服务的文件（像.php和.html文件）对于Web服务器的用户应该是不可写的。这意味着Apache或者Nginx用户不应该拥有Web目录的写权限。有很多方法都可以做到这一点，而最简单的就是将这些文件为其他用户所有，然后让Apache/Nginx等用户归属于能够使用640权限读取文件的组中。这会防范几乎所有的黑客和针对页面的攻击。</p>
<p>此外，永远不要使用Ftp来上传文件，特别是在公用的Wi-Fi环境中，因为在其中黑客很容易盗取用户名和密码。取而代之的是使用Sftp会更加安全。另外，每个雇员都应该拥有自己的用户ID和随机密码。</p>
<p><strong>3.使用标准的路径和安装配置</strong></p>
<p>一个令人讨厌的部署问题是，开发者很少考虑他们的软件会被部署到生产Web服务器的什么位置，以及如何部署。我们看到过许多大型的系统将它们的PHP代码部署在/home/xiaofeng或者/web/code路径下。事实上，这两个路径都是非常不标准的，并且会带来操作和安全性的问题。当这些系统从开发环境转移到测试环境再到生产环境中时，因为每个安装配置都是非标准的，所以经常会出现问题，这时就需要开发者调整才能够正常工作。</p>
<p>你应该总是使用标准的安装包和二进制文件来安装像Apache之类的服务器。不要从源代码编译或者安装Tarball，因为这会导致长期稳定性和管理上的问题，另外在服务器上安装多个不同的版本也会造成混淆。</p>
<p>Web 站点应该总是在指定的平台和Linux发布的标准路径下进行测试和部署 ，像 RedHat 或者CentOS下的/var/www/html路径。这有助于对系统进行有效的权限管理、备份、配置、监控以及其他操作。</p>
<p>Web服务器的日志应该存放在/var/logs或者/var/logs/app_name下，而不应该位于主代码区域。这样做的原因不仅仅是因为这些标准的路径很重要，更应该关注的是，恰当地配置服务器会将/var配置为分离的文件系统。如果应用程序突然写入了大量日志并占用所有磁盘空间，由于我们做了以上的配置就不会导致系统崩溃，或者其他严重的问题。如果日志位于其他位置，就可能会产生问题。</p>
<p><strong>4.总是使用日志</strong></p>
<p>在Web系统中做多少日志都不为过。所有系统都应该将重要的数据写入到日志中，不管是它们自己的日志还是系统的Syslog。Cron的Job以及其他Shell脚本或者C语言的程序，对日志都有相应标准以及简单的函数。在<a href="http://www.linuxsong.org/tag/shell/">Shell</a>脚本中，只需要使用 Logger命令就可以实现日志的写入。在脚本启动/停止、重要的脚本执行以及实时数据产生的情况下都要执行写入日志操作。这样出现问题的时候，查看主要的系统日志就可以很容易地看到发生了什么。</p>
<p>大型系统经常会使用专门的工具如Local5来记录日志，并配置Syslog或者Syslog-ng来将其存放在单独的文件中，这样会更容易使用。需要注意的是，Syslog工具和Logger（以及任何Syslog调用）默认优先使用user.notice，如有必要，你可以对其进行调整。</p>
<p>一个好的系统会对程序进行配置，用来打开或者关闭日志，并可以选择在每模块或者功能的级别上应用不同级别的日志。这使得我们可以记录非常详细和强大的日志，用来分析和调试在生产操作中所发生的问题。</p>
<p><a href="http://www.linuxsong.org/wp-content/uploads/2010/11/cjdxwz1.jpg"><img class="alignnone size-full wp-image-434" title="创建大型高性能Web站点的十项规则" src="http://www.linuxsong.org/wp-content/uploads/2010/11/cjdxwz1.jpg" alt="创建大型高性能Web站点的十项规则" width="550" height="399" /></a></p>
<p id="img4710125"><strong>5. 使用良好的数据库设计和SQL</strong></p>
<p>在任何系统中，数据库通常是最大的性能瓶颈。而影响数据库性能的最大两个问 题是数据库设计和SQL代码质量。很多系统都拥有良好的或者至少是可用的数据库设计，但由于没有经过适当的性能测试，SQL代码质量通常都会很差。这样的 SQL代码在开发环境中可能运行很快，因为其中只有小数据集和最小的负载。但是当成千上万的用户同时读取数据库中 上百万条记录的时候，它就很可能会崩溃。</p>
<p>不幸的是，这些问题一开始并不明显，直到系统增大、突然开始崩溃的时候才会显现出来。在增大的 过程中，数据库系统看起来运行得很快(因为数据都位于内存中，而且很少有并发的查询)，并且对用户的响 应也很快，但实际上它的内部运行效率很低。这并不重要，我们关注的是在系统增大并遇到性能问题之前找到这些问题并加以解决。</p>
<p>关于这个问 题有很多不错的书和站点进行了解 析，其中的关键工具包括慢查询日志、INNODB状态系统，以及描述当前性能的MySQL统计信息。我们见到过很多系统每秒会读取500,000条数据， 这是出现SQL问题的明显预兆，但公司往往对其一无所知直到服务器开始崩溃。</p>
<p>MySQL系统应该对所有数据使用 INNODB存储引擎，因为INNODB与之前的MyISAM相比，运行得更快、更稳定，并且管理性能和备份工作也更加容易和快捷。在主配置文件 中，INNODB应该被设置为默认的数据库引擎，并且系统应该不时地进行检查，看是否意外创建了MyISAM的表。</p>
<p><strong>6. 总要拥有良好的DB配置和备份</strong></p>
<p>很多公司都没有良好的备份机制，也不知道如何恰当地完成这项工作。MySQL的Dump是不够 的，因为最好的备份方法是使用LVM快照和INNODB对系统进行热备份，从而得到超快的速度和超高的可靠性。</p>
<p>另外，在将所有备份文件 从服务器上转移出来之前要进行压缩和加密。另外还要确保拥有设计合理的 MySQL配置。MySQL默认安装使用说明中只有5~10行关于配置的说明，这根本不适合开发使用。 而我们提供给客户的最佳实践文档足足有10页那么长。文档中大约有100种有用的关于安全、性能和稳定性问题的设定，包括防止数据败坏，其中很多设定都是 非常重要的。</p>
<p><strong>7. 使用读/写数据库分离</strong></p>
<p>随着系统变得越来越庞大，特别是当它们拥有很差的SQL时， 一台数据库服务器通常不足以处理负载。但是多个数据库 意味着重复，除非你对数据进行了分离。更一般地，这意味着建立主/从副本系统，其中程序会对主库编写所有的Update、Insert和Delete变更 语句，而所有Select的数据都读取自从数据库(或者多个从数据库)。</p>
<p>尽管概念上很简单，但是想要合理、精确地实现并不容易，这可能 需要大量的代码工作。因此，即便在开始时使用同一台数据库服务器，也要尽早计划在PHP中使用分离的DB连接来进行读写操作。如果正确 地完成该项工作，那么系统就可以扩展到2台、3台甚至12台服务器，并具备高可用性和稳定性。</p>
<p><strong>8. 使用类似Memcached之类的数据库缓存</strong></p>
<p>即便有了好的数据库设计、SQL和读写 离，大型的系统仍然需要更快的性能，特别是对会话状态、好友列表以及BBS文字之类的东西。为了达到这个目的，我们可以使用像MemCached之类的数 据缓存，它是一个高性能的简单数据缓存，已经被所有最大型的站点使用。但是要小心的是，不要100%依赖于一台Memcache服务器来提高性能，因为如果那台服务器崩溃了，就会破坏整个系统的性能。在这种情况下，应该使用2~3台 Memcache服务器形成簇集架构，并且有选择地包含一个 缓存准备过程， 如果缓存服务器重启，需要重新载入数据，它能够快速 地载入缓存。</p>
<p><strong>9. 构建测试和开发环境</strong></p>
<p>很多公司只有开发者的桌面系统和他们的生产服务器。当系统变得越来越大、越来越复杂时，测试和管理代码就会导致严重的问 题。最佳的实践是拥有两个测试系统，一个用于开发者的代码和功能的整合测试， 另一个要与生产环境完全一致，从而更容易向生产环境平滑地过渡。幸运的是，现在使用云计算(或者私有云)可以轻松达到这一点。一个5~10台服务器的生产 环境，可以很容易地在办公室或者IDC中使用一台服务器来复制，从而用于测试，而这台服务器我们可以用于多个客户的项目。</p>
<p><strong>10. 使用版本控制</strong></p>
<p>最后，要对一切使用版本控制，包括测试和生 产环境的部署。很多开发者都使用SVN或者类似的方法。在理想状态下，这些方法可以被用于所有代码、脚本、HTML、图片、配置、文档和测试。版本控制应 该是代码转移到测试环境的必经之路，而不是简单地复制或者使用tar文件，因为这二者都是不可靠的。开发者应该将所有一切都签入，打上标签，然后将它们签出到测试系统。如果所有都没问题，那么它们会将该版本签出到 生产环境。</p>
<p><strong>总结</strong></p>
<p>不管是在开发还是在运营过程中，创建可靠的高性能Web系统都有很多应该注意的事项。 本文试图从可操作性和可靠性的角度讨论最重要的几点。当你构建和管理站点的时候，请不要忘了这些重要的问题。遵循这些规则会有助于确保系统长久、良好地运 行。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/11/high-performance-web-site/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为什么Lisp语言如此先进？</title>
		<link>http://www.linuxsong.org/2010/10/revenge-of-the-nerds/</link>
		<comments>http://www.linuxsong.org/2010/10/revenge-of-the-nerds/#comments</comments>
		<pubDate>Thu, 14 Oct 2010 08:33:01 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[lisp]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=428</guid>
		<description><![CDATA[如果我们把流行的编程语言，以这样的顺序排列：Java、Perl、Python、Ruby。你会发现，排在越后面的语言，越像Lisp。

Python模仿Lisp，甚至把许多Lisp黑客认为属于设计错误的功能，也一起模仿了。至于Ruby，如果回到1975年，你声称它是一种Lisp方言，没有人会反对。

编程语言现在的发展，不过刚刚赶上1958年Lisp语言的水平。 <a href="http://www.linuxsong.org/2010/10/revenge-of-the-nerds/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>作者：Paul Graham</p>
<p>译者：阮一峰</p>
<p>英文原文：<em><a href="http://www.paulgraham.com/icad.html" target="_blank">Revenge of the Nerds</a></em></p>
<p>一、</p>
<p>如果我们把流行的编程语言，以这样的顺序排列：Java、Perl、Python、Ruby。你会发现，排在越后面的语言，越像Lisp。</p>
<p>Python模仿Lisp，甚至把许多Lisp黑客认为属于设计错误的功能，也一起模仿了。至于Ruby，如果回到1975年，你声称它是一种Lisp方言，没有人会反对。</p>
<p>编程语言现在的发展，不过刚刚赶上1958年Lisp语言的水平。</p>
<p><span id="more-428"></span>二、</p>
<p>1958年，John McCarthy设计了Lisp语言。我认为，当前最新潮的编程语言，只是实现了他在1958年的设想而已。</p>
<p>这怎么可能呢？计算机技术的发展，不是日新月异吗？1958年的技术，怎么可能超过今天的水平呢？</p>
<p>让我告诉你原因。</p>
<p>这是因为John McCarthy本来没打算把Lisp设计成编程语言，至少不是我们现在意义上的编程语言。他的原意只是想做一种理论演算，用更简洁的方式定义图灵机。</p>
<p>所以，为什么上个世纪50年代的编程语言，到现在还没有过时？简单说，因为这种语言本质上不是一种技术，而是数学。数学是不会过时的。你不应该把Lisp语言与50年代的硬件联系在一起，而是应该把它与快速排序（Quicksort）算法进行类比。这种算法是1960年提出的，至今仍然是最快的通用排序方法。</p>
<p>三、</p>
<p>Fortran语言也是上个世纪50年代出现的，并且一直使用至今。它代表了语言设计的一种完全不同的方向。Lisp是无意中从纯理论发展为编程语言，而Fortran从一开始就是作为编程语言设计出来的。但是，今天我们把Lisp看成高级语言，而把Fortran看成一种相当低层次的语言。</p>
<p>1956年，Fortran刚诞生的时候，叫做Fortran I，与今天的Fortran语言差别极大。Fortran I实际上是汇编语言加上数学，在某些方面，还不如今天的汇编语言强大。比如，它不支持子程序，只有分支跳转结构（branch）。</p>
<p>Lisp和Fortran代表了编程语言发展的两大方向。前者的基础是数学，后者的基础是硬件架构。从那时起，这两大方向一直在互相靠拢。Lisp刚设计出来的时候，就很强大，接下来的二十年，它提高了自己的运行速度。而那些所谓的主流语言，把更快的运行速度作为设计的出发点，然后再用超过四十年的时间，一步步变得更强大。</p>
<p>直到今天，最高级的主流语言，也只是刚刚接近Lisp的水平。虽然已经很接近了，但还是没有Lisp那样强大。</p>
<p>四、</p>
<p>Lisp语言诞生的时候，就包含了9种新思想。其中一些我们今天已经习以为常，另一些则刚刚在其他高级语言中出现，至今还有2种是Lisp独有的。按照被大众接受的程度，这9种思想依次是：</p>
<p>1. 条件结构（即&quot;if-then-else&quot;结构）。现在大家都觉得这是理所当然的，但是Fortran I就没有这个结构，它只有基于底层机器指令的goto结构。</p>
<p>2. 函数也是一种数据类型。在Lisp语言中，函数与整数或字符串一样，也属于数据类型的一种。它有自己的字面表示形式（literal representation），能够储存在变量中，也能当作参数传递。一种数据类型应该有的功能，它都有。</p>
<p>3. 递归。Lisp是第一种支持递归函数的高级语言。</p>
<p>4. 变量的动态类型。在Lisp语言中，所有变量实际上都是指针，所指向的值有类型之分，而变量本身没有。复制变量就相当于复制指针，而不是复制它们指向的数据。</p>
<p>5. 垃圾回收机制。</p>
<p>6. 程序由表达式（expression）组成。Lisp程序是一些表达式区块的集合，每个表达式都返回一个值。这与Fortran和大多数后来的语言都截然不同，它们的程序由表达式和语句（statement）组成。</p>
<p>区分表达式和语句，在Fortran I中是很自然的，因为它不支持语句嵌套。所以，如果你需要用数学式子计算一个值，那就只有用表达式返回这个值，没有其他语法结构可用，因为否则就无法处理这个值。</p>
<p>后来，新的编程语言支持区块结构（block），这种限制当然也就不存在了。但是为时已晚，表达式和语句的区分已经根深蒂固。它从Fortran扩散到Algol语言，接着又扩散到它们两者的后继语言。</p>
<p>7. 符号（symbol）类型。符号实际上是一种指针，指向储存在哈希表中的字符串。所以，比较两个符号是否相等，只要看它们的指针是否一样就行了，不用逐个字符地比较。</p>
<p>8. 代码使用符号和常量组成的树形表示法（notation）。</p>
<p>9. 无论什么时候，整个语言都是可用的。Lisp并不真正区分读取期、编译期和运行期。你可以在读取期编译或运行代码；也可以在编译期读取或运行代码；还可以在运行期读取或者编译代码。</p>
<p>在读取期运行代码，使得用户可以重新调整（reprogram）Lisp的语法；在编译期运行代码，则是Lisp宏的工作基础；在运行期编译代码，使得Lisp可以在Emacs这样的程序中，充当扩展语言（extension language）；在运行期读取代码，使得程序之间可以用S-表达式（S-expression）通信，近来XML格式的出现使得这个概念被重新&quot;发明&quot;出来了。</p>
<p>五、</p>
<p>Lisp语言刚出现的时候，它的思想与其他编程语言大相径庭。后者的设计思想主要由50年代后期的硬件决定。随着时间流逝，流行的编程语言不断更新换代，语言设计思想逐渐向Lisp靠拢。</p>
<p>思想1到思想5已经被广泛接受，思想6开始在主流编程语言中出现，思想7在Python语言中有所实现，不过似乎没有专用的语法。</p>
<p>思想8可能是最有意思的一点。它与思想9只是由于偶然原因，才成为Lisp语言的一部分，因为它们不属于John McCarthy的原始构想，是由他的学生Steve Russell自行添加的。它们从此使得Lisp看上去很古怪，但也成为了这种语言最独一无二的特点。Lisp古怪的形式，倒不是因为它的语法很古怪，而是因为它根本没有语法，程序直接以解析树（parse tree）的形式表达出来。在其他语言中，这种形式只是经过解析在后台产生，但是Lisp直接采用它作为表达形式。它由列表构成，而列表则是Lisp的基本数据结构。</p>
<p>用一门语言自己的数据结构来表达该语言，这被证明是非常强大的功能。思想8和思想9，意味着你可以写出一种能够自己编程的程序。这可能听起来很怪异，但是对于Lisp语言却是再普通不过。最常用的做法就是使用宏。</p>
<p>术语&quot;宏&quot;在Lisp语言中，与其他语言中的意思不一样。Lisp宏无所不包，它既可能是某样表达式的缩略形式，也可能是一种新语言的编译器。如果你想真正地理解Lisp语言，或者想拓宽你的编程视野，那么你必须学习宏。</p>
<p>就我所知，宏（采用Lisp语言的定义）目前仍然是Lisp独有的。一个原因是为了使用宏，你大概不得不让你的语言看上去像Lisp一样古怪。另一个可能的原因是，如果你想为自己的语言添上这种终极武器，你从此就不能声称自己发明了新语言，只能说发明了一种Lisp的新方言。</p>
<p>我把这件事当作笑话说出来，但是事实就是如此。如果你创造了一种新语言，其中有car、cdr、cons、quote、cond、atom、eq这样的功能，还有一种把函数写成列表的表示方法，那么在它们的基础上，你完全可以推导出Lisp语言的所有其他部分。事实上，Lisp语言就是这样定义的，John McCarthy把语言设计成这个样子，就是为了让这种推导成为可能。</p>
<p>六、</p>
<p>就算Lisp确实代表了目前主流编程语言不断靠近的一个方向，这是否意味着你就应该用它编程呢？</p>
<p>如果使用一种不那么强大的语言，你又会有多少损失呢？有时不采用最尖端的技术，不也是一种明智的选择吗？这么多人使用主流编程语言，这本身不也说明那些语言有可取之处吗？</p>
<p>另一方面，选择哪一种编程语言，许多项目是无所谓的，反正不同的语言都能完成工作。一般来说，条件越苛刻的项目，强大的编程语言就越能发挥作用。但是，无数的项目根本没有苛刻条件的限制。大多数的编程任务，可能只要写一些很小的程序，然后用胶水语言把这些小程序连起来就行了。你可以用自己熟悉的编程语言，或者用对于特定项目来说有着最强大函数库的语言，来写这些小程序。如果你只是需要在Windows应用程序之间传递数据，使用Visual Basic照样能达到目的。</p>
<p>那么，Lisp的编程优势体现在哪里呢？</p>
<p>七、</p>
<p>语言的编程能力越强大，写出来的程序就越短（当然不是指字符数量，而是指独立的语法单位）。</p>
<p>代码的数量很重要，因为开发一个程序耗费的时间，主要取决于程序的长度。如果同一个软件，一种语言写出来的代码比另一种语言长三倍，这意味着你开发它耗费的时间也会多三倍。而且即使你多雇佣人手，也无助于减少开发时间，因为当团队规模超过某个门槛时，再增加人手只会带来净损失。Fred Brooks在他的名著《人月神话》（The Mythical Man-Month）中，描述了这种现象，我的所见所闻印证了他的说法。</p>
<p>如果使用Lisp语言，能让程序变得多短？以Lisp和C的比较为例，我听到的大多数说法是C代码的长度是Lisp的7倍到10倍。但是最近，New Architect杂志上有一篇介绍ITA软件公司的文章，里面说&quot;一行Lisp代码相当于20行C代码&quot;，因为此文都是引用ITA总裁的话，所以我想这个数字来自ITA的编程实践。 如果真是这样，那么我们可以相信这句话。ITA的软件，不仅使用Lisp语言，还同时大量使用C和C++，所以这是他们的经验谈。</p>
<p>根据上面的这个数字，如果你与ITA竞争，而且你使用C语言开发软件，那么ITA的开发速度将比你快20倍。如果你需要一年时间实现某个功能，它只需要不到三星期。反过来说，如果某个新功能，它开发了三个月，那么你需要五年才能做出来。</p>
<p>你知道吗？上面的对比，还只是考虑到最好的情况。当我们只比较代码数量的时候，言下之意就是假设使用功能较弱的语言，也能开发出同样的软件。但是事实上，程序员使用某种语言能做到的事情，是有极限的。如果你想用一种低层次的语言，解决一个很难的问题，那么你将会面临各种情况极其复杂、乃至想不清楚的窘境。</p>
<p>所以，当我说假定你与ITA竞争，你用五年时间做出的东西，ITA在Lisp语言的帮助下只用三个月就完成了，我指的五年还是一切顺利、没有犯错误、也没有遇到太大麻烦的五年。事实上，按照大多数公司的实际情况，计划中五年完成的项目，很可能永远都不会完成。</p>
<p>我承认，上面的例子太极端。ITA似乎有一批非常聪明的黑客，而C语言又是一种很低层次的语言。但是，在一个高度竞争的市场中，即使开发速度只相差两三倍，也足以使得你永远处在落后的位置。</p>
<p><strong>附录：编程能力</strong></p>
<p>为了解释我所说的语言编程能力不一样，请考虑下面的问题。我们需要写一个函数，它能够生成累加器，即这个函数接受一个参数n，然后返回另一个函数，后者接受参数i，然后返回n增加（increment）了i后的值。</p>
<p>Common Lisp的写法如下：</p>
<blockquote><p>(defun foo (n)<br />
(lambda (i) (incf n i)))</p></blockquote>
<p>Ruby的写法几乎完全相同：</p>
<blockquote><p>def foo (n)<br />
lambda {|i| n += i } end</p></blockquote>
<p>Perl 5的写法则是：</p>
<blockquote><p>sub foo {<br />
my ($n) = @_;<br />
sub {$n += shift}<br />
}</p></blockquote>
<p>这比Lisp和Ruby的版本，有更多的语法元素，因为在Perl语言中，你不得不手工提取参数。</p>
<p>Smalltalk的写法稍微比Lisp和Ruby的长一点：</p>
<blockquote><p>foo: n<br />
|s|<br />
s := n.<br />
^[:i| s := s+i. ]</p></blockquote>
<p>因为在Smalltalk中，局部变量（lexical variable）是有效的，但是你无法给一个参数赋值，因此不得不设置了一个新变量，接受累加后的值。</p>
<p>Javascript的写法也比Lisp和Ruby稍微长一点，因为Javascript依然区分语句和表达式，所以你需要明确指定return语句，来返回一个值：</p>
<blockquote><p>function foo (n) {<br />
return function (i) {<br />
return n += i } }</p></blockquote>
<p>（实事求是地说，Perl也保留了语句和表达式的区别，但是使用了典型的Perl方式处理，使你可以省略return。）</p>
<p>如果想把Lisp/Ruby/Perl/Smalltalk/Javascript的版本改成Python，你会遇到一些限制。因为Python并不完全支持局部变量，你不得不创造一种数据结构，来接受n的值。而且尽管Python确实支持函数数据类型，但是没有一种字面量的表示方式（literal representation）可以生成函数（除非函数体只有一个表达式），所以你需要创造一个命名函数，把它返回。最后的写法如下：</p>
<blockquote><p>def foo (n):<br />
s = [n]<br />
def bar (i):<br />
s[0] += i<br />
return s[0]<br />
return bar</p></blockquote>
<p>Python用户完全可以合理地质疑，为什么不能写成下面这样：</p>
<blockquote><p>def foo (n):<br />
return lambda i: return n += i</p></blockquote>
<p>或者：</p>
<blockquote><p>def foo (n):<br />
lambda i: n += i</p></blockquote>
<p>我猜想，Python有一天会支持这样的写法。（如果你不想等到Python慢慢进化到更像Lisp，你总是可以直接......）</p>
<p>在面向对象编程的语言中，你能够在有限程度上模拟一个闭包（即一个函数，通过它可以引用由包含这个函数的代码所定义的变量）。你定义一个类（class），里面有一个方法和一个属性，用于替换封闭作用域（enclosing scope）中的所有变量。这有点类似于让程序员自己做代码分析，本来这应该是由支持局部作用域的编译器完成的。如果有多个函数，同时指向相同的变量，那么这种方法就会失效，但是在这个简单的例子中，它已经足够了。</p>
<p>Python高手看来也同意，这是解决这个问题的比较好的方法，写法如下：</p>
<blockquote><p>def foo (n):<br />
class acc:<br />
def _ _init_ _ (self, s):<br />
self.s = s<br />
def inc (self, i):<br />
self.s += i<br />
return self.s<br />
return acc (n).inc</p></blockquote>
<p>或者</p>
<blockquote><p>class foo:<br />
def _ _init_ _ (self, n):<br />
self.n = n<br />
def _ _call_ _ (self, i):<br />
self.n += i<br />
return self.n</p></blockquote>
<p>我添加这一段，原因是想避免Python爱好者说我误解这种语言。但是，在我看来，这两种写法好像都比第一个版本更复杂。你实际上就是在做同样的事，只不过划出了一个独立的区域，保存累加器函数，区别只是保存在对象的一个属性中，而不是保存在列表（list）的头（head）中。使用这些特殊的内部属性名（尤其是__call__），看上去并不像常规的解法，更像是一种破解。</p>
<p>在Perl和Python的较量中，Python黑客的观点似乎是认为Python比Perl更优雅，但是这个例子表明，最终来说，编程能力决定了优雅。Perl的写法更简单（包含更少的语法元素），尽管它的语法有一点丑陋。</p>
<p>其他语言怎么样？前文曾经提到过Fortran、C、C++、Java和Visual Basic，看上去使用它们，根本无法解决这个问题。Ken Anderson说，Java只能写出一个近似的解法：</p>
<blockquote><p>public interface Inttoint {<br />
public int call (int i);<br />
}</p>
<p>public static Inttoint foo (final int n) {<br />
return new Inttoint () {<br />
int s = n;<br />
public int call (int i) {<br />
s = s + i;<br />
return s;<br />
}};<br />
}</p></blockquote>
<p>这种写法不符合题目要求，因为它只对整数有效。</p>
<p>当然，我说使用其他语言无法解决这个问题，这句话并不完全正确。所有这些语言都是图灵等价的，这意味着严格地说，你能使用它们之中的任何一种语言，写出任何一个程序。那么，怎样才能做到这一点呢？就这个小小的例子而言，你可以使用这些不那么强大的语言，写一个Lisp解释器就行了。</p>
<p>这样做听上去好像开玩笑，但是在大型编程项目中，却不同程度地广泛存在。因此，有人把它总结出来，起名为&quot;格林斯潘第十定律&quot;（Greenspun&#039;s Tenth Rule）：</p>
<blockquote><p>&quot;任何C或Fortran程序复杂到一定程度之后，都会包含一个临时开发的、只有一半功能的、不完全符合规格的、到处都是bug的、运行速度很慢的Common Lisp实现。&quot;</p></blockquote>
<p>如果你想解决一个困难的问题，关键不是你使用的语言是否强大，而是好几个因素同时发挥作用（a）使用一种强大的语言，（b）为这个难题写一个事实上的解释器，或者（c）你自己变成这个难题的人肉编译器。在Python的例子中，这样的处理方法已经开始出现了，我们实际上就是自己写代码，模拟出编译器实现局部变量的功能。</p>
<p>这种实践不仅很普遍，而且已经制度化了。举例来说，在面向对象编程的世界中，我们大量听到&quot;模式&quot;（pattern）这个词，我觉得那些&quot;模式&quot;就是现实中的因素（c），也就是人肉编译器。 当我在自己的程序中，发现用到了模式，我觉得这就表明某个地方出错了。程序的形式，应该仅仅反映它所要解决的问题。代码中其他任何外加的形式，都是一个信号，（至少对我来说）表明我对问题的抽象还不够深，也经常提醒我，自己正在手工完成的事情，本应该写代码，通过宏的扩展自动实现。</p>
<p>（完）</p>
<p>原文网址：<a href="http://www.ruanyifeng.com/blog/2010/10/why_lisp_is_superior.html" target="_blank">http://www.ruanyifeng.com/blog/2010/10/why_lisp_is_superior.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/10/revenge-of-the-nerds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qt 4.7 发布了！</title>
		<link>http://www.linuxsong.org/2010/09/qt-4-7-0-release/</link>
		<comments>http://www.linuxsong.org/2010/09/qt-4-7-0-release/#comments</comments>
		<pubDate>Tue, 21 Sep 2010 16:16:28 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[qt]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=424</guid>
		<description><![CDATA[刚刚看到了Qt labs 上宣布Qt 4.7.0正式版发布了。

和Qt 4.6相比（Qt 4.6是2009年12月1 号发布的），Qt 4.7中主要的主要改进: <a href="http://www.linuxsong.org/2010/09/qt-4-7-0-release/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>刚刚看到了<a href="http://labs.qt.nokia.com/2010/09/21/qt-4-7-0-now-available/" target="_blank">Qt labs</a> 上宣布Qt 4.7.0正式版发布了。</p>
<p>和<a href="http://www.linuxsong.org/category/qt/">Qt</a> 4.6相比（Qt 4.6是2009年12月1 号发布的），Qt 4.7中主要的主要改进：</p>
<p><strong>Qt Quick </strong><br />
Qt Quick 是一种高级用户界面技术，使用它可轻松地创建供移动和嵌入式设备使用的动态触摸式界面和轻量级应用程序。三种全新的技术共同构成了 Qt Quick 用户界面创建工具包：一个改进的Qt Creator IDE、一种新增的简便易学的语言 (QML) 和一个新加入 Qt 库中名为 QtDeclarative 的模块，这些使得 Qt 更加便于不熟悉 C++ 的开发人员和设计人员使用。</p>
<p><strong>Qt WebKit 更新 </strong><br />
Qt 4.7 包含了使 Qt WebKit 集成的稳定性和性能均得到提升的更新。</p>
<p><strong>改进了性能和质量</strong><br />
Qt 4.7 和 Qt Creator 2.0 的发布给 Qt 开发框架和运作方式都带来了变化，旨在确保 Qt 的每一次发布都会带来速度更快、质量更好的产品：</p>
<ul>
<li>Qt 4.7 版将是首个由 Qt Continuous Integration 系统控制的 Qt 发布版本，该系统控制着将更改内容合入 Qt 的流程，防止了新错误的发生，并提高了产品的质量和稳定性。</li>
<li>在 Qt 开发部门内部成立了全新的性能团队，专门负责创建一套标准检查程序，用于阻止那些导致 Qt 性能下降的更改。</li>
</ul>
<p>Qt 4.7的<a href="http://qt.nokia.com/downloads" target="_blank">下载地址</a>。</p>
<p>另外估计Qt Creator 2.1正式版也快要发布了，等不急的朋友可以先下个 <a href="http://get.qt.nokia.com/qtcreator/snapshots/latest/" target="_blank">snapshots</a>试用下，我下载了一个感觉确实比2.0改进了不少。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/qt-4-7-0-release/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>代码优化概要</title>
		<link>http://www.linuxsong.org/2010/09/overlooked_ess_optimizing_code/</link>
		<comments>http://www.linuxsong.org/2010/09/overlooked_ess_optimizing_code/#comments</comments>
		<pubDate>Mon, 20 Sep 2010 03:31:06 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=422</guid>
		<description><![CDATA[我编写程序至今有35年了，我做了很多关于程序执行速度方面优化的工(一个示例)，我也看过其它人做的优化。我发现有两个最基本的优化技术总是被人所忽略。

注意，这两个技术并不是避免时机不成熟的优化。并不是把冒泡排序变成快速排序（算法优化）。也不是语言或是编译器的优化。也不是把 i*4写成i<<2 i*4的优化。 <a href="http://www.linuxsong.org/2010/09/overlooked_ess_optimizing_code/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>本文译自Dr. Dobb’s Blogger的Walter Bright写的《<a href="http://www.drdobbs.com/blog/archives/2010/09/overlooked_esse.html" target="_blank">Overlooked Essentials For Optimizing Code</a>》[转载］</p>
<hr />我编写程序至今有35年了，我做了很多关于程序执行速度方面优化的工(<a rel="external nofollow" href="http://biolpc22.york.ac.uk/wx/wxhatch/wxMSW_Compiler_choice.html" target="_blank">一个示例</a>)，我也看过其它人做的优化。我发现有两个最基本的优化技术总是被人所忽略。</p>
<p>注意，这两个技术并不是避免时机不成熟的优化。并不是把冒泡排序变成快速排序（算法优化）。也不是语言或是编译器的优化。也不是把 i*4写成i&lt;&lt;2 i*4的优化。</p>
<p><span id="more-422"></span>这两个技术是：</p>
<ol>
<li>使用 一个profiler。</li>
<li>查看程序执行时的汇编码。</li>
</ol>
<p>使用这两个技术的人将会成功地写出运行快的代码，不会使用这两个技术的人则不行。下面让我为你细细道来。</p>
<h2>使用一个 Profiler</h2>
<p>我们知道，程序运行时的90%的时间是用在了10%的代码上。我发现这并不准确。一次又一次地，我发现，几乎所有的程序会在1%的代码上花了99%的运行时间。但是，是哪个1%？一个好的Profiler可以告诉你这个答案。就算我们需要使用100个小时在这1%的代码上进行优化，也比使用100个小时在其它99%的代码上优化产生的效益要高得多得多。</p>
<p>问题是什么？人们不用profiler？不是。我工作过的一个地方使用了一个华丽而奢侈的Profiler，但是购买这个Profiler后，它的包装3年还是那么的暂新。为什么人们不用？我真的不知道。有一次，我和我的同事去了一个负载过大的交易所，我同事坚持说他知道哪里是瓶颈，毕竟，他是一个很有经验的专家。最终，我把我的Profiler在他的项目上运行了一下，我们发现那个瓶颈完全在一个意想不到的地方。</p>
<p>就像是赛车一样。团队是赢在传感器和日志上，这些东西提供了所有的一切。你可以调整一下赛车手的裤子以让其在比赛过程中更舒服，但是这不会让你赢得比赛，也不会让你更有竞争力。如果你不知道你的速度上不去是因为引擎、排气装置、空体动力学、轮胎气压，或是赛车手，那么你将无法获胜。编程为什么会不同呢？只要没有测量，你就永远无法进步。</p>
<p>这个世界上有太多可以使用的Profiler了。随便找一个你就可以看到你的函数的调用层次，调用的次数，以前每条代码的时间分解表（甚至可以到汇编级）。我看过太多的程序员回避使用Profiler，而是把时间花在那些无用的，错误的方向上的“优化”，而被其竞争对手所羞辱。（<strong>译者陈皓注</strong>：使用Profiler时，重点需要关注：1）花时间多的函数以优化其算法，2）调用次数巨多的函数——如果一个函数每秒被调用300K次，你只需要优化出0.001毫秒，那也是相当大的优化。这就是作者所谓的1%的代码占用了99%的CPU时间）</p>
<h2>查看汇编代码</h2>
<p>几年前，我有一个同事，Mary Bailey，她在华盛顿大学教矫正代数（remedial algebra），有一次，她在黑板上写下：</p>
<p><code>x + 3 = 5</code></p>
<p>然后问他的学生“求解x”，然后学生们不知道答案。于是她写下：</p>
<p><code>__ + 3 = 5</code></p>
<p>然后，再问学生“填空”，所有的学生都可以回答了。未知数x就像是一个有魔法的字母让大家都在想“x意味着代数，而我没有学过代数，所以我就不知道这个怎么做”。</p>
<p>汇编程序就是编程世界的代数。如果某人问我“inline函数是否被编译器展开了？”或是问我“如果我写下i*4，编译器会把其优化为左移位操作吗？”。这个时候，我都会建议他们看看编译器的汇编码。这样的回答是不是很粗暴和无用？通常，在我这样回答了提问者后，提问都通常都会说，对不起，我不知道什么是汇编！甚至C++的专家都会这么回答。</p>
<p>汇编语言是最简单的编程语言了（就算是和C++相比也是这样的），如：</p>
<p><code>ADD ESI,x</code></p>
<p>就是（C风格的代码）</p>
<p><code>ESI += x;</code></p>
<p>而：</p>
<p><code>CALL foo</code></p>
<p>则是：</p>
<p><code>foo();</code></p>
<p>细节因为CPU的种类而不同，但这就是其如何工作的。有时候，我们甚至都不需要细节，只需要看看汇编码的长啥样，然后和源代码比一比，你就可以知道汇编代码很多很多了。</p>
<p>那么，这又如何帮助代码优化？举个例子，我几年前认识一个程序员认为他应该去发现一个新的更快的算法。他有一个benchmark来证明这个算法，并且其写了一篇非常漂亮的文章关于他的这个算法。但是，有人看了一下其原来算法以及新算法的汇编，发现了他的改进版本的算法允许其编译器把两个除法操作变成了一个。这和算法真的没有什么关系。我们知道除法操作是一个很昂贵的操作，并且其还在一个内嵌循环中，所以，他的改进版的算法当然要快一些。只需要在原来的算法上做一点点小的改动——使用一个除法操作，那么其原来的算法将会和新的一样快。而他的新发现什么也不是。</p>
<p>下一个例子，一个D用户张贴了一个 benchmark 来显示 dmd (Digital Mars D 编译器)在整型算法上的很糟糕，而ldc (LLVM D 编译器) 就好很多了。对于这样的结果，其相当的有意见。我迅速地看了一下汇编，发现两个编译器编译出来相当的一致，并没有什么明显的东西要对2：1这么大的不同而负责。但是我们看到有一个对long型整数的除法，这个除法调用了运行库。而这个库成为消耗时间的杀手，其它所有的加减法都没有速度上的影响。出乎意料地，benchmark 和算法代码生成一点关系也没有，完全就是long型整数的除法的问题。这暴露了在dmd的运行库中的long型除法的实现很差。修正后就可以提高速度。所以，这和编译器没有什么关系，但是如果不看汇编，你将无法发现这一切。</p>
<p>查看汇编代码经常会给你一些意想不到的东西让你知道为什么程序的性能是那样。一些意想不到的函数调用，预料不到的自傲，以及不应该存在的东西，等等其实所有的一切。但也不需要成为一个汇编代码的黑客才能干的事。</p>
<h2>结论</h2>
<p>如果你觉得需要程序有更好的执行速度，那么，最基本的方法就是使用一个profiler和愿意去查看一下其汇编代码以找到程序的瓶颈。只有找到了程序的瓶颈，此时才是真正在思考如何去改进的时候，比如思考一个更好的算法，使用更快的语言优化，等等。</p>
<p>常规的做法是制胜法宝是挑选一个最佳的算法而不是进行微优化。虽然这种做法是无可异议的，但是有两件事情是学校没有教给你而需要你重点注意的。第一个也是最重要的，如果你优化的算法没没有参与到你程序性能中的算法，那么你优化他只是在浪费时间和精力，并且还转移了你的注意力让你错过了应该要去优化的部分。第二点，算法的性能总和处理的数据密切相关的，就算是冒泡排序有那么多的笑柄，但是如果其处理的数据基本是排好序的，只有其中几个数据是未排序的，那么冒泡排序也是所有排序算法里性能最好的。所以，担心没有使用好的算法而不去测量，只会浪费时间，无论是你的还是计算机的。</p>
<p>就好像赛车零件的订购速底是不会让你更靠进冠军（就算是你正确安装零件也不会），没有Profiler，你不会知道问题在哪里，不去看汇编，你可能知道问题所在，但你往往不知道为什么。</p>
<p>本文转自：  <a rel="external nofollow" href="http://coolshell.cn/articles/2967.html" target="_blank">http://coolshell.cn/articles/2967.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/overlooked_ess_optimizing_code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>QT的Graphics View框架与坐标系</title>
		<link>http://www.linuxsong.org/2010/09/qt-graphics-view/</link>
		<comments>http://www.linuxsong.org/2010/09/qt-graphics-view/#comments</comments>
		<pubDate>Fri, 17 Sep 2010 07:43:20 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[qt]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=412</guid>
		<description><![CDATA[Graphics View提供了一个界面，它既可以管理大数量的定制2D graphical items，又可与它们交互，有一个view widget可以把这些项绘制出来，并支持旋转与缩放。这个柜架也包含一个事件传播结构，对于在scene中的这些items,它具有双精度的交互能力。 Items能处理键盘事件，鼠标的按，移动、释放、双击事件，也可以跟踪鼠标移动。Graphics View使用BSP树来提供对item的快速查找，使用这种技术，它可以实时地绘制大规模场景，甚至以百万items计。Graphics View在Qt 4.2中被引用，它替代了它的前辈QCanvas。 <a href="http://www.linuxsong.org/2010/09/qt-graphics-view/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>
<p><span><span>Graphics View提供了一个界面，它既可以管理大数量的定制2D graphical items，又可与它们交互，有一个view widget可以把这些项绘制出来，并支持旋转与缩放。这个柜架也包含一个事件传播结构，对于在scene中的这些items,它具有双精度的交互能力。 Items能处理键盘事件，鼠标的按，移动、释放、双击事件，也可以跟踪鼠标移动。Graphics View使用BSP树来提供对item的快速查找，使用这种技术，它可以实时地绘制大规模场景，甚至以百万items计。Graphics View在<a title="Qt" href="http://www.linuxsong.org/category/qt/">Qt</a> 4.2中被引用，它替代了它的前辈QCanvas。</span></span></p>
<div><span><span><span><strong><em><span id="more-412"></span>Graphics View的体系结构</em><br />
</strong></span><br />
Graphics View提供的是一种类似于Qt model-view的编程。多个views可以监视同一个场景，而场景包含多个具有多种几何外形的items。<br />
<span style="color: #0000ff;"><span><strong>场景</strong></span></span><br />
<span style="color: #0000ff;">QGraphicsScene</span> 表示Graphics View中的场景，它有以下职责：<br />
为管理大量的items提供一个快速的接口。<br />
传播事件到每个item。<br />
管理item的状态，例如选择，焦点处理。<br />
提供未经变换的渲染功能，主要用于打印。<br />
场景作为<span style="color: #0000ff;">QGraphicsItem</span>对象的容器。通过调用<span style="color: #0000ff;">QgraphicsScene</span>::<span style="color: #ff00ff;">addItem</span>()把这些Items加入到场景中。可以使用众多的查找函数来获取特定的items。<span style="color: #0000ff;">QGraphicsScene</span>:<span style="color: #ff00ff;">items</span>()与它的许多重载函数可获取那些与点、矩形，多边形，向量路径等相交或是有包含有关系的items。<span style="color: #0000ff;">QGraphicsScene</span>::<span style="color: #ff00ff;">itemAt</span>()返回特定上最顶端的item。所有的item查找函数都以出栈序列返回（也就是说，第一个返回的是最顶端的，最后一个返回的是最底端的）。<br />
<span style="color: #0000ff;">QGraphicsScene</span> scene;<br />
<span style="color: #0000ff;">QGraphicsRectItem</span> *rect=scene.<span style="color: #ff00ff;">addRect</span>(QRectF(0,0,100,100));<br />
<span style="color: #0000ff;">QGraphicsItem</span> *item=scene.<span style="color: #ff00ff;">itemAt</span>(50,50);<br />
//item==rect;<br />
<span style="color: #0000ff;">QGraphicsScene</span>的事件传播结构会把场景事件投递到items，也管理多个items之间的传递。假如场景收到了鼠标在某个位置press事件，场景会把这个事件投递给处在那个位置的item。QGraphicsScene也管理某种item状态，像选择与焦点。你可以通过调用<span style="color: #0000ff;">QGraphicsScene</span>::<span style="color: #ff00ff;">setSelectionArea</span>()来选择items，它需要提供一个任意的形状为参数。这个函数也作为在QGraphicsView实现橡皮筋选择功能的一个基础。为得到这些已经被选择的items,调用QGraphicsScene::<span style="color: #ff00ff;">selectedItem</span>()。另一个状态处理是是否一个item拥有键盘输入焦点。你可以调用QGraphicsScene::<span style="color: #ff00ff;">setFocusItem</span>()或QGraphics::<span style="color: #ff00ff;">setFocus</span>()来设定焦点，也可用QGraphicsScene::<span style="color: #ff00ff;">focusItem</span>()来得到当前拥有焦点的那个item。最后，<span style="color: #0000ff;">QGraphicsScene</span>允许你通过调用QGraphicsScene::<span style="color: #ff00ff;">render</span>()函数把部分场景送到绘图设备进行渲染。<br />
<span style="color: #0000ff;"><span><strong>视图<br />
</strong></span></span><span style="color: #0000ff;">QGraphicsView</span>提供了视图部件，它可视化场景中的内容。你可以联结多个视图到同一个场景，对这个相同的数据集提供几个视口。视口部件是一个滚动区域，它提供了滚动条以对大场景进行浏览。为了使用OpenGL,你应该调用QGraphicsView::<span style="color: #ff00ff;">setViewport</span>()来把一个QGLWidget设为视口。视图从键盘，鼠标接收输入事件，在发送这些事件到场景之前，会对这些事件进行适当的翻译（把事件坐标转换成对应的场景坐标）。<br />
利用转换矩阵，QGraphicsView::<span style="color: #ff00ff;">matrix</span>(),视图可变换场景的坐标系统。这允许高级的导航特性，如缩放，旋转。为了方便，QGraphicsView也提供了在视图与场景之间进行坐标转换的函数：QGraphicsView::<span style="color: #ff00ff;">mapToScene</span>(),QGraphicsView::<span style="color: #ff00ff;">mapForScene</span>()。<br />
<a href="http://www.linuxsong.org/wp-content/uploads/2010/09/r_graphicsview-view.png"><img class="alignnone size-full wp-image-419" title="r_graphicsview-view" src="http://www.linuxsong.org/wp-content/uploads/2010/09/r_graphicsview-view.png" alt="" width="354" height="208" /></a></span></span></div>
<div><span><span><span style="color: #0000ff;"><span>The Item<br />
</span></span><span style="color: #0000ff;">QGraphicsItem</span> 是场景中图形items的基类。Graphics View 提供了一些标准的、用于典型形状的items。像矩形(QGraphicsRectItem),椭圆（QGraphicsEllipseItem),文本 (QGraphicsTextItem),当你写定制的item时，那些最有用的一些QGraphicsItem特性也是有效的。除此这 外，QGraphicsItem支持以下特性：<br />
*鼠标按、移动、释放、双击事件，鼠标悬停事件，滚轮事件，弹出菜单事件。<br />
*键盘输入焦点，键盘事件。<br />
*拖拽<br />
*组，包括父子关系，使用QGraphicsItemGroup<br />
*碰撞检测<br />
Items如同<span style="color: #0000ff;">QGraphicsView</span>一样，位于本地坐标系，它也为item与场景之间，item与item之间的坐标转换提供许多工具函数。而且，也像QGraphicsView一样，它使用矩阵来变换它的坐标系统：QGraphicsItem::matrix()。它对旋转与缩放单个的Item比较有用。<br />
Items可以包含别的items(孩子）。父items的转换被它的子孙所继承。然而，它的所有函数（也就是，QGraphicsItem::<span style="color: #ff00ff;">contains</span>(),QGraphicsItem::<span style="color: #ff00ff;">boundingRect</span>(),QGraphicsItem::<span style="color: #ff00ff;">collidesWith</span>()),不会积累这些转换，依然在本地坐标下工作。<br />
<span style="color: #0000ff;">QGraphicsItem</span>通过QGraphicsItem::<span style="color: #ff00ff;">shape</span>()，QGraphicsItem::<span style="color: #ff00ff;">collideWith</span>())来支持碰撞检测。这两个都是虚函数。从shape()返回你的item的形状（以本地坐标<span style="color: #0000ff;">QPainterPath</span>表示），QGraphicsItem会为你处理所有的碰撞检测。假如你想提供自己的碰撞检测，你应该重新实现QGraphicsItem::<span style="color: #ff00ff;">collideWith</span>()。</span></span></div>
<div><span><span style="font-size: large;"><em>Graphics View 坐标系统</em></span><br />
Graphics View基于笛卡尔坐标系。item在场景中的位置与几何形状通过x,y坐标表示。当使用未经变形的视图来观察场景时，场景中的一个单位等于屏幕上的一个 像素。在Graphics View中有三个有效的坐标系统：Item坐标系，场景坐标系，视图坐标系。为了简化你的实现，Graphics View提供了方便的函数，允许三个坐标系之间相互映射。<br />
当渲染时，Graphics View的场景坐标对应于QPainter的逻辑坐标，视图坐标与设备坐标相同。</p>
<p><a href="http://www.linuxsong.org/wp-content/uploads/2010/09/o_graphicsview-parentchild.png"><img class="alignnone size-full wp-image-418" title="o_graphicsview-parentchild" src="http://www.linuxsong.org/wp-content/uploads/2010/09/o_graphicsview-parentchild.png" alt="" width="200" height="200" /></a></p>
<p></span></div>
<div><span><strong>Item坐标<br />
</strong>Items位于它们自己的坐标系中。它的坐标都以点(0,0)为中心点，这也是所有变换的中心点。在item坐标系中的几何图元，经常被称为item点，item线，item矩形。当创建一个定制的item,item坐标是所需要考虑的。<span style="color: #0000ff;">QGraphicsScene</span>与<span style="color: #0000ff;">QGraphicsView</span>可以为你执行所有转换，这使得实现定制的item变得容易。举例来说，假如你收到鼠标按或是拖进入事件，事件的位置以item坐标的形式给出。<span style="color: #0000ff;">QGraphicsItem</span>::<span style="color: #0000ff;">contain</span>()虚函数，当某个点的位置在你的item范围内时，返回true,否则返回false。这个点参数使用item坐标，相似地，item的包围矩形与形状也使用item坐标。<br />
Item位置指的是item的中心点在它父亲的坐标系中的坐标。以这种思想来看，场景指的就是那些祖先最少的item的“父亲”。最上级的Item位置就是在场景中的位置。<br />
子 坐标与父坐标之间是相关的，假如孩子未经变换，子坐标与父坐标之间的差值等于在父坐标系下，父item与子item之间的距离。例如，假如一个未经变换的 子item位置与其父item的中心重合，那么这两个item的坐标系统完全相同。如果孩子的位置是（10，0），那么孩子坐标系中的(0,10)点，对 应于父坐标系中的（10，10）点。<br />
因为item的位置与变换是相对于父item的，子item的坐标不会被父亲的变换影响，尽管父item的变 换隐含地对子item做了变换。在上面的例子中，即使父item旋转，缩放，子item的(0,10)点依然对应于父item的(10,10)点。然而， 相对于场景来讲，子item会遵循父item的变换。假如父item被缩放(2X,2X),子item的位置在场景中的坐标是（20，0），它的 （10，0）点则与场景中的（40，0）对应 。除了QGraphicsItem::pos()，QGraphicsItem的函数以Item坐标工作，如一个item&#039;s包围矩形总是以item坐标 的形式给出。</span></div>
<div><span><strong>场景坐标<br />
</strong>场景坐标系统描述了每个最顶级item的位置，也是从视图向场景投递场景事件的基础。场景中的每个item有场景位置与包围矩形（<span style="color: #0000ff;">QGraphicsItem</span>::<span style="color: #0000ff;">scenePos(),</span><span style="color: #0000ff;">QGraphicsItem::sceneBoundingRect()),</span> 另外，它有自己本地item位置与包围矩形。场景位置描述了item在场景坐标下的位置，它的场景包围矩形则用于QGraphicsScene决定场景中哪块区域发生了变化。场景中的变化通过QGraphicsScene::<span style="color: #0000ff;">changed</span>()信号来通知，它的参数是场景矩形列表。</span></div>
<div><span><strong>视图坐标<br />
</strong>视图坐标是widget的坐 标，视图坐标中每个单位对应一个像素。这种坐标的特殊之处在于它是相对于widget或是视口的，不会被所观察的场景所影响。QGraphicsView 的视口的左上角总是（0，0），右下角总是(视口宽，视口高）。所有的鼠标事件与拖拽事件，最初以视图坐标表示，就应该把这些坐标映射到场景坐标以便与 item交互。</span></div>
<div><span><strong>坐标映射</strong><br />
经常，处理场景中item时，在场景与item之间，item与item之间，视图与场景之间进行坐标映射，形状映射是非常有用的。举例来讲，当你在<span style="color: #0000ff;">QGraphicsView</span>的视口中点击鼠标时，你应该通过调用<span style="color: #0000ff;">QGraphicsView::mapToScence()</span>与<span style="color: #0000ff;">QGraphicsScene::itemAt()</span>来获知光标下是场景中的哪个item。假如你想获知一个item位于视口中的什么位置，你应该先在item上调用<span style="color: #0000ff;">QGraphicsItem::mapToScene(),</span>然后调用<span style="color: #0000ff;">QGraphicsView::mapFromScene()。</span>最后，假如你想在一个视图椭圆中有哪些items,你应该把<span style="color: #0000ff;">QPainterPath</span>传递到mapToScene(),然后再把映射后的路径传递到<span style="color: #0000ff;">QGraphicsScene::items()。</span><br />
你可以调用<span style="color: #0000ff;">QGraphicsItem::mapToScene()</span>与<span style="color: #0000ff;">QGraphicsItem::mapFromScene()</span>在item与场景之间进行坐标与形状的映射。也可以在item与其父item之间通过<span style="color: #0000ff;">QGraphicsItem::mapToParent()</span>与<span style="color: #0000ff;">QGraphicsItem::mapFromItem()</span>进行映射。所有映射函数可以包括点，矩形，多边形，路径。视图与场景之间的映射也与此类似。对于从视图与item之间的映射，你应该首先映射到场景，然后再从场景向item进行映射。</span></div>
<div>
<p><span><span style="color: #0000ff;"><em>关键特性</em></span></span></p>
<p><strong>缩放与旋转</strong><br />
QGraphicsView通过QGraphicsView::setMatrix()支持同QPainter一样的仿射变换，通过对一个视图应用变换，你可以很容易地支持普通的导航特性如缩放与旋转。下面是一个例子：<br />
class View::public QGraphicsView<br />
{<br />
Q_OBJECT<br />
//.....<br />
public slots:<br />
void zoomIn() {scale(1.2,1.2);}<br />
void zoomOut() {scale(1/1.2,1/1.2);}<br />
void rotateLeft() {rotate(-10);}<br />
void rotateRight() {rotate(10);}<br />
};<br />
这些槽应与QToolButtons联接，并使autoRepeat有效。当对视图变换时，QGraphicsView会对视图中心进行校正。</p>
</div>
<div><span><strong>拖拽<br />
</strong>因为QGraphicsView继承自 QWidget,它也提供了像QWidget那样的拖拽功能，另处，为了方便，Graphics View柜架也为场景，每个item提供拖拽支持。当视图接收到拖拽事件，它可翻译为QGraphicsSceneDragDropEvent,再发送到 场景。场景接管这个事件，把它发送到光标下接受拖拽的第一个item。<br />
从一个item开始拖拽时，创建一个QDrag对象，传递开始拖拽的那个 widget的指针。Items可以同时被多个视图观察，但只有一个视图可以开始拖拽。拖拽在多数情况下是从按下鼠标或是移动鼠标开始的，因此，在 mousePressEvent()或mouseMoveEvent()中，你可以从事件中得到那个原始的widget指针，例如：<br />
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)<br />
{<br />
QMimeData *data=new QMimeData;<br />
data-&gt;setColor(Qt::green);<br />
QDrag *drag=new QDrag(event-&gt;widget());<br />
drag-&gt;setMimeData(data);<br />
drag-&gt;start();<br />
}<br />
为 了在场景中载取拖拽事件，你应重新实现QGraphicsScene::dragEnterEvent()和在QGraphicsItem的子类里任何与 你特定场景需要的事件处理器。items也可以通过调用QGraphicsItem::setAcceptDrops()获得拖拽支持，为了处理将要进行 的拖拽，你需要重新实现 QGraphicsItem::dragEnterEvent(),QGraphicsItem::dragMoveEvent(),QGraphicsItem::dragLeaveEvent() 和QGraphicsItem::dropEvent()。<br />
<strong>光标与工具提示</strong><br />
像QWidget一样，<span style="color: #0000ff;">QGraphicsItem</span>也 支持光标（QgraphicsItem::setCursor)与工具提示(QGraphicsItem::setToolTip())。当光标进入到 item的区域，光标与工具提示被QGraphicsView激活（通过调用QGraphicsItem::contains()检测）。你也可以直接在 视图上设置一个缺省光标(QGraphicsView::setCursor)。<br />
<strong>动画</strong><br />
Graphics View支持几种级别的动画。你可以很容易地通过把<span style="color: #0000ff;">QGraphicsItemAnimatoin</span>与你的item联结来<br />
装配出动画路径,这允许以时间线来控制动画，在所有平台上以稳定的速率运作。QGraphicsItemAnimation允许你为item的位置，旋转，缩放，剪切，变换等产生一条路径，动画可以用QSlider来控制，或更为普遍使用的QTimeLine。<br />
另一种是从QObject和QGraphicsItem继承，item可以设置自己的定时器，以在QObject::timeEvent()中增加步进的方式来控制动画。<br />
第三种，是通过调用QGraphicsScene::advance()来推进场景，它又依次调用QGraphicsItem::advance().<br />
<strong>OpenGL渲染<br />
</strong>为了使用OpenGL渲染，你要设置一个新的QGLWidget作为QGraphicsView的视口：QGraphicsView::setViewPort()。假如你让OpenGL提供反锯齿功能，你需要OpenGL采样缓冲支持。<br />
QGraphicsView view(&amp;scene);<br />
view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));<br />
<strong>Item组<br />
</strong>通过把一个item做为另一个item的孩子，你可以得到item组的大多数本质特性：这些items会一起移动，所有变换<br />
会从父到子传递。QGraphicsItem也可以为它的孩子处理所有的事件，这样就允许以父亲代表它所有的孩子，可以有效地把所有的items看作一个整体。<br />
另外，<span style="color: #0000ff;">QGraphicsItemGroup</span>是一个特殊的item,它既对孩子事件进行处理又有一个接口把items从一个组中增加和删除。把一个item加到<br />
QGraphicsItemGroup仍会保留item的原始位置与变换，而给一个item重新指定父item则会让item根据其新的父亲重新定位。可以用QGraphicsScene::createItemGroup()建组。</span></div>
<div><span><br />
</span></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/qt-graphics-view/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>程序性能优化</title>
		<link>http://www.linuxsong.org/2010/09/interviewbible-1-speed-optimization/</link>
		<comments>http://www.linuxsong.org/2010/09/interviewbible-1-speed-optimization/#comments</comments>
		<pubDate>Sun, 12 Sep 2010 12:30:28 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=406</guid>
		<description><![CDATA[开场白：最近公司招人，接触了一批形形色色的工程师，但感觉绝大多数人基础都很差，在某次TL的讨论之后，就想到了写一个《面试宝典》系列。

卷首语：这个《面试宝典》名字是我一贯的标题党风格，其实在内容上都是很简单、很基础的——都是那种“不知道这些就别出来混”的知识点。所以，高手/牛人可以到此打住了——端咖啡——送客~~~ <a href="http://www.linuxsong.org/2010/09/interviewbible-1-speed-optimization/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>开场白：最近公司招人，接触了一批形形色色的工程师，但感觉绝大多数人基础都很差，在某次TL的讨论之后，就想到了写一个《面试宝典》系列。</p>
<p>卷首语：这个《面试宝典》名字是我一贯的标题党风格，其实在内容上都是很简单、很基础的——都是那种“不知道这些就别出来混”的知识点。所以，高手/牛人可以到此打住了——端咖啡——送客~~~</p>
<p>作/译序：此文可能会持续更新直到补充得比较完整为止，有什么要补充的欢迎留言<br />
<span id="more-406"></span></p>
<h1>基础原则之万能利器：Profiling</h1>
<p>如何测量距离？——直尺/游标卡尺/卷尺/etc<br />
如何测量电压？——电压表/万用表<br />
如何测量时间？——钟表/秒表<br />
如何测量温度？——温度计<br />
如何测量质量？——天平/台秤/etc<br />
如何测量程序性能？——Profiler !</p>
<p>是的，Profiler就是这么一件又基础又重要的工具（小标题里的“万能”是标题党了）。要回答“程序为什么慢/什么地方慢/到底有多慢”等问题，离不开Profiler，就像测量长度离不开尺子一样。 (嗯，那位要测地月距离的，别抬杠了，请移步回你的实验室吧，我知道你是rocket scientist，高科技呢:)</p>
<p>可以使用软件Profiler，也可以使用硬件来做Profiling（DSO/Logic Analyzer/Hybrid DSO/Timer），在什么都没有的情况下，至少也可以输出Log或者用其它方式来达到Profiling的目的。<br />
一般来说，测量工具对被测目标应该没有影响（或者极小），但是软件的Profiler却对被测目标有一定程度的影响——以此为代价，换来的是方便和廉价（免费）。</p>
<p>在系统外部对性能进行测试，也是一种测量性能的方式，只不过它所测量的粒度很大，不能用于分析源码，只能用于比较不同源码的优劣。</p>
<h1>如何进行性能优化？</h1>
<h2>基本原则</h2>
<p>原则：使用Profiler来找出最影响性能的那些程序，重点优化它们<br />
分类：基本知识<br />
提示：时刻记心间</p>
<p>原则：无论尝试了何种优化，都要使用profiler来测量这种优化<br />
分类：基本知识<br />
提示：时刻记心间</p>
<p>原则：二八原则<br />
分类：基本知识<br />
提示：运行中的软件有一种典型情况：20%的程序占了80%的运行时间，优化的重点是这20%的程序（20%和80%为约数）。应当使用Profiler来找出它们，改进它们并继续用Profiler测量改进的效果——在没有明显的性能热点的时候，就要考虑换一种思路进行优化了：比如使用“硬件优化”（参见下文）。在切换了设计和体系结构后，之前做的profiling也有可能会失效，要重新进行测量，每一种判断和决策必须得到证据的支持。</p>
<h2>硬件优化</h2>
<p>原则：使用更快的设备/通讯协议<br />
分类：硬件优化<br />
提示：有时候需要尝试跳出软件优化的框框来想问题<br />
范例：使用SSD代替机械硬盘，在IO速率上你能提高2－5倍（在无RAID的情况下），在寻道时间上你能提高4个数量级（WOW!）</p>
<p>原则：对硬件友好<br />
分类：硬件优化<br />
范例：利用SIMD指令（如视频编码器）；对Cache友好（数据Cache和指令Cache）；对流水线友好（比如threaded code，削减分枝预测失误。注意这里的thread不是“线程”，是“线索化”）；使用硬盘的外圈以达到更大的速度；</p>
<p>原则：利用硬件加速<br />
分类：硬件优化<br />
范例：使用D3D/OpenGL，使用GPU计算（如FFT），使用DMA不使用PIO，使用ASIC代替CPU进行专用计算（如常见的视频编解码专用芯片，还有加解密芯片），使用DSP对高负载数据进行处理（或预处理）</p>
<h2>设计优化</h2>
<p>原则：使用分布式计算<br />
分类：设计优化<br />
范例：使用Hadoop；使用Memcached</p>
<p>原则：改进业务逻辑<br />
分类：设计优化<br />
备注：暂不提供例子</p>
<p>原则：批量操作<br />
分类：设计优化<br />
备注：其实是业务逻辑优化的一个特例</p>
<p>原则：对输入进行缓存<br />
分类：设计优化，缓存<br />
范例：依靠CPU Cache/阵列Cache/磁盘Cache/磁盘/操作系统Cache/程序管理的Cache/专用Cache服务器等，对输入进行缓存，以加快速度</p>
<p>原则：对中间结果进行缓存<br />
分类：设计优化，缓存<br />
范例：预装载/索引/suffix tree</p>
<p>原则：对输出进行缓存<br />
分类：设计优化，缓存<br />
范例：使用buffer批量输出（匹配软件计算速度和设备的速度）</p>
<p>原则：空间换时间<br />
分类：设计优化<br />
范例：在DB中使用denormalized data<br />
备注：这是一个比较通用的原则，Cache也是空间换时间。</p>
<p>原则：使用内存池<br />
分类：设计优化，内存</p>
<p>原则：使用更好/更合适的GC算法<br />
分类：设计优化，内存</p>
<p>原则：控制内存交换<br />
分类：设计优化，内存</p>
<p>原则：吸收掉不必要的界面更新<br />
分类：设计优化，GUI</p>
<p>原则：只重绘更新的区域<br />
分类：设计优化，GUI</p>
<p>原则：对可视化的结果进行缓存<br />
分类：设计优化，GUI<br />
备注：中间结果缓存的一个特例</p>
<p>原则：parallelism–利用多CPU/多核心<br />
分类：设计优化，并行</p>
<p>原则：利用并发(concurrency)<br />
分类：设计优化，并行<br />
提示：在单CPU上跑并发也能提高性能<br />
范例：线程池</p>
<p>原则：选取合适的锁类型<br />
分类：设计优化，并行，锁<br />
范例：使用读写锁</p>
<p>原则：使用消息<br />
分类：设计优化，并行，锁<br />
备注：可以减少共享数据和锁</p>
<p>原则：使用异步模型<br />
分类：设计优化，并行，锁<br />
范例：使用epoll/kqueue等；nginx</p>
<p>原则：消除锁<br />
分类：设计优化，并行，锁<br />
提示：试用无锁的算法/数据结构/算法</p>
<p>原则：使用FP Paradigm<br />
分类：设计优化，并行<br />
提示：彪悍的FP不需要提示</p>
<h2>算法优化</h2>
<p>（其实算法往往是包含在设计中的）</p>
<p>原则：使用更优的算法，减小算法的阶<br />
分类：算法优化<br />
范例：使用BM/Sunday算法代替BF算法</p>
<p>原则：减小算法的常量（BigOO）<br />
分类：算法优化<br />
范例：使用sentry来编写double link list</p>
<p>原则：处理好Big Omega和BigO，使算法在“最坏的时候也不要太坏”<br />
分类：算法优化<br />
范例：quick sort，避免O(N*N)的情况</p>
<p>原则：使用更优的数据结构<br />
分类：算法优化<br />
范例：AVL Tree–&gt;Hash Table–&gt;Ternary Search Tree<br />
备注：其实有些重复，主要是为了区分狭义的“算法”和“数据结构”</p>
<p>原则：寻找并行化算法<br />
分类：算法优化<br />
备注：和前面的parallelism有些重复，这个更多的是指可并行的算法而不是其它意义上的并行</p>
<h2>小技巧</h2>
<p>原则：编译器优化<br />
分类：小技巧<br />
范例：使用Intel的编译器，使用Intel的性能库IPP<br />
备注：注意Proebsting定律</p>
<p>原则：树递归–&gt;尾递归<br />
分类：小技巧<br />
备注：在许多语言中，尾递归是不需要栈的，自动转换成迭代了（例如在erlang中用尾递归实现无限循环）</p>
<p>原则：少用小技巧，以免妨碍大粒度上的性能优化<br />
分类：小技巧<br />
提示：主要是指那些影响并行计算的小技巧，或者那些没有使用profiler进行测量就草率进行的盲目优化</p>
<p>原则：远离“神话”<br />
分类：小技巧<br />
提示：有些流传的关于优化的神化不足信，“是骡子是马拉出来骝骝”，一切在profiler下见真章<br />
范例：比如“大块内存分配非常慢”的神话（甚至有过一个人估计数量级的时候说：分配10M内存至少要1秒钟），比如“虚函数导致效率低”的神话，比如“解释运行比编译慢”的神话，等等</p>
<p>原则：使用Lazy Evaluation<br />
分类：小技巧</p>
<p>原则：避免大对象复制<br />
分类：小技巧<br />
范例：RVO/RVal Ref</p>
<p>原则：预译码/编译成本地代码<br />
分类：小技巧，解释器和VM<br />
范例：PYC/HipHop</p>
<p>原则：混合使用各有优势的语言<br />
分类：小技巧<br />
范例：C里使用汇编；Python里使用C模块；</p>
<p>原则：使用二进制优化器<br />
分类：小技巧<br />
范例：JIT就是最出名的一种二进制优化；Win32SDK的BitBlt()函数也是；</p>
<p>……</p>
<p>重温：无论尝试了何种优化，都要使用profiler来测量这种优化<br />
分类：红宝书<br />
提示：时刻记心间</p>
<p>本文转自：<a title="CS巴别塔" rel="external nofollow" href="http://csbabel.wordpress.com/2010/04/29/interviewbible-1-speed-optimization/" target="_blank">CS巴别塔</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/interviewbible-1-speed-optimization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>让美女时钟做你的桌面</title>
		<link>http://www.linuxsong.org/2010/09/girl-clock-wallpaper/</link>
		<comments>http://www.linuxsong.org/2010/09/girl-clock-wallpaper/#comments</comments>
		<pubDate>Sun, 12 Sep 2010 04:13:19 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[shell]]></category>
		<category><![CDATA[gnome]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=301</guid>
		<description><![CDATA[前两天写了一篇文章：Linux命令行下更改桌面背景(GNOME环境)，这几天刚好看到了搜道网站的美女时钟，上面的美女图片是每分钟换一次，想了想要是能把上面的报时的美女图片当做桌面，为你报时，岂不是很好玩？ <a href="http://www.linuxsong.org/2010/09/girl-clock-wallpaper/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>前两天写了一篇文章：<a title="Linux命令行下更改桌面背景(GNOME环境)" href="http://www.linuxsong.org/2010/09/gnome-change-wallpaper-with-command-line/" target="_blank">Linux命令行下更改桌面背景(GNOME环境)</a>，这几天刚好看到了<a title="搜道" rel="external nofollow" href="http://www.sodao.com/" target="_blank">搜道</a>网站的美女时钟，上面的美女图片是每分钟换一次，想了想要是能把上面的报时的美女图片当做桌面，为你报时，岂不是很好玩？</p>
<p>于是研究了下那个网站，写了个<a title="Shell" href="http://www.linuxsong.org/category/shell/">Shell</a>脚本，实现了上面的想法，脚本如下：</p>
<p><span id="more-301"></span></p>
<pre class="brush: bash;">

#!/bin/bash
#Author: LinuxSong
#Blog: http://www.linuxsong.org

gconftool=`which gconftool-2`

if [ ! -x  &quot;$gconftool&quot; ]; then
    echo 没有找到[gconftool-2]
    exit 1
fi

imagePath=/tmp/sodao

if [ ! -d &quot;$imagePath&quot; ]; then
    mkdir -p $imagePath
    if [ ! -d &quot;$imagePath&quot; ]; then
        echo 创建[$imagePath]目录失败
        exit 1
    fi
fi

url=&quot;http://www.sodao.com/app/ShowTime/gt?pcs_id=1&amp;size=3&quot;
#下面这个地址是青岛版，上面那个是杭州的
#url=&quot;http://www.sodao.com/app/ShowTime/gt1?pcs_id=9&amp;size=3&quot;

while [ true ]
do
    imgUrl=`curl --connect-timeout 20 --retry 2 -s $url  |awk -F, '{print $5}' | awk -F\&quot; '{print $4}'`
    if [ -n &quot;$imgUrl&quot; ]; then
        fileName=`echo $imgUrl | awk -F\/ '{print $NF}'`
        if [ -f &quot;$imagePath/$fileName&quot; -a &quot;$fileName&quot; = &quot;$lastName&quot; ];then
            continue
        fi

        curl --connect-timeout 20 --retry 2 -s $imgUrl -o $imagePath/$fileName

        if [ ! -f &quot;$imagePath/$fileName&quot; ]; then
            echo 获取[$imgUrl]失败
            continue
        fi

        $gconftool -s /desktop/gnome/background/picture_filename -t string &quot;$imagePath/$fileName&quot; -s  /desktop/gnome/background/picture_options zoom
        lastName=$fileName
    fi
    sleep 1
done
</pre>
<p>把上面的脚本复制到你的机器上，执行一下，你的桌面就会每分钟更换一个美女为你报时。不过要注意只能在GNOME环境下用，因为我的系统中只装了GNOME环境，KDE的用户只要把设置桌面的命令改成KDE下设置桌面的命令即可。</p>
<p>有了上面的脚本，我们就可以加入开机自动启动。加在rc.local和 crontab是不行的，因为gconftool-2依赖于很多GNOME桌面环境变量，而有些变量是每次启动图形都不一样。不过GNOME是支持自动启动配置程序的，方法如下：</p>
<p>在$HOME/.config/autostart目录中新建一个文件：</p>
<p>[Desktop Entry]</p>
<p>Version=1.0</p>
<p>Encoding=UTF-8</p>
<p>Name=wallpaper</p>
<p>Type=Application</p>
<p>Exec=/home/linuxsong/wallpaper.sh</p>
<p>Terminal=false</p>
<p>Comment=Girl wallpaper</p>
<p>Categories=Utility;</p>
<p>X-Desktop-File-Install-Version=0.15</p>
<p>Hidden=false</p>
<p>把Exec=/home/linuxsong/wallpaper.sh这句中的路径改成你自己的路径即可。</p>
<p>重新注销一下看看你的桌面，是不是有美女为你报时？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/girl-clock-wallpaper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux命令行下更改桌面背景(GNOME环境)</title>
		<link>http://www.linuxsong.org/2010/09/gnome-change-wallpaper-with-command-line/</link>
		<comments>http://www.linuxsong.org/2010/09/gnome-change-wallpaper-with-command-line/#comments</comments>
		<pubDate>Thu, 09 Sep 2010 17:10:04 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[gnome]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=294</guid>
		<description><![CDATA[GNOME桌面环境下通过图形界面操作更改桌面背景很简单，但是如何在命令行下设置桌面背景呢？我们可以用GNOME的配置工具﻿﻿gconftool-2实现 <a href="http://www.linuxsong.org/2010/09/gnome-change-wallpaper-with-command-line/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.linuxsong.org/tag/gnome/">GNOME</a>桌面环境下通过图形界面操作更改桌面背景很简单，但是如何在命令行下设置桌面背景呢？我们可以用GNOME的配置工具﻿﻿gconftool-2实现，方法如下：</p>
<p>比如我们要把/tmp/image.jpg设为桌面背景，缩放显示，命令如下：<br />
gconftool-2  -s /desktop/gnome/background/picture_filename -t string &quot;/tmp/image.jpg&quot; -s  /desktop/gnome/background/picture_options zoom</p>
<p>如果想居中显示，并且指定背景颜色为纯黑色：<br />
<span id="more-294"></span>gconftool -s /desktop/gnome/background/picture_filename -t string &quot;/tmp/image.jpg&quot; -s  /desktop/gnome/background/picture_options center -s /desktop/gnome/background/primary_color -t string &quot;#000000&quot;  -s /desktop/gnome/background/color_shading_type solid</p>
<p>picture_options其它的几个选项</p>
<p>平铺： wallpaper</p>
<p>伸缩： stretched</p>
<p>SPAN: spanned</p>
<p>有了这个命令，我们就可以做一些比如定时更换桌面背景的事情了。比如设置一个图片目录，然后隔一段时间从里面选一张做为桌面背景。</p>
<p>举个例子，比如我有一个图片目录 /tmp/wallpaper,想每隔10分钟更换一张图片做为桌面背景，代码如下：</p>
<pre class="brush: bash;">

#!/bin/sh

while [ true ]

do

gconftool-2  -s /desktop/gnome/background/picture_filename -t string &quot;`ls /tmp/wallpaper/*.jpg | shuf -n 1`&quot; -s  /desktop/gnome/background/picture_options zoom

sleep 600

done
</pre>
<p>这几行就搞定了。</p>
<p>注：以上内容只在GNOME桌面环境下有效。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/gnome-change-wallpaper-with-command-line/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Vim快速选中、删除、复制引号或括号中的内容</title>
		<link>http://www.linuxsong.org/2010/09/vim-quick-select-copy-delete/</link>
		<comments>http://www.linuxsong.org/2010/09/vim-quick-select-copy-delete/#comments</comments>
		<pubDate>Tue, 07 Sep 2010 02:43:33 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=284</guid>
		<description><![CDATA[最近刚刚发现了一些Vim中，快速对引号或括号等标点内的内容进行选中、删除、复制操作的超级技巧，感觉非常实用。可以极大的提高编辑效率。 <a href="http://www.linuxsong.org/2010/09/vim-quick-select-copy-delete/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>最近刚刚发现了一些<a href="http://www.linuxsong.org/category/vim/">Vim</a>中，快速对引号或括号等标点内的内容进行选中、删除、复制操作的超级技巧，感觉非常实用。可以极大的提高编辑效率。</p>
<p>以下命令可以对标点内的内容进行操作。<br />
ci&#039;、ci&quot;、ci(、ci[、ci{、ci&lt; - 分别更改这些配对标点符号中的文本内容<br />
di&#039;、di&quot;、di(或dib、di[、di{或diB、di&lt; - 分别删除这些配对标点符号中的文本内容<br />
yi&#039;、yi&quot;、yi(、yi[、yi{、yi&lt; - 分别复制这些配对标点符号中的文本内容<br />
vi&#039;、vi&quot;、vi(、vi[、vi{、vi&lt; - 分别选中这些配对标点符号中的文本内容</p>
<p><span id="more-284"></span>另外如果把上面的i改成a可以连配对标点一起操作。</p>
<p>举个例子：</p>
<p>比如要操作的文本如下：</p>
<p>111&quot;222&quot;333</p>
<p>将光标移到&quot;222&quot;的任何一个字符处输入命令 di&quot; ,文本会变成： 111&quot;&quot;333</p>
<p>若输入命令 da&quot; ,文本会变成： 111333</p>
<p>特别是对于用Vim编码的同学来说，真是非常强劲的技巧。</p>
<p>内容部分引自：<a href="http://linuxtoy.org/archives/killer-vim-tip.html" target="_blank">linuxtoy</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/vim-quick-select-copy-delete/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Vim中设置svn代码更新、提交快捷键</title>
		<link>http://www.linuxsong.org/2010/09/vim-svn-shortcut-key/</link>
		<comments>http://www.linuxsong.org/2010/09/vim-svn-shortcut-key/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 11:20:38 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=279</guid>
		<description><![CDATA[经常写代码的同学免不了要经常重往版本库中提交、更新代码。如果在Vim中设置一些快捷键来完成这些工作，可以极大的提高工作效率。由于Vim灵活的可配置性，完成这些工作非常轻松，以svn为例说下具体方法。 <a href="http://www.linuxsong.org/2010/09/vim-svn-shortcut-key/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>经常写代码的同学免不了要经常重往版本库中提交、更新代码。如果在Vim中设置一些快捷键来完成这些工作，可以极大的提高工作效率。由于<a href="http://www.linuxsong.org/category/vim/">Vim</a>灵活的可配置性，完成这些工作非常轻松，以svn为例说下具体方法：</p>
<p>在~/.vimrc中添加以下代码：<br />
&quot;更新当前目录的代码<br />
map &lt;F5&gt;    :!svn up &lt;cr&gt;<br />
&quot;提交SVN(当前目录)<br />
map &lt;F7&gt;    :!svn ci -m &quot;&quot; &lt;cr&gt;<br />
&quot;提交SVN(当前文件)<br />
map &lt;F8&gt;    :!svn ci -m &quot;&quot; %&lt;cr&gt;</p>
<p>添加以上代码后，在Vim中按F5就可以更新当前目录，F7提交当前目录中版本库的所有改动,F8只提交当前编辑的文件（前提是当前文件已添加到版本库中），快捷键可以根据自己的喜好修改。</p>
<p>另外在版本库提交时还可以做一些其他的工作，比如如果你写的是PHP代码，那么可以在提交前先检查php程序中有没有语法错误，如果没有错误再提交，有错误不提交。</p>
<p>&quot;提交SVN(当前文件)前先检查php语法<br />
map &lt;F8&gt;    :!php -l % &gt; /dev/null &amp;&amp; svn ci -m &quot;&quot; %&lt;cr&gt;<br />
&quot;仅检测PHP语法<br />
autocmd FileType php map &lt;silent&gt; &lt;F9&gt; :!php -l %&lt;cr&gt;</p>
<p>如果你使用的是其它版本控制软件，比如cvs等，相信参照以上的方法也可以简单实现。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/vim-svn-shortcut-key/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery性能优化指南</title>
		<link>http://www.linuxsong.org/2010/09/jquery-optimize/</link>
		<comments>http://www.linuxsong.org/2010/09/jquery-optimize/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 04:06:10 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=267</guid>
		<description><![CDATA[现在jquery应用的越来越多, 有些同学在享受爽快淋漓coding时就将性能问题忽略了,  比如我.  jquery虽在诸多的js类库中性能表现还算优秀, 但毕竟不是在用原生的javascript开发, 性能问题还是需要引起重视的.  <a href="http://www.linuxsong.org/2010/09/jquery-optimize/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div style="margin: 8px 15px 15px;">
<p>现在<em>jquery</em>应用的越来越多, 有些同学在享受爽快淋漓coding时就将性能问题忽略了,  比如我.  jquery虽在诸多的js类库中性能表现还算优秀, 但毕竟不是在用原生的javascript开发, 性能问题还是需要引起重视的. 在twitter上发现了&lt;<a title="jQuery Performance Rules" href="http://www.artzstudio.com/2009/04/jquery-performance-rules/" target="_blank">jQuery Performance Rules</a>&gt;这篇文章, 简单的摘译了一下:</p>
</div>
<div id="articlebody">
<div id="article_body">
<ol>
<li>总是从ID选择器开始继承</li>
<li>在class前使用tag</li>
<li>将<em>jquery</em>对象缓存起来</li>
<li>掌握强大的链式操作</li>
<li>使用子查询</li>
<li>对直接的DOM操作进行限制</li>
<li>冒泡</li>
<li>消除无效查询</li>
<li>推迟到 $(window).load</li>
<li>压缩<a href="http://www.linuxsong.org/category/javascript/">js</a></li>
<li>全面掌握<em>jquery</em>库</li>
</ol>
<h3><span id="more-267"></span>1. 总是从ID选择器开始继承</h3>
<p>在<em>jquery</em>中最快的选择器是ID选择器. 因为它直接来自于Javascript的getElementById()方法.</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>&lt;div</strong></span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“content”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;form</strong></span> <span style="color: #bbbbbb;">method=</span><span style="color: #ed9d13;">“post”</span> <span style="color: #bbbbbb;">action=</span><span style="color: #ed9d13;">“/”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;h2&gt;</strong></span><span style="color: #d0d0d0;">Traffic Light</span><span style="color: #6ab825;"><strong>&lt;/h2&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;ul</strong></span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“traffic_light”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“on”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“red”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Red</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“yellow”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Yellow</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“green”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Green</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/ul&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;input</strong></span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“button”</span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“traffic_button”</span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“submit”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“Go”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/form&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/div&gt;</strong></span></div>
</div>
<p>像这样选择按钮是低效的:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">traffic_button</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#content .button’</span>);</span></div>
</div>
<p>用ID直接选择按钮效率更高:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">traffic_button</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_button’</span>);</span></div>
</div>
<h4>选择多个元素</h4>
<p>提到多元素选择其实是在说DOM遍历和循环, 这些都是比较慢的东西.为了提高<a href="http://www.yeeyan.com/articles/tag/%E6%80%A7%E8%83%BD" target="_blank"><em>性能</em></a>, 最好从就近的ID开始继承.</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">traffic_lights</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light input’</span>);</span></div>
</div>
<h3>2. 在class前使用tag</h3>
<p>第二快的选择器是tag选择器($(’head’)). 同理,因为它来自原生的getElementsByTagName() 方法.</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>&lt;div</strong></span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“content”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;form</strong></span> <span style="color: #bbbbbb;">method=</span><span style="color: #ed9d13;">“post”</span> <span style="color: #bbbbbb;">action=</span><span style="color: #ed9d13;">“/”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;h2&gt;</strong></span><span style="color: #d0d0d0;">Traffic Light</span><span style="color: #6ab825;"><strong>&lt;/h2&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;ul</strong></span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“traffic_light”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“on”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“red”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Red</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“yellow”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Yellow</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“green”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Green</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/ul&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;input</strong></span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“button”</span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“traffic_button”</span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“submit”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“Go”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/form&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/div&gt;;</strong></span></div>
</div>
<p>总是用一个tag name来限制(修饰)class (并且不要忘记就近的ID):</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">active_light</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light input.on’</span>);</span></div>
</div>
<p><em>注意: 在<em>jquery</em>中Class是最慢的选择器. IE浏览器下它会遍历所有DOM节点不管它用在那里.</em></p>
<p>不要用用tag name来修饰ID. 下面的例子将会遍历所有的div元素来查找id为’content’的哪一个节点:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">content</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘div#content’</span>);</span></div>
</div>
<p>用ID修饰ID也是画蛇添足:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">traffic_light</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#content #traffic_light’</span>);</span></div>
</div>
<h3>3.将<em>jquery</em>对象缓存起来</h3>
<p>要养成将<em>jquery</em>对象缓存进变量的习惯.</p>
<p>永远不要这样做:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light input.on).bind(’</span><span style="color: #d0d0d0;">click</span><span style="color: #ed9d13;">‘, function(){…});</span><br />
<span style="color: #ed9d13;">$(’</span><span style="color: #a61717; background-color: #e3d2d2;">#</span><span style="color: #d0d0d0;">traffic_light</span> <span style="color: #d0d0d0;">input</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">on</span><span style="color: #d0d0d0;">).</span><span style="color: #d0d0d0;">css</span>(<span style="color: #ed9d13;">‘border’</span><span style="color: #d0d0d0;">,</span> <span style="color: #ed9d13;">‘3px dashed yellow’</span>);<br />
<span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light input.on).css(’</span><span style="color: #d0d0d0;">background</span><span style="color: #d0d0d0;">-</span><span style="color: #d0d0d0;">color</span><span style="color: #ed9d13;">‘, ‘</span><span style="color: #d0d0d0;">orange</span><span style="color: #ed9d13;">‘);</span><br />
<span style="color: #ed9d13;">$(’</span><span style="color: #a61717; background-color: #e3d2d2;">#</span><span style="color: #d0d0d0;">traffic_light</span> <span style="color: #d0d0d0;">input</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">on</span><span style="color: #d0d0d0;">).</span><span style="color: #d0d0d0;">fadeIn</span>(<span style="color: #ed9d13;">’slow’</span>);</span></span></div>
</div>
<p>最好先将对象缓存进一个变量然后再操作:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">$active_light</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light input.on’</span>);<br />
<span style="color: #d0d0d0;">$active_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">bind</span>(<span style="color: #ed9d13;">‘click’</span><span style="color: #d0d0d0;">,</span> <span style="color: #6ab825;"><strong>function</strong></span><span style="color: #d0d0d0;">(){…});</span><br />
<span style="color: #d0d0d0;">$active_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">css</span>(<span style="color: #ed9d13;">‘border’</span><span style="color: #d0d0d0;">,</span> <span style="color: #ed9d13;">‘3px dashed yellow’</span>);<br />
<span style="color: #d0d0d0;">$active_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">css</span>(<span style="color: #ed9d13;">‘background-color’</span><span style="color: #d0d0d0;">,</span> <span style="color: #ed9d13;">‘orange’</span>);<br />
<span style="color: #d0d0d0;">$active_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">fadeIn</span>(<span style="color: #ed9d13;">’slow’</span>);</span></div>
</div>
<p><em>为了记住我们本地变量是<em>jquery</em>的封装, 通常用一个$作为变量前缀. </em>记住,永远不要让相同的选择器在你的代码里出现多次.</p>
<h4>缓存<em>jquery</em>结果,备用</h4>
<p>如果你打算将<em>jquery</em>结果对象用在程序的其它部分,或者你的function会多次执行, 那么就将他们缓存到一个全局变量中.</p>
<p>定义一个全局容器来存放<em>jquery</em>结果, 我们就可以在其它函数引用它们:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;">
<p><span style="color: #999999;"><em>// 在全局范围定义一个对象 (例如: window对象)</em></span><br />
<span style="color: #24909d;">window</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">$my</span> <span style="color: #d0d0d0;">=</span><br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #999999;"><em>// 初始化所有可能会不止一次要使用的查询</em></span><br />
<span style="color: #d0d0d0;">head</span> <span style="color: #d0d0d0;">:</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘head’</span>)<span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">traffic_light</span> <span style="color: #d0d0d0;">:</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light’</span>)<span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">traffic_button</span> <span style="color: #d0d0d0;">:</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_button’</span>)<br />
<span style="color: #d0d0d0;">};</span></span></span></span></p>
<p><span style="color: #6ab825;"><strong>function</strong></span> <span style="color: #d0d0d0;">do_something</span>()<br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #999999;"><em>// 现在你可以引用存储的结果并操作它们</em></span><br />
<span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">script</span> <span style="color: #d0d0d0;">=</span> <span style="color: #24909d;">document</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">createElement</span>(<span style="color: #ed9d13;">’script’</span>);<br />
<span style="color: #d0d0d0;">$my</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">head</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">append</span>(<span style="color: #d0d0d0;">script</span>);</p>
<p><span style="color: #999999;"><em>// 当你在函数内部操作是, 可以继续将查询存入全局对象中去</em></span><span style="color: #999999;"><em>.</em></span><br />
<span style="color: #d0d0d0;">$my</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">cool_results</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#some_ul li’</span>);<br />
<span style="color: #d0d0d0;">$my</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">other_results</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#some_table td’</span>);</span></span></p>
<p><span style="color: #999999;"><em>// 将全局函数作为一个普通的</em><em><em>jquery</em></em><em>对象去使用.</em></span><br />
<span style="color: #d0d0d0;">$my</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">other_results</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">css</span>(<span style="color: #ed9d13;">‘border-color’</span><span style="color: #d0d0d0;">,</span> <span style="color: #ed9d13;">‘red’</span>);<br />
<span style="color: #d0d0d0;">$my</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">traffic_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">css</span>(<span style="color: #ed9d13;">‘border-color’</span><span style="color: #d0d0d0;">,</span> <span style="color: #ed9d13;">‘green’</span>);<br />
<span style="color: #d0d0d0;">}</span></p>
</div>
</div>
<h3>4. 掌握强大的链式操作</h3>
<p>上面的例子也可以写成这样:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">$active_light</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light input.on’</span>);<span style="color: #d0d0d0;">$active_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">bind</span>(<span style="color: #ed9d13;">‘click’</span><span style="color: #d0d0d0;">,</span> <span style="color: #6ab825;"><strong>function</strong></span><span style="color: #d0d0d0;">(){…})</span><br />
<span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">css</span>(<span style="color: #ed9d13;">‘border’</span><span style="color: #d0d0d0;">,</span> <span style="color: #ed9d13;">‘3px dashed yellow’</span>)<br />
<span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">css</span>(<span style="color: #ed9d13;">‘background-color’</span><span style="color: #d0d0d0;">,</span> <span style="color: #ed9d13;">‘orange’</span>)<br />
<span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">fadeIn</span>(<span style="color: #ed9d13;">’slow’</span>);</span></div>
</div>
<p>这样可以写更少的代码, 让我们的js更轻量.</p>
<h3>5.使用子查询</h3>
<p>jQuery 允许我们对一个已包装的对象使用附加的选择器操作. 因为我们已经在保存了一个父级对象在变量里, 这样大大提高对其子元素的操作:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>&lt;div</strong></span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“content”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;form</strong></span> <span style="color: #bbbbbb;">method=</span><span style="color: #ed9d13;">“post”</span> <span style="color: #bbbbbb;">action=</span><span style="color: #ed9d13;">“/”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;h2&gt;</strong></span><span style="color: #d0d0d0;">Traffic Light</span><span style="color: #6ab825;"><strong>&lt;/h2&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;ul</strong></span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“traffic_light”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“on”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“red”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Red</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“yellow”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Yellow</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“green”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Green</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/ul&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;input</strong></span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“button”</span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“traffic_button”</span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“submit”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“Go”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/form&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/div&gt;</strong></span></div>
</div>
<p>例如, 我们可以用子查询的方法来抓取到亮或不亮的灯, 并缓存起来以备后续操作.</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">$traffic_light</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#traffic_light’</span>)<span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">$active_light</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;">$traffic_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">find</span>(<span style="color: #ed9d13;">‘input.on’</span>)<span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">$inactive_lights</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;">$traffic_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">find</span>(<span style="color: #ed9d13;">‘input.off’</span>);</span></div>
</div>
<p><em>提示: 你可以用逗号分隔的方法一次声明多个局部变量–节省字节数</em></p>
<h3>6.对直接的DOM操作进行限制</h3>
<p>这里的基本思想是在内存中建立你确实想要的东西，然后更新DOM 。这并不是一个jQuery最佳实践，但必须进行有效的JavaScript操作 。直接的DOM操作速度很慢。</p>
<p>例如,你想动态的创建一组列表元素, 千万不要这么做:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;">
<p><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">top_100_list</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;">[...]</span><span style="color: #d0d0d0;">,</span> <span style="color: #999999;"><em>// 假设这里是100个独一无二的字符串</em></span><br />
<span style="color: #d0d0d0;">$mylist</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#mylist’</span>); <span style="color: #999999;"><em>// jQuery 选择到 &lt;ul&gt; 元素</em></span></span></p>
<p><span style="color: #6ab825;"><strong>for</strong></span> (<span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">=</span><span style="color: #3677a9;">0</span><span style="color: #d0d0d0;">,</span> <span style="color: #d0d0d0;">l</span><span style="color: #d0d0d0;">=</span><span style="color: #d0d0d0;">top_100_list</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">length</span>; <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">&lt;</span><span style="color: #d0d0d0;">l</span>; <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">++</span>)<br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #d0d0d0;">$mylist</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">append</span>(<span style="color: #ed9d13;">‘&lt;li&gt;’</span> <span style="color: #d0d0d0;">+</span> <span style="color: #d0d0d0;">top_100_list</span><span style="color: #d0d0d0;">[</span><span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">]</span> <span style="color: #d0d0d0;">+</span> <span style="color: #ed9d13;">‘&lt;/li&gt;’</span>);<br />
<span style="color: #d0d0d0;">}</span></p>
</div>
</div>
<p>我们应该将整套元素字符串在插入进dom中之前全部创建好:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;">
<p><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">top_100_list</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;">[...]</span><span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">$mylist</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#mylist’</span>)<span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">top_100_li</span> <span style="color: #d0d0d0;">=</span> <span style="color: #ed9d13;">“”</span>; <span style="color: #999999;"><em>// 这个变量将用来存储我们的列表元素</em></span></span></p>
<p><span style="color: #6ab825;"><strong>for</strong></span> (<span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">=</span><span style="color: #3677a9;">0</span><span style="color: #d0d0d0;">,</span> <span style="color: #d0d0d0;">l</span><span style="color: #d0d0d0;">=</span><span style="color: #d0d0d0;">top_100_list</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">length</span>; <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">&lt;</span><span style="color: #d0d0d0;">l</span>; <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">++</span>)<br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #d0d0d0;">top_100_li</span> <span style="color: #d0d0d0;">+=</span> <span style="color: #ed9d13;">‘&lt;li&gt;’</span> <span style="color: #d0d0d0;">+</span> <span style="color: #d0d0d0;">top_100_list</span><span style="color: #d0d0d0;">[</span><span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">]</span> <span style="color: #d0d0d0;">+</span> <span style="color: #ed9d13;">‘&lt;/li&gt;’</span>;<br />
<span style="color: #d0d0d0;">}</span><br />
<span style="color: #d0d0d0;">$mylist</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">html</span>(<span style="color: #d0d0d0;">top_100_li</span>);</p>
</div>
</div>
<p>我们在插入之前将多个元素包裹进一个单独的父级节点会更快:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;">
<p><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">top_100_list</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;">[...]</span><span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">$mylist</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#mylist’</span>)<span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">top_100_ul</span> <span style="color: #d0d0d0;">=</span> <span style="color: #ed9d13;">‘&lt;ul id=”#mylist”&gt;’</span>;</span></p>
<p><span style="color: #6ab825;"><strong>for</strong></span> (<span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">=</span><span style="color: #3677a9;">0</span><span style="color: #d0d0d0;">,</span> <span style="color: #d0d0d0;">l</span><span style="color: #d0d0d0;">=</span><span style="color: #d0d0d0;">top_100_list</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">length</span>; <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">&lt;</span><span style="color: #d0d0d0;">l</span>; <span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">++</span>)<br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #d0d0d0;">top_100_ul</span> <span style="color: #d0d0d0;">+=</span> <span style="color: #ed9d13;">‘&lt;li&gt;’</span> <span style="color: #d0d0d0;">+</span> <span style="color: #d0d0d0;">top_100_list</span><span style="color: #d0d0d0;">[</span><span style="color: #d0d0d0;">i</span><span style="color: #d0d0d0;">]</span> <span style="color: #d0d0d0;">+</span> <span style="color: #ed9d13;">‘&lt;/li&gt;’</span>;<br />
<span style="color: #d0d0d0;">}</span><br />
<span style="color: #d0d0d0;">top_100_ul</span> <span style="color: #d0d0d0;">+=</span> <span style="color: #ed9d13;">‘&lt;/ul&gt;’</span>; <span style="color: #999999;"><em>//关闭无序列表</em></span><br />
<span style="color: #d0d0d0;">$mylist</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">replaceWith</span>(<span style="color: #d0d0d0;">top_100_ul</span>);</p>
</div>
</div>
<p>如果你做了以上几条还是担心有<a href="http://www.yeeyan.com/articles/tag/%E6%80%A7%E8%83%BD" target="_blank"><em>性能</em></a>问题,那么:</p>
<ul>
<li>试试<em>jquery</em>的 clone() 方法, 它会创建一个节点树的副本, 它允许以”离线”的方式进行dom操作, 当你操作完成后再将其放回到节点树里.</li>
<li>使用<a href="http://www.devguru.com/technologies/xmldom/quickref/obj_documentFragment.html" target="_blank">DOM DocumentFragments</a>. 正如jQuery作者所言, 它的性能要明显优于直接的dom操作.</li>
</ul>
<h3>7. 冒泡</h3>
<p>除非在特殊情况下, 否则每一个js事件(例如:click, mouseover, 等.)都会冒泡到父级节点. 当我们需要给多个元素调用同个函数时这点会很有用.</p>
<p>代替这种效率很差的多元素事件监听的方法就是, 你只需向它们的父节点绑定一次, 并且可以计算出哪个节点触发了事件.</p>
<p>例如, 我们要为一个拥有很多输入框的表单绑定这样的行为: 当输入框被选中时为它添加一个class</p>
<p>像这样绑定事件是低效的:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#entryform input).bind(’</span><span style="color: #d0d0d0;">focus</span><span style="color: #ed9d13;">‘, function(){</span><br />
<span style="color: #ed9d13;"> $(this).addClass(’</span><span style="color: #d0d0d0;">selected</span><span style="color: #ed9d13;">‘);</span><br />
<span style="color: #ed9d13;">}).bind(’</span><span style="color: #d0d0d0;">blur</span><span style="color: #ed9d13;">‘, function(){</span><br />
<span style="color: #ed9d13;"> $(this).removeClass(’</span><span style="color: #d0d0d0;">selected</span><span style="color: #a61717; background-color: #e3d2d2;">‘</span>);<br />
<span style="color: #d0d0d0;">});</span></span></div>
</div>
<p>我们需要在父级监听获取焦点和失去焦点的事件:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #ed9d13;">‘#entryform’</span><span style="color: #d0d0d0;">).</span><span style="color: #d0d0d0;">bind</span>(<span style="color: #ed9d13;">‘focus’</span><span style="color: #d0d0d0;">,</span> <span style="color: #6ab825;"><strong>function</strong></span>(<span style="color: #d0d0d0;">e</span><span style="color: #d0d0d0;">){</span><br />
<span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">cell</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #d0d0d0;">e</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">target</span>); <span style="color: #999999;"><em>// e.target grabs the node that triggered the event.</em></span><br />
<span style="color: #d0d0d0;">cell</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">addClass</span>(<span style="color: #ed9d13;">’selected’</span>);<br />
<span style="color: #d0d0d0;">}).</span><span style="color: #d0d0d0;">bind</span>(<span style="color: #ed9d13;">‘blur’</span><span style="color: #d0d0d0;">,</span> <span style="color: #6ab825;"><strong>function</strong></span>(<span style="color: #d0d0d0;">e</span><span style="color: #d0d0d0;">){</span><br />
<span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">cell</span> <span style="color: #d0d0d0;">=</span> <span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #d0d0d0;">e</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">target</span>);<br />
<span style="color: #d0d0d0;">cell</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">removeClass</span>(<span style="color: #ed9d13;">’selected’</span>);<br />
<span style="color: #d0d0d0;">});</span></span></span></span></div>
</div>
<p>父级元素扮演了一个调度员的角色, 它可以基于目标元素绑定事件. 如果你发现你给很多元素绑定了同一个事件监听, 那么你肯定哪里做错了.</p>
<h3>8.消除无效查询</h3>
<p>尽管<em>jquery</em>可以很优雅的处理没有匹配元素的情况, 但它还是需要花费时间去寻找. 如果你整站只有一个全局js, 那么极有可能把所有的jquery函数塞进$(document)ready(function(){//所有你引以为傲的代码})里.</p>
<p>只运行在页面里用到的函数. 大多数有效的方法就是使用行内初始化函数, 这样你的模板就能准确的控制何时何处该执行js.</p>
<p>例如, 你的”文章”页面模板, 你可能会引用如下的代码在body结束处:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>&lt;script </strong></span><span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“text/javascript</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #d0d0d0;">mylib</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">article</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">init</span>();<br />
<span style="color: #6ab825;"><strong>&lt;/script&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/body&gt;</strong></span></div>
</div>
<p>如果你的页面模板包含一些多变的模块可能不会出现在页面中, 或者为了视觉呈现的原因你需要它们能够快速加载, 你可以将初始化函数紧跟在模块之后.</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>&lt;ul</strong></span> <span style="color: #bbbbbb;">id=</span><span style="color: #ed9d13;">“traffic_light”</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“on”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“red”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Red</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“yellow”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Yellow</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;li&gt;&lt;input</strong></span> <span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“radio”</span> <span style="color: #bbbbbb;">class=</span><span style="color: #ed9d13;">“off”</span> <span style="color: #bbbbbb;">name=</span><span style="color: #ed9d13;">“light”</span> <span style="color: #bbbbbb;">value=</span><span style="color: #ed9d13;">“green”</span> <span style="color: #6ab825;"><strong>/&gt;</strong></span><span style="color: #d0d0d0;"> Green</span><span style="color: #6ab825;"><strong>&lt;/li&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;/ul&gt;</strong></span><br />
<span style="color: #6ab825;"><strong>&lt;script </strong></span><span style="color: #bbbbbb;">type=</span><span style="color: #ed9d13;">“text/javascript</span><span style="color: #6ab825;"><strong>&gt;</strong></span><br />
<span style="color: #d0d0d0;">mylib</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">traffic_light</span><span style="color: #d0d0d0;">.</span><span style="color: #d0d0d0;">init</span>();<br />
<span style="color: #6ab825;"><strong>&lt;/script&gt;</strong></span></div>
</div>
<p>你的全局js库可能会是这样子的:</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #6ab825;"><strong>var</strong></span> <span style="color: #d0d0d0;">mylib</span> <span style="color: #d0d0d0;">=</span><br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #d0d0d0;">article_page</span> <span style="color: #d0d0d0;">:</span><br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #d0d0d0;">init</span> <span style="color: #d0d0d0;">:</span> <span style="color: #6ab825;"><strong>function</strong></span>()<br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #999999;"><em>// Article 特有的jQuery函数.</em></span><br />
<span style="color: #d0d0d0;">}</span><br />
<span style="color: #d0d0d0;">}</span><span style="color: #d0d0d0;">,</span><br />
<span style="color: #d0d0d0;">traffic_light</span> <span style="color: #d0d0d0;">:</span><br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #d0d0d0;">init</span> <span style="color: #d0d0d0;">:</span> <span style="color: #6ab825;"><strong>function</strong></span>()<br />
<span style="color: #d0d0d0;">{</span><br />
<span style="color: #999999;"><em>// Traffic light 特有的jQuery函数.</em></span><br />
<span style="color: #d0d0d0;">}</span><br />
<span style="color: #d0d0d0;">}</span><br />
<span style="color: #d0d0d0;">}</span></div>
</div>
<h3>9. 推迟到 $(window).load</h3>
<p><a href="http://www.yeeyan.com/articles/tag/jquery" target="_blank"><em>jquery</em></a>对于开发者来说有一个很诱人的东西, 可以把任何东西挂到$(document).ready下冒充事件. 在大多数例子中你都会发现这样的情况.</p>
<p>尽管$(document).rady 确实很有用, 它可以在页面渲染时,其它元素还没下载完成就执行. 如果你发现你的页面一直是载入中的状态, 很有可能就是$(document).ready函数引起的.</p>
<p>你可以通过将<em>jquery</em>函数绑定到$(window).load 事件的方法来减少页面载入时的cpu使用率. 它会在所有的html(包括&lt;iframe&gt;)被下载完成后执行.</p>
<div style="background-color: #1e1e27;">
<div style="color: #d0d0d0; background-color: #1e1e27;"><span style="color: #d0d0d0;"><!--more--><span id="_mce_tmp">XX</span>lt;/span&gt;(<span style="color: #24909d;">window</span><span style="color: #d0d0d0;">).</span><span style="color: #d0d0d0;">load</span>(<span style="color: #6ab825;"><strong>function</strong></span><span style="color: #d0d0d0;">(){</span><br />
<span style="color: #999999;"><em>// 页面完全载入后才初始化的jQuery函数.</em></span><br />
<span style="color: #d0d0d0;">});</span></span></div>
</div>
<p>多余的功能例如拖放, 视觉特效和动画, 预载入隐藏图像,等等. 都是适合这种技术的场合.</p>
<h3>10. 压缩js</h3>
<p>推荐一个js在线压缩地址: http://dean.edwards.name/packer/</p>
<h3>11. 全面掌握<em>jquery</em>库</h3>
<p>知己知彼, 百战百胜.  只有更深入的了解jQuery才能更灵活的使用它.  这里提供一个<a href="http://acodingfool.typepad.com/blog/jquery-13-cheat-sheet.html" target="_blank">jQuery的速查手册</a>, 可以打印出来随身携带.  要是有能力将jQuery源码通读一遍那就更好了.</p>
<p style="background-color: #ffff99;">转自: <a href="http://rlog.cn/" target="_blank">Rlog.cn</a> .</p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/jquery-optimize/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>oracle预定义的异常列表</title>
		<link>http://www.linuxsong.org/2010/09/oracle-exception/</link>
		<comments>http://www.linuxsong.org/2010/09/oracle-exception/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:57:50 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=265</guid>
		<description><![CDATA[命名的系统异常 产生原因
ACCESS_INTO_NULL 未定义对象
CASE_NOT_FOUND CASE 中若未包含相应的 WHEN ，并且没有设置 ELSE 时
COLLECTION_IS_NULL 集合元素未初始化
CURSER_ALREADY_OPEN 游标已经打开 <a href="http://www.linuxsong.org/2010/09/oracle-exception/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>命名的系统异常 产生原因<br />
ACCESS_INTO_NULL 未定义对象<br />
CASE_NOT_FOUND CASE 中若未包含相应的 WHEN ，并且没有设置 ELSE 时<br />
COLLECTION_IS_NULL 集合元素未初始化<br />
CURSER_ALREADY_OPEN 游标已经打开<br />
DUP_VAL_ON_INDEX 唯一索引对应的列上有重复的值<br />
INVALID_CURSOR 在不合法的游标上进行操作<br />
INVALID_NUMBER 内嵌的 SQL 语句不能将字符转换为数字<br />
NO_DATA_FOUND 使用 select into 未返回行，或应用索引表未初始化的元素时<br />
TOO_MANY_ROWS 执行 select into 时，结果集超过一行<br />
ZERO_DIVIDE 除数为 0<br />
SUBSCRIPT_BEYOND_COUNT 元素下标超过嵌套表或 VARRAY 的最大值<br />
SUBSCRIPT_OUTSIDE_LIMIT 使用嵌套表或 VARRAY 时，将下标指定为负数<br />
VALUE_ERROR 赋值时，变量长度不足以容纳实际数据<br />
LOGIN_DENIED PL/SQL 应用程序连接到 oracle 数据库时，提供了不正确的用户名或密码<br />
NOT_LOGGED_ON PL/SQL 应用程序在没有连接 oralce 数据库的情况下访问数据<br />
PROGRAM_ERROR PL/SQL 内部问题，可能需要重装数据字典＆ pl./SQL 系统包<br />
ROWTYPE_MISMATCH 宿主游标变量与 PL/SQL 游标变量的返回类型不兼容<br />
SELF_IS_NULL 使用对象类型时，在 null 对象上调用对象方法<br />
STORAGE_ERROR 运行 PL/SQL 时，超出内存空间<br />
SYS_INVALID_ID 无效的 ROWID 字符串<br />
TIMEOUT_ON_RESOURCE Oracle 在等待资源时超时</p>
<p><span id="more-265"></span>BEGIN<br />
《PL/SQL块》;<br />
Exception<br />
when no_data_found then --没有找到数据<br />
《响应命令》;<br />
when too_many_rows then --返回多行，隐式光标每次只能检索一行数据<br />
《响应命令》;<br />
when invalid_number then --字符向数字转换失败<br />
《响应命令》;<br />
when zero_divide then --被零除<br />
《响应命令》;<br />
when dup_val_on_index then --向唯一索引中插入重复数据<br />
《响应命令》;<br />
when invalid_cursor then --非法游标操作<br />
《响应命令》;<br />
when value_error then --数字的,数据转换,截字符串或强制性的错误<br />
《响应命令》;<br />
when others then --发生其它任何错误<br />
null; --选择一：什么也不做，就当错误没发生<br />
raise form_trigger_failure; --选择二：挂起当前程序<br />
END;</p>
<p>常用预定义例外<br />
EXCEPTION<br />
WHEN CURSOR_ALREADY_OPEN THEN -- ORA-06511 SQLCODE = -6511 游标已经打开<br />
..WHEN DUP_VAL_ON_INDEX THEN -- ORA-00001 SQLCODE = -1 向唯一索引中插入重复数据<br />
..WHEN INVALID_CURSOR THEN -- ORA-01001 SQLCODE = -1001 非法游标操作<br />
..WHEN INVALID_NUMBER THEN -- ORA-01722 SQLCODE = -1722 字符向数字转换失败<br />
..WHEN LOGIN_DENIED THEN -- ORA-01017 SQLCODE = -1017</p>
<p>..WHEN NO_DATA_FOUND THEN -- ORA-01403 SQLCODE = +100 没有找到数据<br />
..WHEN NOT_LOGGED_ON THEN -- ORA-01012 SQLCODE = -1012<br />
..WHEN PROGRAM_ERROR THEN -- ORA-06501 SQLCODE = -6501 程序错误<br />
..WHEN STORAGE_ERROR THEN -- ORA-06500 SQLCODE = -6500<br />
..WHEN TIMEOUT_ON_RESOURCE THEN -- ORA-00051 SQLCODE = -51</p>
<p>..WHEN TOO_MANY_ROWS THEN -- ORA-01422 SQLCODE = -1422 返回多行<br />
..WHEN TRANSACTION_BACKED_OUT THEN -- ORA-00061 SQLCODE = -61</p>
<p>..WHEN VALUE_ERROR THEN -- ORA-06502 SQLCODE = -6502 数值转换错误<br />
..WHEN ZERO_DIVIDE THEN -- ORA-01476 SQLCODE = -1476 被零除<br />
..WHEN OTHERS THEN -- 其它任何错误的处理</p>
<div><span style="color: #433c2f; font-family: Arial; line-height: 16px; font-size: 12px;"><br />
</span></div>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/oracle-exception/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ORACLE 中ROWNUM用法详解</title>
		<link>http://www.linuxsong.org/2010/09/oracle-rownum/</link>
		<comments>http://www.linuxsong.org/2010/09/oracle-rownum/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:55:26 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[oracle]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=263</guid>
		<description><![CDATA[对于 Oracle 的 rownum 问题，很多资料都说不支持>,>=,=,between...and，只能用以上符号(<、<=、!=)，并非说用>,& gt;=,=,between..and 时会提示SQL语法错误，而是经常是查不出一条记录来，还会出现似乎是莫名其妙的结果来，其实您只要理解好了这个 rownum 伪列的意义就不应该感到惊奇，同样是伪列，rownum 与 rowid 可有些不一样，下面以例子说明 <a href="http://www.linuxsong.org/2010/09/oracle-rownum/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>这段时间工作上一直在与ORACLE打交道，由于以前没有用过ORACLE,所以对很多知识不了解，上网时看到了一些ORACLE知识，在此记录，以便进一步学习。</p>
<p>对于 Oracle 的 rownum 问题，很多资料都说不支持&gt;,&gt;=,=,between...and，只能用以上符号(&lt;、&lt;=、!=)，并非说用&gt;,&amp; gt;=,=,between..and 时会提示SQL语法错误，而是经常是查不出一条记录来，还会出现似乎是莫名其妙的结果来，其实您只要理解好了这个 rownum 伪列的意义就不应该感到惊奇，同样是伪列，rownum 与 rowid 可有些不一样，下面以例子说明<br />
<span id="more-263"></span><br />
假设某个表 t1(c1) 有 20 条记录</p>
<p>如果用 select rownum,c1 from t1 where rownum &lt;&gt; 10 (如果写下这样的查询语句，这时候在您的头脑中应该是想得到表中后面10条记录)，你就会发现，显示出来的结果要让您失望了，也许您还会怀疑是不谁删了一 些记录，然后查看记录数，仍然是 20 条啊？那问题是出在哪呢？</p>
<p>先好好理解 rownum 的意义吧。因为ROWNUM是对结果集加的一个伪列，即先查到结果集之后再加上去的一个列 (强调：先要有结果集)。简单的说 rownum 是对符合条件结果的序列号。它总是从1开始排起的。所以你选出的结果不可能没有1，而有其他大于1的值。所以您没办法期望得到下面的结果集：</p>
<p>11 aaaaaaaa<br />
12 bbbbbbb<br />
13 ccccccc<br />
.................</p>
<p>rownum &gt;10 没有记录，因为第一条不满足去掉的话，第二条的ROWNUM又成了1，所以永远没有满足条件的记录。或者可以这样理解：</p>
<p>ROWNUM是一个序列，是oracle数据库从数据文件或缓冲区中读取数据的顺序。它取得第一条记录则rownum值为1，第二条为2，依次类推。如果 你用&gt;,&gt;=,=,between...and这些条件，因为从缓冲区或数据文件中得到的第一条记录的rownum为1，则被删除，接着取下 条，可是它的rownum还是1，又被删除，依次类推，便没有了数据。</p>
<p>有了以上从不同方面建立起来的对 rownum 的概念，那我们可以来认识使用 rownum 的几种现像</p>
<p>1. select rownum,c1 from t1 where rownum != 10 为何是返回前9条数据呢？它与 select rownum,c1 from tablename where rownum &lt;&gt;=10,所以只显示前面9条记录。也可以这样理解，rownum 为9后的记录的 rownum为10，因条件为 !=10，所以去掉，其后记录补上，rownum又是10，也去掉，如果下去也就只会显示前面9条记录了</p>
<p>2. 为什么 rownum &gt;1 时查不到一条记录，而 rownum &gt;0 或 rownum &gt;=1 却总显示所以的记录<br />
因为 rownum 是在查询到的结果集后加上去的，它总是从1开始</p>
<p>3. 为什么 between 1 and 10 或者 between 0 and 10 能查到结果，而用 between 2 and 10 却得不到结果<br />
原因同上一样，因为 rownum 总是从 1 开始</p>
<p>从上可以看出，任何时候想把 rownum = 1 这条记录抛弃是不对的，它在结果集中是不可或缺的，少了rownum=1 就像空中楼阁一般不能存在，所以你的 rownum 条件要包含到 1</p>
<p>但如果就是想要用 rownum &gt; 10 这种条件的话话就要用嵌套语句,把 rownum 先生成，然后对他进行查询。<br />
select *<br />
from (selet rownum as rn，t1.* from a where ...)<br />
where rn &gt;10</p>
<p>一般代码中对结果集进行分页就是这么干的。</p>
<p>另外：rowid 与 rownum 虽都被称为伪列，但它们的存在方式是不一样的，rowid 可以说是物理存在的，表示记录在表空间中的唯一位置ID，在DB中唯一。只要记录没被搬动过，rowid是不变的。rowid 相对于表来说又像表中的一般列，所以以 rowid 为条件就不会有 rownum那些情况发生。<br />
另外还要注意：rownum不能以任何基表的名称作为前缀。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/oracle-rownum/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>gvim 在新标签页中打开文件</title>
		<link>http://www.linuxsong.org/2010/09/gvim-open-file-in-tab/</link>
		<comments>http://www.linuxsong.org/2010/09/gvim-open-file-in-tab/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:51:47 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=258</guid>
		<description><![CDATA[在windows下使用vim时有个很不方便的地方，每次双击文件编辑时，就会新打开一个窗口，如果想在新标签中打开，就必须右击文件，然后选择在当前的vim中打开。网上搜索了一些文章，方法基本都是修改注册表，修改右键的编辑功能，使用起来还是不方便。能不能双击文件时直接在gvim的新标签中打开呢？ <a href="http://www.linuxsong.org/2010/09/gvim-open-file-in-tab/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>在windows下使用<a href="http://www.linuxsong.org/category/vim/">vim</a>时有个很不方便的地方，每次双击文件编辑时，就会新打开一个窗口，如果想在新标签中打开，就必须右击文件，然后选择在当前的vim中打开。网上搜索了一些文章，方法基本都是修改注册表，修改右键的编辑功能，使用起来还是不方便。能不能双击文件时直接在gvim的新标签中打开呢？经过摸索，我想到了以下方法。</p>
<p>1.新建一个批处理文件,文件名随便取，比如gvim_tab.bat, 写入以下几行内容：<br />
@echo off<br />
start /B D:\Vim\vim72\gvim.exe -p --remote-tab-silent &quot;%~f1&quot;<br />
exit<br />
(注意修改你自己的gvim的路径)<br />
2.将你想要用gvim编辑的文件类型的打开程序改为gvim_tab.bat(并选择记住打开方式）</p>
<p>这样双击你刚才修改的文件类型，看看是不是在gvim的新标签中打开了呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/gvim-open-file-in-tab/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>软件开发者面试百问</title>
		<link>http://www.linuxsong.org/2010/09/interview-questions-for-software-developers/</link>
		<comments>http://www.linuxsong.org/2010/09/interview-questions-for-software-developers/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:49:00 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=256</guid>
		<description><![CDATA[想雇到搞软件开发的聪明人可不容易。万一一不小心，就会搞到一堆低能大狒狒。我去年就碰到这种事了。你肯定不想这样吧。听我的，没错。在树上开站立会议门都没有。 <a href="http://www.linuxsong.org/2010/09/interview-questions-for-software-developers/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>来自： <a href="http://www.infoq.com/cn/articles/programmer-interview" target="_blank">InfoQ</a><strong><br />
</strong></p>
<p><strong>想雇到搞软件开发的聪明人可不容易</strong>。万一一不小心，就会搞到一堆低能大狒狒。我去年就碰到这种事了。你肯定不想这样吧。听我的，没错。在树上开站立会议门都没有。</p>
<p><strong>问点有难度的问题</strong>能帮你把聪明人跟狒狒们分开。我决定把我自己整理出来的<strong>软件开发者面试百问</strong>发出来，希望能帮到你们的忙。</p>
<p>这个列表涵盖了<a href="http://en.wikipedia.org/wiki/SWEBOK" target="_blank">软件工程知识体系</a>中定义的大多数知识域。当然，如果你只想找出类拔萃的程序员，便只需涉及结构、算法、数据结构、测试这几个话题。如果想雇架构师，也可以只考虑需求、功能设计、技术设计这些地方。</p>
<p><span id="more-256"></span>不过不管你怎么做，都要牢记一点：</p>
<p><strong>这里大多数问题的答案都没有对错之分！</strong></p>
<p><strong>你可以把我的这些问题作为引子，展开讨论。</strong>例如下面有个问题是使用静态方法或是单例的缘由。如果那个面试的就此展开长篇大论，那他很有可能是个聪明能干的家伙！如果他一脸茫然的看着你，发出<a href="http://simplythebest.net/sounds/WAV/sound_effects_WAV/sound_effect_WAV_files/mandrill.wav" target="_blank">这种声音</a>，很明显这就是只狒狒了。同样，想知道一个数是不是2的乘方也有很多方法，不过要是面试的人想用mod运算符，嗯……你知道我的意思吧。（你不知道也没关系，来根香蕉？）</p>
<p><strong>需求</strong></p>
<ol>
<li>你能给出一些非功能性（或者质量）需求的例子么？</li>
<li>如果客户需要高性能、使用极其方便而又高度安全，你会给他什么建议？</li>
<li>你能给出一些用来描述需求的不同技术么？它们各自适用于什么场景？</li>
<li>需求跟踪是什么意思？什么是向前追溯，什么是向后追溯？</li>
<li>你喜欢用什么工具跟踪需求？</li>
<li>你怎么看待需求变化？它是好是坏？给出你的理由。</li>
<li>你怎样研究需求，发现需求？有哪些资源可以用到？</li>
<li>你怎么给需求制定优先级？有哪些技术？</li>
<li>在需求过程中，用户、客户、开发人员各自的职责是什么？</li>
<li>你怎么对待不完整或是令人费解的需求？</li>
</ol>
<p><strong>功能设计</strong></p>
<ol>
<li>在功能设计中有哪些隐喻？给出几个成功的例子。</li>
<li>如果有些功能的执行时间很长，怎么能让用户感觉不到太长的等待？</li>
<li>如果用户必须要在一个很小的区域内，从一个常常的列表中选择多个条目，你会用什么控件？</li>
<li>有哪些方法可以保证数据项的完整？</li>
<li>建立系统原型有哪些技术？</li>
<li>应用程序怎样建立对用户行为的预期？给出一些例子。</li>
<li>如何入手设计一组数量庞大而又复杂的特性，你能举出一些设计思路吗？</li>
<li>有一个列表，其中有10个元素，每个元素都有20个字段可以编辑，你怎样设计这种情况？如果是1000个元素，每个元素有3个字段呢？</li>
<li>用不同的颜色对一段文本中的文字标记高亮，这种做法有什么问题？</li>
<li>Web环境和Windows环境各有些什么限制？</li>
</ol>
<p><strong>技术设计</strong></p>
<ol>
<li>什么是低耦合和高聚合？封装原则又是什么意思？</li>
<li>在Web应用中，你怎样避免几个人编辑同一段数据所造成的冲突？</li>
<li>你知道设计模式吗？你用过哪些设计模式？在什么场合下用的？</li>
<li>是否了解什么是无状态的业务层？长事务如何与之相适应？</li>
<li>在搭建一个架构，或是技术设计时，你用过几种图？</li>
<li>在N层架构中都有哪些层？它们各自的职责是什么？</li>
<li>有哪些方法可以确保架构中数据的正确和健壮？</li>
<li>面向对象设计和面向组件设计有哪些不同之处？</li>
<li>怎样在数据库中对用户授权、用户配置、权限管理这几项功能建模？</li>
<li>怎样按照等级制度给动物王国（包括各种物种和各自的行为）建模？</li>
</ol>
<p><strong>程序设计</strong></p>
<ol>
<li>你怎样保证你的代码可以处理各种错误事件？</li>
<li>解释一下什么是测试驱动开发，举出极限编程中的一些原则。</li>
<li>看别人代码的时候，你最关心什么地方？</li>
<li>什么时候使用抽象类，什么时候使用接口？</li>
<li>除了IDE以外，你还喜欢哪些必不可少的工具？</li>
<li>你怎么保证代码执行速度快，而又不出问题？</li>
<li>什么时候用多态，什么时候用委派？</li>
<li>什么时候使用带有静态成员的类，什么时候使用单例？</li>
<li>你在代码里面怎么提前处理需求的变化？给一些例子。</li>
<li>描述一下实现一段代码的过程，从需求到最终交付。</li>
</ol>
<p><strong>算法</strong></p>
<ol>
<li>怎样知道一个数字是不是2的乘方？怎样判断一个数是不是奇数？</li>
<li>怎样找出链表中间的元素？</li>
<li>怎样改变10,000个静态HTML页面中所有电话号码的格式？</li>
<li>举出一个你所用过的递归的例子。</li>
<li>在散列表和排序后的列表中找一个元素，哪个查找速度最快？</li>
<li>不管是书、杂志还是网络，你从中所学到的最后一点算法知识是什么？</li>
<li>怎样把字符串反转？你能不用临时的字符串么？</li>
<li>你愿意用什么类型的语言来编写复杂的算法？</li>
<li>有一个数组，里面是从1到1,000,000的整数，其中有一个数字出现了两次，你怎么找出那个重复的数字？</li>
<li>你知道“旅行商问题（Traveling Salesman Problem）”么？</li>
</ol>
<p><strong>数据结构</strong></p>
<ol>
<li>怎样在内存中实现伦敦地铁的结构？</li>
<li>怎样以最有效的方式在数据库中存储颜色值？</li>
<li>队列和堆栈区别是什么？</li>
<li>用堆或者栈存储数据的区别是什么？</li>
<li>怎样在数据库中存储N维向量？</li>
<li>你倾向于用哪种类型的语言编写复杂的数据结构？</li>
<li>21的二进制值是什么？十六制值呢？</li>
<li>不管是书、杂志还是网络，你从中所学到的最后一点数据结构的知识是什么？</li>
<li>怎样在XML文档中存储足球比赛结果（包括队伍和比分）？</li>
<li>有哪些文本格式可以保存Unicode字符？</li>
</ol>
<p><strong>测试</strong></p>
<ol>
<li>什么是回归测试？怎样知道新引入的变化没有给现有的功能造成破坏？</li>
<li>如果业务层和数据层之间有依赖关系，你该怎么写单元测试？</li>
<li>你用哪些工具测试代码质量？</li>
<li>在产品部署之后，你最常碰到的是什么类型的问题？</li>
<li>什么是代码覆盖率？有多少种代码覆盖率？</li>
<li>功能测试和探索性测试的区别是什么？你怎么对网站进行测试？</li>
<li>测试套件、测试用例、测试计划，这三者之间的区别是什么？你怎么组织测试？</li>
<li>要对电子商务网站做冒烟测试，你会做哪些类型的测试？</li>
<li>客户在验收测试中会发现不满意的东西，怎样减少这种情况的发生？</li>
<li>你去年在测试和质量保证方面学到了哪些东西？</li>
</ol>
<p><strong>维护</strong></p>
<ol>
<li>你用哪些工具在维护阶段对产品进行监控？</li>
<li>要想对一个正在产品环境中被使用的产品进行升级，该注意哪些重要事项？</li>
<li>如果在一个庞大的文件中有错误，而代码又无法逐步跟踪，你怎么找出错误？</li>
<li>你怎样保证代码中的变化不会影响产品的其他部分？</li>
<li>你怎样为产品编写技术文档？</li>
<li>你用过哪些方式保证软件产品容易维护？</li>
<li>怎样在产品运行的环境中进行系统调试？</li>
<li>什么是负载均衡？负载均衡的方式有哪些种？</li>
<li>为什么在应用程序的生命周期中，软件维护费用所占的份额最高？</li>
<li>再造工程（re-engineering）和逆向工程（reverse engineering）的区别是什么？</li>
</ol>
<p><strong>配置管理</strong></p>
<ol>
<li>你知道配置管理中基线的含义么？怎样把项目中某个重要的时刻冻结？</li>
<li>你一般会把哪些东西纳入版本控制？</li>
<li>怎样可以保证团队中每个人都知道谁改变了哪些东西？</li>
<li>Tag和Branch的区别是什么？在什么情况下该使用tag，什么时候用branch？</li>
<li>怎样管理技术文档——如产品架构文档——的变化？</li>
<li>你用什么侗剧管理项目中所有数字信息的状态？你最喜欢哪种工具？</li>
<li>如果客户想要对一款已经发布的产品做出变动，你怎么处理？</li>
<li>版本管理和发布管理有什么差异？</li>
<li>对文本文件的变化和二进制文件的变化进行管理，这二者有什么不同？</li>
<li>同时处理多个变更请求，或是同时进行增量开发和维护，这种事情你怎么看待？</li>
</ol>
<p><strong>项目管理</strong></p>
<ol>
<li>范围、时间、成本，这三项中哪些是可以由客户控制的？</li>
<li>谁该对项目中所要付出的一切做出估算？谁有权设置最后期限？</li>
<li>减少交付的次数，或是减少每个每个交付中的工作量，你喜欢哪种做法？</li>
<li>你喜欢用哪种图来跟踪项目进度？</li>
<li>迭代和增量的区别在哪里？</li>
<li>试着解释一下风险管理中用到的实践。风险该如何管理？</li>
<li>你喜欢任务分解还是滚动式计划？</li>
<li>你需要哪些东西帮助你判断项目是否符合时间要求，在预算范围内运作？</li>
<li>DSDM、Prince2、Scrum，这三者之间有哪些区别？</li>
<li>如果客户想要的东西太多，你在范围和时间上怎样跟他达成一致呢？</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/interview-questions-for-software-developers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://simplythebest.net/sounds/WAV/sound_effects_WAV/sound_effect_WAV_files/mandrill.wav" length="42868" type="audio/wav" />
		</item>
		<item>
		<title>Linux下MBR的备份与恢复</title>
		<link>http://www.linuxsong.org/2010/09/linux-backup-mbr/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-backup-mbr/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:44:51 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=253</guid>
		<description><![CDATA[MBR是Master Boot Record的简称,又叫主引导记录.它是硬盘上最重要的一个数据结构,当用分区软件创建分区的时候,分区软件会自动创建MBR.MBR处于硬盘的第一个 扇区.即0柱面,0磁头,1扇区.主引导记录由三部分构成,第一部分是一小段执行代码,共446字节，第二部分是64字节的分区表,第三部分是系统标志,一般为 55AA（两个字节）. <a href="http://www.linuxsong.org/2010/09/linux-backup-mbr/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>MBR是Master Boot Record的简称,又叫主引导记录.它是硬盘上最重要的一个数据结构,当用分区软件创建分区的时候,分区软件会自动创建MBR.MBR处于硬盘的第一个 扇区.即0柱面,0磁头,1扇区.主引导记录由三部分构成,第一部分是一小段执行代码,共446字节，第二部分是64字节的分区表,第三部分是系统标志,一般为 55AA（两个字节）.在基于X86的计算机上,可执行代码检查分区表的合法性,同时查找系统分区.找到系统分区后,MBR读取系统分区的第一个扇区,也就是分区引导 扇区到内存,然后把代码控制权交给分区引导扇区.</p>
<p>在<a href="http://www.linuxsong.org/category/linux/">Linux</a>备份或恢复MBR的方法很简单。<br />
备份MBR分区法份方法如下：<br />
dd if=/dev/sda1 of=/root/mbr bs=512 count=1</p>
<p>恢复MBR</p>
<p>dd if=/root/mbr of=/dev/sda1 bs=512 count=1</p>
<p>硬盘的分区表是存放在硬盘的446字节开始的64个字节中，如果只想备份硬盘分区表的方法如下:</p>
<p>dd if=/dev/sda1 of=/root/mbr bs=1 skip=446 count=64</p>
<p>恢复分区表的方法如下：<br />
dd if=/root/mbr of=/dev/sda1 bs=1 skip=446 count=64</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-backup-mbr/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql中复制介绍及主从服务器的配置</title>
		<link>http://www.linuxsong.org/2010/09/mysql-master-slov/</link>
		<comments>http://www.linuxsong.org/2010/09/mysql-master-slov/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:42:46 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=251</guid>
		<description><![CDATA[复制介绍

MySQL支持单向、异步复制，复制过程中一个服务器充当主服务器，而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件，并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时，它通知主 服务器从服务器在日志中读取的最后一次成功更新的位置。 <a href="http://www.linuxsong.org/2010/09/mysql-master-slov/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>复制介绍</h2>
<p>MySQL支持单向、异步复制，复制过程中一个服务器充当主服务器，而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件，并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时，它通知主 服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新，然后封锁并等待主服务器通知新的更新。</p>
<p>如果你想要设置链式复制服务器，从服务器本身也可以充当主服务器。</p>
<p><span id="more-251"></span>请注意当你进行复制时，所有对复制中的表的更新必须在主服务器上进行。否则，你必须要小心，以避免用户对主服务器上的表进行的更新与对从服务器上的表所进行的更新之间的冲突。</p>
<p>单向复制有利于健壮性、速度和系统管理：</p>
<p>· 主服务器/从服务器设置增加了健壮性。主服务器出现问题时，你可以切换到从服务器作为备份。</p>
<p>· 通过在主服务器和从服务器之间切分处理客户查询的负荷，可以得到更好的客户响应时间。SELECT查询可以发送到从服务器以降低主服务器的查询处理负荷。但修改数据的语句仍然应发送到主服务器，以便主服务器和从服务器保持同步。如果非更新查询为主，该负载均衡策略很有效，但一般是更新查询。</p>
<p>· 使用复制的另一个好处是可以使用一个从服务器执行备份，而不会干扰主服务器。在备份过程中主服务器可以继续处理更新。</p>
<p>主从服务器的配置</p>
<p>假如有两台机器，<br />
A： 192.168.10.86<br />
B： 192.168.10.87</p>
<p>想把A配置成主服务器，B配置成从服务器(从服务器可以有多个，这里做一个为例子，其它的从机操作基本相同），操作步骤如下：<br />
<strong>机器A上的操作：<br />
</strong>1.为从服务器创建复制帐号（建议只用这个用户做复制帐号使用，不要做为它用）<br />
mysql&gt; GRANT REPLICATION SLAVE ON *.* TO &#039;repl&#039;@&#039;192.168.10.87&#039; IDENTIFIED BY &#039;slavepass&#039;;</p>
<p>2.修改/etc/my.cnf</p>
<p>在[mysqld]中添加如下内容：<br />
server-id = 1 #主机标示，唯一整数,不能和其它主从服务器相同。<br />
log_bin = /var/log/mysql/mysql-bin #确保此文件mysql可写<br />
binlog-do-db =test #需要备份数据，多个写多行<br />
binlog-ignore-db=mysql #不需要备份的数据库，多个写多行</p>
<p>$ sudo service mysqld restart</p>
<p><strong><strong>机器B上的操作：</strong></strong>1. 先测试一下，复制帐号是否可用：<br />
$ mysql -h192.168.10.86 -urepl -p<strong><strong>slavepass</strong></strong></p>
<p>2. 修改/etc/my.cnf<br />
在[mysqld]中添加如下内容：</p>
<p>server-id=2<br />
master-host=192.168.10.86<br />
master-port=3306<br />
master-user=repl<br />
master-password=test<br />
master-connect-retry=5</p>
<p>replicate-do-db =test</p>
<p>参数介绍：</p>
<p>master-host=<em>host</em></p>
<p>主复制服务器的主机名或IP地址。如果没有给出该选项，从服务器线程不启动。</p>
<p>master-password=<em>password</em></p>
<p>连接主服务器时从服务器线程用于鉴定的账户的密码。如果未设置，假定密码为空。</p>
<p>master-port=<em>port_number</em></p>
<p>mysql的的端口号（如果你没有修改的话就是3306)</p>
<p>master-user=<em>username</em></p>
<p>连接主服务器时从服务器线程用于鉴定的账户的用户名。该账户必须具有REPLICATION SLAVE权限。如果未设置主服务器用户，假定使用用户test。</p>
<p>replicate-do-db=<em>db_name</em></p>
<p>告诉从服务器限制默认数据库(由USE所选择)为<em>db_name</em>的语句的复制。要指定多个数据库，应多次使用该选项，每个数据库使用一次。请注意不复制跨数据库的语句，例如当已经选择了其它数据库或没有数据库时执行UPDATE<em>some_db.some_table</em> SET foo=&#039;bar&#039;。如果需要跨数据库进行更新，使用--replicate-wild-do-table=<em>db_name</em>.%。请读取该选项列表后面的注意事项。</p>
<p>一个不能按照期望工作的例子：如果用--replicate-do-db=sales启动从服务器，并且在主服务器上执行下面的语句，UPDATE语句不会复制：</p>
<p>USE prices; UPDATE sales.january SET amount=amount+1000; 如果需要跨数据库进行更新，应使用--replicate-wild-do-table=<em>db_name</em>.%。</p>
<p>master-connect-retry=retry_seconds<br />
从服务器丢失与主服务器的连接，从服务器尝试立即重新连接。如果失败，则过retry_seconds秒后重新连接。</p>
<p>数据库同步</p>
<p>修改完后，要进行数据同步。<br />
同步方法可以用两种方法<br />
1.<br />
mysql&gt; LOAD DATA FROM MASTER;</p>
<p>使用这种方法时，授予复制帐户必须有SUPER和RELOAD全局权限（前面我们创建的帐号没有这个权限）。<br />
LOAD DATA FROM MASTER目前只在所有表使用MyISAM存储引擎的主服务器上工作。并且，该语句将获得全局读锁定，因此当表正复制到从服务器上时，不可能在主服务器上进行更新。</p>
<p>2.<br />
用mysqldump将主服务器中要复制的数据库导出，在本例中我们用test<br />
$ mysqldump -uroot -p test --databases &gt; test.sql</p>
<p>然后将其拷贝到B机器中，导入数据。<br />
$ mysql -uroot -p &lt; test.sql</p>
<p>验证</p>
<p>在主机A中，mysql&gt;show master status;</p>
<p>在从机B中，mysql&gt;show slave status;</p>
<p>然后，在主机中插入一条数据，看一下B机上的数据库中有相应的数据。</p>
<p><strong>注意：</strong>你不能从使用新二进制日志格式的主服务器向使用旧二进制日志格式的从服务器复制(例如，从MySQL 5.0到MySQL 4.1）。这样操作在复制设置升级服务器时后果严重</p>
<p>合理利用mysql的主从数据库，可以为大负载的需求提供负载均衡，并且可以实现读写分离，可以做更多的优化。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/mysql-master-slov/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>修改mysql的最大连接数</title>
		<link>http://www.linuxsong.org/2010/09/mysql-max-connections/</link>
		<comments>http://www.linuxsong.org/2010/09/mysql-max-connections/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:40:07 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=248</guid>
		<description><![CDATA[mysql 5.0的默认最大连接数为100， 对于大负载量的并发需求可能不够，这时你可以修改mysql的最大连接。
查看mysql的当前最大连接数：
mysqladmin -uroot -ppassword variables &#124; grep max_connections <a href="http://www.linuxsong.org/2010/09/mysql-max-connections/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>mysql 5.0的默认最大连接数为100， 对于大负载量的并发需求可能不够，这时你可以修改mysql的最大连接。<br />
查看mysql的当前最大连接数：<br />
mysqladmin -uroot -ppassword variables | grep max_connections<br />
或者<br />
mysql&gt; SHOW GLOBAL VARIABLES WHERE Variable_name=&#039;max_connections&#039;;</p>
<p>修改方法有如下几种</p>
<p><span id="more-248"></span>1.<br />
mysql&gt; SET GLOBAL max_connections=1000;</p>
<p>修改后会立即生效，不需要重启mysql服务，但是重启后会失效。</p>
<p>2.修改/etc/my.cnf,<br />
在[mysqld] 下面添加：<br />
max_connections=1000</p>
<p>修改后需要重启mysql服务才会重效。<br />
结合第1和第2种方法，可以实现修改立即生效，以后重启也会有效。</p>
<p>3.修改/usr/bin/mysqld_safe<br />
将下面的内容<br />
if test -z &quot;$args&quot;<br />
then<br />
$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file --skip-external-locking &gt;&gt; $err_log 2&gt;&amp;1<br />
else<br />
eval &quot;$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file --skip-external-locking $args &gt;&gt; $err_log 2&gt;&amp;1&quot;</p>
<p>改为（添加红色字体的内容）：<br />
if test -z &quot;$args&quot;<br />
then<br />
$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file --skip-external-locking 　　-O max_connections=1000 &gt;&gt; $err_log 2&gt;&amp;1<br />
else<br />
eval &quot;$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file --skip-external-locking $args -O max_connections=1000 &gt;&gt; $err_log 2&gt;&amp;1&quot;</p>
<p>修改后重启mysql服务后有效。</p>
<p>建议用第一和第二种方法进行修改。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/mysql-max-connections/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux 下查看CPU温度</title>
		<link>http://www.linuxsong.org/2010/09/linux-look-cpu-temperature/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-look-cpu-temperature/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:35:54 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=245</guid>
		<description><![CDATA[在Linux下可以通过lm_sensors来查看CPU的温度(当然你的硬件首先要支持）,要使用这个功能要有内核相关模块(比如I2C)的支持，下面说一下操作方法：

先看一下你的机器上是否安装了lm_sensors, <a href="http://www.linuxsong.org/2010/09/linux-look-cpu-temperature/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>在<a href="http://www.linuxsong.org/category/linux/">Linux</a>下可以通过lm_sensors来查看CPU的温度(当然你的硬件首先要支持）,要使用这个功能要有内核相关模块(比如I2C)的支持，下面说一下操作方法：</p>
<p>先看一下你的机器上是否安装了lm_sensors,<br />
$ rpm -q lm_sensors</p>
<p>如果没有安装就先安装一下<br />
$ sudo yum install -y lm_sensors</p>
<p>检测传感器：<br />
$ sudo sh -c &quot;yes|sensors-detect&quot;</p>
<p><span id="more-245"></span><br />
如果以上步骤没有问题，执行下面的命令就可以查看CPU的温度了：<br />
$ sensors</p>
<p>coretemp-isa-0000<br />
Adapter: ISA adapter<br />
Core 0: +41.0°C (crit = +100.0°C)</p>
<p>coretemp-isa-0001<br />
Adapter: ISA adapter<br />
Core 1: +41.0°C (crit = +100.0°C)</p>
<p>(crit 值应该是上限值）</p>
<p>另外，也可以通过文件查看(我机器用的双核，所以有两个）:<br />
$ cat /proc/acpi/thermal_zone/TZS0/temperature<br />
temperature: 41 C</p>
<p>$ cat /proc/acpi/thermal_zone/TZS1/temperature<br />
temperature: 41 C</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-look-cpu-temperature/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Linux下查看、修改Windows分区的卷标</title>
		<link>http://www.linuxsong.org/2010/09/linux-change-ntfs-vfat-label/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-change-ntfs-vfat-label/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:34:02 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=243</guid>
		<description><![CDATA[在Linux中如何修改Windows分区的卷标呢？我们要用到两个工具：
对于 VFAT 文件系统，可以使用来自 dosfstools 软件包的 >dosfslabel；对于 NTFS 文件系统，可以使用来自 ntfsprogs 软件包的 ntfslabel <a href="http://www.linuxsong.org/2010/09/linux-change-ntfs-vfat-label/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>修改<a href="http://www.linuxsong.org/category/linux/">Linux</a>分区的卷标可以用 e2label,比如要把/dev/sda1 的卷标改为/boot,则可这样</p>
<p>$ e2label /dev/sda1 /boot<br />
查看Linux分区文件系统卷标<br />
$ e2label /dev/sda1<br />
/boot</p>
<p>在Linux中如何修改Windows分区的卷标呢？我们要用到两个工具：<br />
对于 VFAT 文件系统，可以使用来自 dosfstools 软件包的 &gt;dosfslabel；对于 NTFS 文件系统，可以使用来自 ntfsprogs 软件包的 ntfslabel</p>
<p>dosfslabel （若没有安装，Fedora用户可以直接yum install -y dosfstools)<br />
用于VFAT分区，命令用法：<br />
dosfslabel device [label]</p>
<p>如修改vfat分区（fat16,fat32均可)卷标</p>
<p>$ dosfslabel /dev/sda5 /windows</p>
<p>查看vfat分区卷标</p>
<p>$ dosfslabel /dev/sda5</p>
<p>ntfsprogs （若没有安装，Fedora用户可以直接yum install -y ntfsprogs)</p>
<p>用于NTFS分区，命令用法：<br />
ntfslabel device [label]<br />
如修改ntfs分区卷标</p>
<p>$ ntfslabel  /dev/sda6 /xp</p>
<p>查看ntfs分区卷标</p>
<p>$ ntfslabel /dev/sda6<br />
/xp</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-change-ntfs-vfat-label/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>UNIX 高手的 10 个习惯</title>
		<link>http://www.linuxsong.org/2010/09/unix-master-habit/</link>
		<comments>http://www.linuxsong.org/2010/09/unix-master-habit/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:28:05 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=240</guid>
		<description><![CDATA[采用 10 个能够提高您的 UNIX® 命令行效率的好习惯——并在此过程中摆脱不良的使用模式。本文循序渐进地指导您学习几项用于命令行操作的技术，这些技术非常好，但是通常被忽略。了解常见 错误和克服它们的方法，以便您能够确切了解为何值得采用这些 UNIX 习惯。 <a href="http://www.linuxsong.org/2010/09/unix-master-habit/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p>采用 10 个能够提高您的 UNIX® 命令行效率的好习惯——并在此过程中摆脱不良的使用模式。本文循序渐进地指导您学习几项用于命令行操作的技术，这些技术非常好，但是通常被忽略。了解常见 错误和克服它们的方法，以便您能够确切了解为何值得采用这些 <a href="http://www.linuxsong.org/category/linux/">UNIX </a>习惯。</p></blockquote>
<p>当 您经常使用某个系统时，往往会陷入某种固定的使用模式。有时，您没有养成以尽可能最好的方式做事的习惯。有时，您的不良习惯甚至会导致出现混乱。纠正此类 缺点的最佳方法之一，就是有意识地采用抵制这些坏习惯的好习惯。本文提出了 10 个值得采用的 UNIX 命令行习惯——帮助您克服许多常见使用怪癖，并在该过程中提高命令行工作效率的好习惯。下面列出了这 10 个好习惯，之后对进行了更详细的描述。</p>
<p><span id="more-240"></span>要采用的十个好习惯为：</p>
<ol>
<li>在单个命令中创建目录树。</li>
<li>更改路径；不要移动存档。</li>
<li>将命令与控制操作符组合使用。</li>
<li>谨慎引用变量。</li>
<li>使用转义序列来管理较长的输入。</li>
<li>在列表中对命令分组。</li>
<li>在 <code>find</code> 之外使用 <code>xargs</code> 。</li>
<li>了解何时 <code>grep</code> 应该执行计数——何时应该绕过。</li>
<li>匹配输出中的某些字段，而不只是对行进行匹配。</li>
<li>停止对 <code>cat</code> 使用管道。</li>
</ol>
<p>清单 1 演示了最常见的 UNIX 坏习惯之一：一次定义一个目录树。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ mkdir tmp
~ $ cd tmp
~/tmp $ mkdir a
~/tmp $ cd a
~/tmp/a $ mkdir b
~/tmp/a $ cd b
~/tmp/a/b/ $ mkdir c
~/tmp/a/b/ $ cd c
~/tmp/a/b/c $</pre>
</td>
</tr>
</tbody>
</table>
<p>使用 <code>mkdir</code> 的 <code>-p</code> 选项并在单个命令中创建所有父目录及其子目录要容易得多。但是即使对于知道此选项的管理员，他们在命令行上创建子目录时也仍然束缚于逐步创建每级子目录。花时间有意识地养成这个好习惯是值得的：<br />
<a name="listing2"></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ mkdir -p tmp/a/b/c</pre>
</td>
</tr>
</tbody>
</table>
<p>您可以使用此选项来创建整个复杂的目录树（在脚本中使用是非常理想的），而不只是创建简单的层次结构。例如：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}</pre>
</td>
</tr>
</tbody>
</table>
<p>过去，单独定义目录的唯一借口是您的 <code>mkdir</code> 实现不支持此选项，但是在大多数系统上不再是这样了。IBM、AIX®、<code>mkdir</code>、GNU <code>mkdir</code> 和其他遵守单一 UNIX 规范 (Single UNIX Specification) 的系统现在都具有此选项。</p>
<p>对于仍然缺乏该功能的少数系统，您可以使用 <code>mkdirhier</code> 脚本，此脚本是执行相同功能的 <code>mkdir</code> 的包装：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ mkdirhier project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}</pre>
</td>
</tr>
</tbody>
</table>
<p>另一个不良的使用模式是将 .tar 存档文件移动到某个目录，因为该目录恰好是您希望在其中提取 .tar 文件的目录。其实您根本不需要这样做。您可以随心所欲地将任何 .tar 存档文件解压缩到任何目录——这就是 <code>-C</code> 选项的用途。在解压缩某个存档文件时，使用 <code>-C</code> 选项来指定要在其中解压缩该文件的目录：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ tar xvf -C tmp/a/b/c newarc.tar.gz</pre>
</td>
</tr>
</tbody>
</table>
<p>相对于将存档文件移动到您希望在其中解压缩它的位置，切换到该目录，然后才解压缩它，养成使用 <code>-C</code> 的习惯则更加可取——当存档文件位于其他某个位置时尤其如此。</p>
<p>您可能已经知道，在大多数 <a href="http://www.linuxsong.org/category/shell/">Shell</a> 中，您可以在单个命令行上通过在命令之间放置一个分号 (;) 来组合命令。该分号是 Shell <em>控制操作符</em>， 虽然它对于在单个命令行上将离散的命令串联起来很有用，但它并不适用于所有情况。例如，假设您使用分号来组合两个命令，其中第二个命令的正确执行完全依赖 于第一个命令的成功完成。如果第一个命令未按您预期的那样退出，第二个命令仍然会运行——结果会导致失败。相反，应该使用更适当的控制操作符（本文将描述 其中的部分操作符）。只要您的 Shell 支持它们，就值得养成使用它们的习惯。</p>
<p>使用 <code>&amp;&amp;</code> 控制操作符来组合两个命令，以便<em>仅当</em> 第一个命令返回零退出状态时才运行第二个命令。换句话说，如果第一个命令运行成功，则第二个命令将运行。如果第一个命令失败，则第二个命令根本就不运行。例如：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ cd tmp/a/b/c &amp;&amp; tar xvf ~/archive.tar</pre>
</td>
</tr>
</tbody>
</table>
<p>在此例中，存档的内容将提取到 ~/tmp/a/b/c 目录中，除非该目录不存在。如果该目录不存在，则 <code>tar</code> 命令不会运行，因此不会提取任何内容。</p>
<p>类似地，<code>||</code> 控制操作符分隔两个命令，并且仅当第一个命令返回非零退出状态时才运行第二个命令。换句话说，如果第一个命令<em>成功</em>，则第二个命令不会运行。如果第一个命令失败，则第二个命令<em>才会</em> 运行。在测试某个给定目录是否存在时，通常使用此操作符，如果该目录不存在，则创建它：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c</pre>
</td>
</tr>
</tbody>
</table>
<p>您还可以组合使用本部分中描述的控制操作符。每个操作符都影响最后的命令运行：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c &amp;&amp; tar xvf -C tmp/a/b/c ~/archive.tar</pre>
</td>
</tr>
</tbody>
</table>
<p>始 终要谨慎使用 Shell 扩展和变量名称。一般最好将变量调用包括在双引号中，除非您有不这样做的足够理由。类似地，如果您直接在字母数字文本后面使用变量名称，则还要确保将该变 量名称包括在方括号 ([]) 中，以使其与周围的文本区分开来。否则，Shell 将把尾随文本解释为变量名称的一部分——并且很可能返回一个空值。清单 8 提供了变量的各种引用和非引用及其影响的示例。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ ls tmp/
a b
~ $ VAR="tmp/*"
~ $ echo $VAR
tmp/a tmp/b
~ $ echo "$VAR"
tmp/*
~ $ echo $VARa

~ $ echo "$VARa"

~ $ echo "${VAR}a"
tmp/*a
~ $ echo ${VAR}a
tmp/a
~ $</pre>
</td>
</tr>
</tbody>
</table>
<p>您 或许看到过使用反斜杠 (\) 来将较长的行延续到下一行的代码示例，并且您知道大多数 Shell 都将您通过反斜杠联接的后续行上键入的内容视为单个长行。然而，您可能没有在命令行中像通常那样利用此功能。如果您的终端无法正确处理多行回绕，或者您的 命令行比通常小（例如在提示符下有长路经的时候），反斜杠就特别有用。反斜杠对于了解键入的长输入行的含义也非常有用，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ cd tmp/a/b/c || \
&gt; mkdir -p tmp/a/b/c &amp;&amp; \
&gt; tar xvf -C tmp/a/b/c ~/archive.tar</pre>
</td>
</tr>
</tbody>
</table>
<p>或者，也可以使用以下配置：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ cd tmp/a/b/c \
&gt;                 || \
&gt; mkdir -p tmp/a/b/c \
&gt;                    &amp;&amp; \
&gt; tar xvf -C tmp/a/b/c ~/archive.tar</pre>
</td>
</tr>
</tbody>
</table>
<p>然而，当您将输入行划分到多行上时，Shell 始终将其视为单个连续的行，因为它总是删除所有反斜杠和额外的空格。</p>
<p><strong>注意：</strong>在大多数 Shell 中，当您按向上箭头键时，整个多行输入将重绘到单个长输入行上。</p>
<p>大多数 Shell 都具有在列表中对命令分组的方法，以便您能将它们的合计输出向下传递到某个管道，或者将其任何部分或全部流重定向到相同的地方。您一般可以通过在某个 Subshell 中运行一个命令列表或通过在当前 Shell 中运行一个命令列表来实现此目的。</p>
<p>使用括号将命令列表包括在单个组中。这样做将在一个新的 Subshell 中运行命令，并允许您重定向或收集整组命令的输出，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ ( cd tmp/a/b/c/ || mkdir -p tmp/a/b/c &amp;&amp; \
&gt; VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) \
&gt; | mailx admin -S "Archive contents"</pre>
</td>
</tr>
</tbody>
</table>
<p>在此示例中，该存档的内容将提取到 tmp/a/b/c/ 目录中，同时将分组命令的输出（包括所提取文件的列表）通过邮件发送到地址 <code>admin</code>。</p>
<p>当您在命令列表中重新定义环境变量，并且您不希望将那些定义应用于当前 Shell 时，使用 Subshell 更可取。</p>
<p>将命令列表用大括号 ({}) 括起来，以在<em>当前</em> Shell 中运行。确保在括号与实际命令之间包括空格，否则 Shell 可能无法正确解释括号。此外，还要确保列表中的最后一个命令以分号结尾，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ { cp ${VAR}a . &amp;&amp; chown -R guest.guest a &amp;&amp; \
&gt; tar cvf newarchive.tar a; } | mailx admin -S "New archive"</pre>
</td>
</tr>
</tbody>
</table>
<p>使用 <code>xargs</code> 工具作为筛选器，以充分利用从 <code>find</code> 命令挑选的输出。<code>find</code> 运行通常提供与某些条件匹配的文件列表。此列表被传递到 <code>xargs</code> 上，后者然后使用该文件列表作为参数来运行其他某些有用的命令，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ find <em>some-file-criteria some-file-path</em> | \
&gt; xargs <em>some-great-command-that-needs-filename-arguments</em></pre>
</td>
</tr>
</tbody>
</table>
<p>然而，不要将 <code>xargs</code> 仅看作是 <code>find</code> 的辅助工具；它是一个未得到充分利用的工具之一，当您养成使用它的习惯时，将会希望进行所有试验，包括以下用法。</p>
<p>在最简单的调用形式中，<code>xargs</code> 就像一个筛选器，它接受一个列表（每个成员分别在单独的行上）作为输入。该工具将那些成员放置在单个空格分隔的行上：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ xargs
          a
          b
          c

              <em>Control-D</em>

a b c
~ $</pre>
</td>
</tr>
</tbody>
</table>
<p>您可以发送通过 <code>xargs</code> 来输出文件名的任何工具的输出，以便为其他某些接受文件名作为参数的工具获得参数列表，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~/tmp $ ls -1 | xargs
December_Report.pdf README a archive.tar mkdirhier.sh
~/tmp $ ls -1 | xargs file
December_Report.pdf: PDF document, version 1.3
README: ASCII text
a: directory
archive.tar: POSIX tar archive
mkdirhier.sh: Bourne shell script text executable
~/tmp $</pre>
</td>
</tr>
</tbody>
</table>
<p><code>xargs</code> 命令不只用于传递文件名。您还可以在需要将文本筛选到单个行中的任何时候使用它：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~/tmp $ ls -l | xargs
-rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r--r-- 1 \
root root 238 Dec 03 08:19 README drwxr-xr-x 38 joe joe 354082 Nov 02 \
16:07 a -rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar -rwxr-xr-x 1 \
joe joe 3239 Sep 30 12:40 mkdirhier.sh
~/tmp $</pre>
</td>
</tr>
</tbody>
</table>
<p>从技术上讲，使用 <code>xargs</code> 很少遇到麻烦。缺省情况下，文件结束字符串是下划线 (_)；如果将该字符作为单个输入参数来发送，则它之后的所有内容将被忽略。为了防止这种情况发生，可以使用 <code>-e</code> 标志，它在不带参数的情况下完全禁用结束字符串。</p>
<p>避免通过管道将 <code>grep</code> 发送到 <code>wc -l</code> 来对输出行数计数。<code>grep</code> 的 <code>-c</code> 选项提供了对与特定模式匹配的行的计数，并且一般要比通过管道发送到 <code>wc</code> 更快，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ time grep and tmp/a/longfile.txt | wc -l
2811

real    0m0.097s
user    0m0.006s
sys     0m0.032s
~ $ time grep -c and tmp/a/longfile.txt
2811

real    0m0.013s
user    0m0.006s
sys     0m0.005s
~ $</pre>
</td>
</tr>
</tbody>
</table>
<p>除了速度因素外，<code>-c</code> 选项还是执行计数的好方法。对于多个文件，带 <code>-c</code> 选项的<code>grep</code> 返回每个文件的单独计数，每行一个计数，而针对 <code>wc</code> 的管道则提供所有文件的组合总计数。</p>
<p>然而，不管是否考虑速度，此示例都表明了另一个要避免地常见错误。这些计数方法仅提供<em>包含匹配模式的行数</em>——如果那就是您要查找的结果，这没什么问题。但是在行中具有某个特定模式的多个实例的情况下，这些方法无法为您提供实际匹配<em>实例数量</em> 的真实计数。归根结底，若要对实例计数，您还是要使用 <code>wc</code> 来计数。首先，使用 <code>-o</code> 选项（如果您的版本支持它的话）来运行 <code>grep</code> 命令。此选项<em>仅</em> 输出匹配的模式，每行一个模式，而不输出行本身。但是您不能将它与 <code>-c</code> 选项结合使用，因此要使用 <code>wc -l</code> 来对行计数，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ grep -o and tmp/a/longfile.txt | wc -l
3402
~ $</pre>
</td>
</tr>
</tbody>
</table>
<p>在此例中，调用 <code>wc</code> 要比第二次调用 <code>grep</code> 并插入一个虚拟模式（例如 <code>grep -c</code>）来对行进行匹配和计数稍快一点。</p>
<p>当您只希望匹配输出行中<em>特定字段</em> 中的模式时，诸如 <code>awk</code> 等工具要优于 <code>grep</code>。</p>
<p>下面经过简化的示例演示了如何仅列出 12 月修改过的文件。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~/tmp $ ls -l /tmp/a/b/c | grep Dec
-rw-r--r--  7 joe joe  12043 Jan 27 20:36 December_Report.pdf
-rw-r--r--  1 root root  238 Dec 03 08:19 README
-rw-r--r--  3 joe joe   5096 Dec 14 14:26 archive.tar
~/tmp $</pre>
</td>
</tr>
</tbody>
</table>
<p>在此示例中，<code>grep</code> 对行进行筛选，并输出其修改日期和名称中带 <code>Dec</code> 的所有文件。因此，诸如 December_Report.pdf 等文件是匹配的，即使它自从一月份以来还未修改过。这可能不是您希望的结果。为了匹配特定字段中的模式，最好使用<code>awk</code>，其中的一个关系运算符对确切的字段进行匹配，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~/tmp $ ls -l | awk '$6 == "Dec"'
-rw-r--r--  3 joe joe   5096 Dec 14 14:26 archive.tar
-rw-r--r--  1 root root  238 Dec 03 08:19 README
~/tmp $</pre>
</td>
</tr>
</tbody>
</table>
<p><code>grep</code> 的一个常见的基本用法错误是通过管道将 <code>cat</code> 的输出发送到 <code>grep</code> 以搜索单个文件的内容。这绝对是不必要的，纯粹是浪费时间，因为诸如 <code>grep</code> 这样的工具接受文件名作为参数。您根本不需要在这种情况下使用 <code>cat</code>，如以下示例所示：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>~ $ time cat tmp/a/longfile.txt | grep and
2811

real    0m0.015s
user    0m0.003s
sys     0m0.013s
~ $ time grep and tmp/a/longfile.txt
2811

real    0m0.010s
user    0m0.006s
sys     0m0.004s
~ $</pre>
</td>
</tr>
</tbody>
</table>
<p>此错误存在于许多工具中。由于大多数工具都接受使用连字符 (-) 的标准输入作为一个参数，因此即使使用 <code>cat</code> 来分散 <code>stdin</code> 中的多个文件，参数也通常是无效的。仅当您使用带多个筛选选项之一的 <code>cat</code> 时，才真正有必要在管道前首先执行连接。</p>
<p>最好检查一下您的命令行习惯中的任何不良的使用模式。不良的使用模式会降低您的速度，并且通常会导致意外错误。本文介绍了 10 个新习惯，它们可以帮助您摆脱许多最常见的使用错误。养成这些好习惯是加强您的 UNIX 命令行技能的积极步骤。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td colspan="3"><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="5" /></td>
</tr>
<tr align="left" valign="top">
<td></td>
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="4" height="5" /></td>
<td width="100%">Michael Stutz 是 <a href="http://dsl.org/" target="_blank"><em>The Linux Cookbook</em> </a>一书的作者，他仅使用开放源码软件对该书进行了设计和排版。他的研究兴趣包括数字出版和图书的发展未来。他使用各种 UNIX 操作系统已有 20 多年。您可以通过 <a rel="noreferrer">stutz@dsl.org</a> 与他联系。</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/unix-master-habit/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>GNU 与自由软件基金会创始人 Richard Stallman 访谈录</title>
		<link>http://www.linuxsong.org/2010/09/richard-stallman-interview/</link>
		<comments>http://www.linuxsong.org/2010/09/richard-stallman-interview/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:18:07 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=238</guid>
		<description><![CDATA[Richard Stallman 是著名的 GNU 项目，自由软件基金会创始人，这是vnunet.com 对 Richard Stallman 做的一次访谈，谈到了他对自由软件，商业软件以及开源软件看法，另谈到了社会网络站点以及隐私问题。原文作者 Rosalie Marshall。 <a href="http://www.linuxsong.org/2010/09/richard-stallman-interview/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Richard Stallman 是著名的 GNU 项目，自由软件基金会创始人，这是<a href="http://www.vnunet.com/" target="_blank">vnunet.com</a> 对 Richard Stallman 做的一次访谈，谈到了他对自由软件，商业软件以及开源软件看法，另谈到了社会网络站点以及隐私问题。原文作者 Rosalie Marshall。</p>
<p><img src="http://www.comsharp.com/Writable/Resource/_Random_/2008-11-17/Richard_Stallman.jpg" alt="" /></p>
<p><strong>作为自由软件基金会的创始人，你如何定义自由软件？<br />
</strong><br />
<span id="more-238"></span>自由软件意味着尊重用户的自由，更具体地说，作为用户你拥有以下4个最根本的自由：</p>
<ol>
<li>你可以自由使用该软件</li>
<li>研究其源代码并进行修改</li>
<li>可以自由分发该软件</li>
<li>可以自由分发你修改过的版本</li>
</ol>
<p>基于这些自由，用户可以掌控自己的计算，自由软件是在用户的控制下民主地开发起来，而商业软件是在特定团体的控制下专制地开发起来。用户面临的选择是自由还是受限。</p>
<p><strong>你刻意将自己和开源社区保持距离，能否解释一下二者的区别？</strong></p>
<p>开源软件同自由软件在许可上几乎是一致的，因为开源软件是从自由软件基础上发展起来的，最大的区别在于其价值体系。自由软件运动的主要价值是自由与合作，而商业软件是反合作的，这是一个社会问题，我们的目标是改变这个问题。</p>
<p>1990年代，自由软件社区出现了价值分歧，1998年，一些人提出了“开源”一说，开源这个词的初衷这是为了避免隐含对非自由软件的批评，他们关 注他们的实践价值。开源的理念使一些开发者将自己的产品变成自由软件，我欣赏他们对自由软件社区的贡献，但不赞同他们的价值体系。</p>
<p>自由软件更重视价值，而开源软件重视实践，这是二者最大的区别 - 译者。</p>
<p><strong>是什么东西影响你发起自由软件运动？</strong></p>
<p>1970年代，我在 MIT 的 AI 实验室工作，我加入了那时最大的自由软件社区，那个社区包括当时一些大学和公司。在 AI 实验室，我们使用一个免费的操作系统。在自由软件社区的那段时光我意识到了那是和美妙的事。</p>
<p>1980年代，商业压力，连同大型机的衰落最终导致我们的社区解散。后来开始使用商业软件的日子让我感到非常不堪，便决定自己创建一个新的自由软件社区。</p>
<p>1983年，我宣布了开发 GNU 的计划，这是一个完全自由的，类似 Unix 的操作系统，为了区别于 Unix，我起名为 GNU，意思是，Not Unix。</p>
<p><strong>为什么你认为这些不同的名称，开源,自由软件, 商业软件，GNU/Linux 是很重要的？</strong></p>
<p>在自由软件社区，自由软件和开源代表两个不同立场，作为自由软件运动的发起人，我在努力传播自由的理念。因此我拒绝参加开源活动。</p>
<p><strong>我注意到 FSF 的 Shane Coughlan 在同 Google 的开源团队合作。FSF 是否同那些开源组织合作？</strong></p>
<p>Shane 是欧洲 FSF 的，我不知道他在做什么，但我可以告诉你我们的原则，我们同自由软件项目进行技术合作，只要它是有用的，不管开发者是否认同自由软件的价值观。</p>
<p><strong>在你看来 OpenOffice 与 Firefox 一类的软件是否自由软件？</strong></p>
<p>OpenOffice is free software, and has been ever since it appeared under that name. OpenOffice 一直是。</p>
<p>Firefox 是个奇怪的个案，一开始，Firefox 代码是自由的，但编译的二进制文件不是。他们不是自由软件的理由有二，第一，他们包含一个非自由模块，Talkback，Talkback 的代码不能自由获得（甚至 Mozilla 基金会也得不到），第二，他们使用具有限制性的 EULA （用户许可协议）。</p>
<p>不过，这两个问题现在好象已经改正，所以现在应该也是自由软件。</p>
<p><strong>你对一些地理位置监控类的程序如何看，比如 Yahoo 的 Fire Eagle？</strong></p>
<p>如果你要告诉朋友们你在哪里，这很好，但你不能将自己的交流数据放往一个你不信任的公司的服务器。这个程序可能有一个“删除以往数据”的命令，但你不知道他们是否真这样做了。这是 Internet 被错误利用的很不好的趋势，就是将用户的交流数据送往某个公司的服务器。</p>
<p><strong>你对社会网络站点如何看待？</strong></p>
<p>我从来不用所以没有发言权。我看不出在你的朋友之间分享信息和照片有什么不好，我曾听到传闻，说 Facebook 将私人数据传给 CIA，不知真假。</p>
<p><strong>你觉得 Asus EeePC 一类的笔记本电脑是否推动 FSF。</strong></p>
<p>不 完全是。EeePC 内置了一些 GNU/Linux 操作系统，但也包含很多非自由软件。事实上，这些机器在启用前要求你接受一些用户协议。我受到一个 EeePC 礼物，但我不能使用，因为我的良心不允许我接受那些协议，后来我让人帮我装了一个自由的 GNU/Linux 才开始用。</p>
<p><strong>当自由软件出了问题，谁该负责？</strong></p>
<p>自由软件开发者和商业开发者一样尽我们所能来保证软件的可靠性。自由软件给了用户比起诉软件商更好的东西，如果系统除了问题，你很容易找到人帮你排除，只要价格公道。（未必，当然商业软件也未必 - 译者）</p>
<p><strong>为什么你们在印度和委内瑞拉一类的地区如此卖力推广自由软件？</strong></p>
<p>这 个问题会让人误解，其实我每年花在美国的演讲时间比委内瑞拉和印度要多得多。但我确实花了很多时间外出演讲。委内瑞拉, 厄瓜多尔 一类的地区有政策要求所有政府部门必须使用自由软件。在印度，有三个省的公立学校要求使用 GNU/Linux。我希望在美国也能看到人们对用户的自由的重视。</p>
<p><strong>你是否认为公共部门应该引领自由软件浪潮？</strong></p>
<p>任何公共部门都应该拥有对自己的计算的控制，而非自由软件的控制权在厂商那里。因此，公共部门应当拒绝商业软件而投身自由软件。委内瑞拉, 厄瓜多尔做得对。</p>
<p><strong>一些慈善机构，如 Computer Aid International 会把一些二手电脑收集起来送给发展中国家，如果也投身 GUN，是否意味着会有更少的学校能得到电脑？</strong></p>
<p>你 可以在任何电脑上安装 GNU/<a href="http://www.linuxsong.org/category/linux/">Linux</a>，因为使用自由软件并不意味着他们可以捐赠的电脑变少。更进一步，我们的本意是让计算机造福，但将装有 Windows 的电脑送给他们是好事吗？使用商业软件意味着向开发商屈服，这是一个社会问题，我们应该消除这个问题，而不是扩大。向他们捐赠 Windows 电脑是一种屈服，走的是错误的道路。</p>
<p><strong>自由软件如何同当前的经济环境契合？一些人认为经济危机是对资本主义体系的控诉，这是否公正的看法？</strong></p>
<p>和以前一样，自由软件可以同各种经济环境契合，不管经济是好还是坏，你都需要自由。我认为经济危机来自一种普遍存在的深度腐败，因为公司拥有过多政治力量。不公平的版权法律也是这个基本问题的结果。</p>
<p><strong>自由软件固然可以节省成本，但那些在商业软件工作的人怎么办？如果人们都使用自由软件，而不再需要商业软件？</strong></p>
<p>这里存在一个误区，自由软件并不减少技术支持市场。那些购买了商业软件又转用自由软件的人仍然需要支持，自由软件的好处是它允许自由的支持市场。</p>
<p>另外，还有些更根本的东西，就是价值，似乎我们在假设人们喜欢被不公正的权力所左右，我在那里需要人们妥协自己的自由才能使用的软件那里看不到积极 的价值。我自己不会使用这样的软件。我在1983年发起 GNU 项目，就是为了脱离商业软件，现在我离开了，就不会再回来。我希望看到没有人再为商业软件从事开发的那一天。</p>
<p>转自：<a href="http://www.comsharp.com/" target="_blank">COMSHARP CMS</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/richard-stallman-interview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用 Shell 进行进制转换</title>
		<link>http://www.linuxsong.org/2010/09/shell-decimal-conversion/</link>
		<comments>http://www.linuxsong.org/2010/09/shell-decimal-conversion/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:13:05 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=236</guid>
		<description><![CDATA[假定在您的脚本中有一些数字，您需要以另外的进制处理这些数字。使用 Shell 运算可以很容易地自动实现这类转换。一种情况是使用 Shell 运算把一个数字从给定的进制转换位十进制。如果数字以运算展开式的形式提供，那么假定它带有十进制符号，除非 它前面带有 0（这种情况假定是八进制）或 0x（这种情况假定是十六进制）。键入以下内容以得到一些八进制和十六进制值的十进制输出： <a href="http://www.linuxsong.org/2010/09/shell-decimal-conversion/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>假定在您的脚本中有一些数字，您需要以另外的进制处理这些数字。使用 <a href="http://www.linuxsong.org/category/shell/">Shell</a> 运算可以很容易地自动实现这类转换。一种情况是使用 Shell 运算把一个数字从给定的进制转换位十进制。如果数字以运算展开式的形式提供，那么假定它带有十进制符号，除非 它前面带有 0（这种情况假定是八进制）或 0x（这种情况假定是十六进制）。键入以下内容以得到一些八进制和十六进制值的十进制输出：</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<pre>$ <strong>echo $((013))</strong>
$ <strong>echo $((0xA4))</strong></pre>
</td>
</tr>
</tbody>
</table>
<p>您还可以使用以下格式指定 2 到 64 之间的任意进制：</p>
<p><span id="more-236"></span></p>
<table border="0" cellspacing="0" cellpadding="0" width="572">
<tbody>
<tr>
<td>
<pre>$((BASE#NUMBER))
</pre>
</td>
</tr>
</tbody>
</table>
<p>通过在 Shell 提示符后键入清单 7 中所示的行，尝试将二进制、八进制、十六进制以及其他进制的数转换为十进制。<br />
<a name="listing7"><strong>清单 7. 在 Shell 中将任意进制的数以十进制输出</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="572">
<tbody>
<tr>
<td>
<pre>
echo $((2#1101010))
echo $((8#377))
echo $((16#D8))
echo $((12#10))
echo $((36#ZZYY))</pre>
</td>
</tr>
</tbody>
</table>
<p><a name="bc"><strong>使用 bc 进行进制转换</strong></a></p>
<p>在 <a href="http://www.linuxsong.org/category/shell/">Shell</a> 中进行进制转换的另一个诀窍是使用 <code>bc</code>，它是一种任意精度运算语言，大多数 UNIX/<a href="http://www.linuxsong.org/category/linux/">Linux</a> 安装程序都提供。因为它允许您指定输出进制，所以当您需要以十进制以外的进制输出时，这是一种很好的技术。</p>
<p><code>bc</code> 的特殊变量 <code>ibase</code> 和 <code>obase</code> 分别包含用于输入和输出的进制的值。缺省情况下，都被设置为 10。要执行进制转换，需要改变其中的一个或两个值，然后提供一个数字。立即尝试，如清单 8 中所示。<br />
<a name="listing8"><strong>清单 8. 使用 bc 执行进制转换</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<pre>
$ <strong>bc -ql</strong>
<strong>   10</strong>
10
<strong>obase=16</strong>
<strong>   10</strong>
A
<strong>ibase=2</strong>
<strong>   10</strong>
2</pre>
</td>
</tr>
</tbody>
</table>
<p>要快速执行进制转换，可以联合使用 <code>bc</code> 和 <code>echo</code>形成快捷的单命令行程序，将给定的值通过管道传输给 <code>bc</code>。键入清单 9 中显示的内容。<br />
<a name="listing9"><strong>清单 9. Shell 单命令行 bc 程序</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<pre>
$ <strong>echo 'obase=16; 47' | bc</strong>
2F
$ <strong>echo 'obase=10; ibase=16; A03' | bc</strong>
2563</pre>
</td>
</tr>
</tbody>
</table>
<p><strong>警告：</strong>当您设置 <code>bc</code> 的输入进制以后，输入 <code>bc</code> 的所有数字都使用该进制，包括您提供用于设置输出进制的数字。因此最好先设置输出进制，否则可能会产生意想不到的结果，如清单 10 中所示。<br />
<a name="listing10"><strong>清单 10. 设置输入和输出进制的先后顺序的重要性</strong></a></p>
<pre>
$ <strong>echo 'ibase=16; obase=10; A' | bc</strong>
A
$ <strong>echo 'ibase=16; obase=A; A' | bc</strong>
10</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/shell-decimal-conversion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>awk内置字符串函数详解</title>
		<link>http://www.linuxsong.org/2010/09/awk-string-function/</link>
		<comments>http://www.linuxsong.org/2010/09/awk-string-function/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:06:26 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[awk]]></category>
		<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=230</guid>
		<description><![CDATA[awk提供了许多强大的字符串函数，见下表：
awk内置字符串函数 <a href="http://www.linuxsong.org/2010/09/awk-string-function/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>awk提供了许多强大的字符串函数，见下表：<br />
<a href="http://www.linuxsong.org/category/awk/">awk</a>内置字符串函数</p>
<table id="c-nq" border="0" cellspacing="0" cellpadding="3">
<tbody>
<tr>
<td width="50%">gsub(r,s)</td>
<td width="50%">在整个$0中用s替代r</td>
</tr>
<tr>
<td width="50%">gsub(r,s,t)</td>
<td width="50%">在整个t中用s替代r</td>
</tr>
<tr>
<td width="50%">index(s,t)</td>
<td width="50%">返回s中字符串t的第一位置</td>
</tr>
<tr>
<td width="50%">length(s)</td>
<td width="50%">返回s长度</td>
</tr>
<tr>
<td width="50%">match(s,r)</td>
<td width="50%">测试s是否包含匹配r的字符串</td>
</tr>
<tr>
<td width="50%">split(s,a,fs)</td>
<td width="50%">在fs上将s分成序列a</td>
</tr>
<tr>
<td width="50%">sprint(fmt,exp)</td>
<td width="50%">返回经fmt格式化后的exp</td>
</tr>
<tr>
<td width="50%">sub(r,s)</td>
<td width="50%">用$0中最左边最长的子串代替s</td>
</tr>
<tr>
<td width="50%">substr(s,p)</td>
<td width="50%">返回字符串s中从p开始的后缀部分</td>
</tr>
<tr>
<td width="50%">substr(s,p,n)</td>
<td width="50%">返回字符串s中从p开始长度为n的后缀部分</td>
</tr>
</tbody>
</table>
<p>详细说明一下各个函数的使用方法。</p>
<p><span id="more-230"></span>gsub函数有点类似于sed查找和替换。它允许替换一个字符串或字符为另一个字符串或字符，并以正则表达式的形式执行。第一个函数作用于记录$0，第二个gsub函数允许指定目标，然而，如果未指定目标，缺省为$0。<br />
index(s,t)函数返回目标字符串s中查询字符串t的首位置。length函数返回字符串s字符<br />
长度。match函数测试字符串s是否包含一个正则表达式r定义的匹配。split使用域分隔符fs将<br />
字符串s划分为指定序列a。sprint函数类似于printf函数(以后涉及)，返回基本输出格式fmt的<br />
结果字符串exp。sub(r,s)函数将用s替代$0中最左边最长的子串，该子串被(r)匹配。<br />
sub(s,p)返回字符串s在位置p后的后缀。substr(s,p,n)同上，并指定子串长度为n。<br />
现在看一看awk中这些字符串函数的功能。</p>
<p>1.gsub<br />
要在整个记录中替换一个字符串为另一个，使用正则表达式格式，/目标模式/，替换模式<br />
/。例如改变学生序号4842到4899：</p>
<p>$ awk &#039;gsub(&#039;4842/, 4899) {print $0}&#039; grade.txt<br />
J.Troll 07/99 4899 Brown-3 12 26 26</p>
<p>2.index<br />
查询字符串s中t出现的第一位置。必须用双引号将字符串括起来。例如返回目标字符串<br />
Bunny中ny出现的第一位置，即字符个数。</p>
<p>$ awk &#039;BEGIN {print index(&quot;Bunny&quot;, &quot;ny&quot;)} grade.txt<br />
4</p>
<p>3.length<br />
返回所需字符串长度，例如检验字符串J.Troll返回名字及其长度，即人名构成的字符个<br />
数。</p>
<p>$ awk &#039;$1==&quot;J.Troll&quot; {print length($1) &quot; &quot;$1}&#039; grade.txt<br />
7 J.Troll</p>
<p>还有一种方法，这里字符串加双引号。</p>
<p>$ awk &#039;BEGIN {print length(&quot;A FEW GOOD MEN&quot;)}&#039;<br />
14</p>
<p>4.match<br />
match测试目标字符串是否包含查找字符的一部分。可以对查找部分使用正则表达式,返<br />
回值为成功出现的字符排列数。如果未找到,返回0,第一个例子在ANCD中查找d。因其不<br />
存在,所以返回0。第二个例子在ANCD中查找D。因其存在,所以返回ANCD中D出现的首位<br />
置字符数。第三个例子在学生J.Lulu中查找u。</p>
<p>$ awk &#039;{BEGIN {print match(&quot;ANCD&quot;, /d/)}&#039;<br />
0<br />
$ awk &#039;{BEGIN {print match(&quot;ANCD&quot;, /C/)}&#039;<br />
3<br />
$ awk &#039;$1==&quot;J.Lulu&quot; {print match($1, &quot;u&quot;)} grade.txt<br />
4</p>
<p>5.split<br />
使用split返回字符串数组元素个数。工作方式如下：如果有一字符串,包含一指定分隔<br />
符-,例如AD2-KP9-JU2-LP-1,将之划分成一个数组。使用split,指定分隔符及数组名。此<br />
例中,命令格式为(&quot;AD2-KP9-JU2-LP-1&quot;,parts_array,&quot;-&quot;),split然后返回数组下标数,这<br />
里结果为4。<br />
还有一个例子使用不同的分隔符。</p>
<p>$ awk &#039;{BEGIN {print split(&quot;123#456#678&quot;, myarray, &quot;#&quot;)}&#039;<br />
3</p>
<p>这个例子中,split返回数组myarray的下标数。数组myarray取值如下：</p>
<p>Myarray[1]=&quot;123&quot;<br />
Myarray[2]=&quot;456&quot;<br />
Myarray[3]=&quot;789&quot;</p>
<p>6.sub<br />
使用sub发现并替换模式的第一次出现位置。字符串STR包含‘popedpopopill’,执行下<br />
列sub命令sub(/op/,&quot;op&quot;,STR)。模式op第一次出现时,进行替换操作,返回结果如下：<br />
‘pOPedpopepill’。<br />
假如grade.txt文件中,学生J.Troll的记录有两个值一样,“目前级别分”与“最高级别分”。只<br />
改变第一个为29,第二个仍为24不动,操作命令为sub(/26/,&quot;29&quot;,$0),只替换第一个出现<br />
24的位置。</p>
<p>$ awk &#039;$1==&quot;J.Troll&quot; sub(/26/, &quot;29&quot;, $0)&#039; grade.txt<br />
L.Troll 07/99 4842 Brown-3 12 29 26<br />
L.Transley 05/99 4712 Brown-2 12 30 28</p>
<p>7.substr<br />
substr是一个很有用的函数。它按照起始位置及长度返回字符串的一部分。例子如下：</p>
<p>$ awk &#039;$1==&quot;L.Transley&quot; {print substr($1, 1,5)}&#039; grade.txt<br />
L.Tan<br />
上面例子中,指定在域1的第一个字符开始,返回其前面5个字符。<br />
如果给定长度值远大于字符串长度， awk将从起始位置返回所有字符，要抽取L.Tansley的姓,只需从第3个字符开始返回长度为7。可以输入长度99,awk返回结果相同。</p>
<p>$ awk &#039;{$1==&quot;L.Transley&quot; {print substr($1, 3,99)}&#039; grade.txt<br />
Transley</p>
<p>substr的另一种形式是返回字符串后缀或指定位置后面字符。这里需要给出指定字符串及其返回字串的起始位置。例如,从文本文件中抽取姓氏,需操作域1,并从第三个字符开始：</p>
<p>$ awk &#039;{print substr($1, 3)}&#039; grade.txt<br />
Troll<br />
Transley</p>
<p>还有一个例子,在BEGIN部分定义字符串,在END部分返回从第t个字符开始抽取的子串。</p>
<p>$ awk &#039;{BEGIN STR=&quot;A FEW GOOD MEN&quot;} END {print substr(STR,7)) grade.txt<br />
GOOD MEN</p>
<p>8.从<a href="http://www.linuxsong.org/category/shell/">shell</a>中向awk传入字符串<br />
awk脚本大多只有一行,其中很少是字符串表示的,这一点通过将变量传入awk命令行会变得很容易。现就其基本原理讲述一些例子。<br />
使用管道将字符串stand-by传入awk,返回其长度。</p>
<p>$ echo &quot;Stand-by&quot; | awk &#039;{print length($0)}&#039;<br />
8</p>
<p>设置文件名为一变量,管道输出到awk,返回不带扩展名的文件名。</p>
<p>$ STR=&quot;mydoc.txt&quot;<br />
$ echo $STR | awk &#039;{print subst($STR, 1, 5)}&#039;<br />
mydoc</p>
<p>设置文件名为一变量,管道输出到awk,只返回其扩展名。<br />
$ STR=&quot;mydoc.txt&quot;<br />
$ echo $STR | awk &#039;{print substr($STR, 7)}&#039;<br />
txt</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/awk-string-function/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux禁止单用户模式(single)来增强系统安全</title>
		<link>http://www.linuxsong.org/2010/09/linux-disable-single-user/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-disable-single-user/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:05:02 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=228</guid>
		<description><![CDATA[一、Linux忘记root密码，进入单用户模式修改密码

（一）、关于lilo

1. 在出现 lilo: 提示时键入 Linux single

画面显示 lilo: Linux single <a href="http://www.linuxsong.org/2010/09/linux-disable-single-user/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>一、<a href="http://www.linuxsong.org/category/linux/">Linux</a>忘记root密码，进入单用户模式修改密码</p>
<p>（一）、关于lilo</p>
<p>1. 在出现 lilo: 提示时键入 Linux single</p>
<p>画面显示 lilo: Linux single</p>
<p>2. 回车可直接进入Linux命令行</p>
<p>3. 用password命令修改密码</p>
<p>（二）、关于 grub</p>
<p>1. 在出现grub画面时，用上下键选中你平时启动Linux的那一项，然后按e键</p>
<p>2. 再次用上下键选中你平时启动Linux的那一项(类似于kernel/boot/vmlinuz-2.4.18-14 ro root=LABEL=/)，然后按e键</p>
<p>3. 修改你现在见到的命令行，后加上数字1或者single：</p>
<p><span id="more-228"></span>kernel /boot/vmlinuz-2.4.18-14 single ro root=LABEL=/ 1</p>
<p>kernel /boot/vmlinuz-2.4.18-14 single ro root=LABEL=/ single</p>
<p>4. 回车返回，然后按b键启动，即可直接进入Linux命令行</p>
<p>5.直接输入passwd 回车即可修改密码，在默认情况下这里直接回车是直接修改ROOT超级管理用户的密码，当然，你要修改其他用户密码，在PASSWD后直接跟需要修改密码的用户名即可。</p>
<p>或</p>
<p>#vi /etc/shadow</p>
<p>将第一行，即以root开头的一行中root:后和下一个:前的内容删除，</p>
<p>第一行将类似于</p>
<p>root::......</p>
<p>保存</p>
<p>#reboot重启，root密码为空。</p>
<p>（三）使用redhat的第一张安装光盘启动，在出现&#039; boot：&#039;时，输入“Linux rescue”，然后一直按回车，直到出现命令提示符后，输入“chroot /mnt/sysimage ”取得root权限，再输入“password root”修改root密码，再reboot就好了</p>
<p>二、禁止进入单用户模式</p>
<p>如果禁止进入单用户,首先要对GRUB进行密码配置，只需要修改/boot/grub/grub.conf或者 /etc/grub.conf（/etc/grub.conf是/boot/grub/grub.conf的符号链接），例如:vi /boot/grub/grub.conf进入配置文件编辑。</p>
<p>这里我们介绍个方法,给grub加个密码,增禁止他人以单用户模式进入系统. 有2个方式：</p>
<p>1、明文方式</p>
<p>在splashimage这个参数下一行添加: password=密码。保存后重新启动计算机，再次登录到GRUB菜单页面的时候就会发现，这时已经不能直接使用e命令编辑启动标签了，须先使用p命 令，输入正确的密码后才能够对启动标签进行编辑.但是我们设置了明文密码也不是很安全的.如果他人得到了明文密码后仍然可以修改GRUB启动标签从而修改 root密码.</p>
<p>2、MD5加密方式</p>
<p>在终端中输入grub-md5-crypt回车，这时系统会要求输入两次相同的密码，之后系统便会输出MD5码。大家只需要将生成的MD5密文复制 下来，在splashimage这个参数下一行添加: password --md5 MD5密文比如: splashimage=(hd0,0)/grub/splash.xpm.gz</p>
<p>password --md5 $1$xI6vS$Wi5pi8JyORUNnj3/0Yq2/0</p>
<p>hiddenmenu</p>
<p>保存后重新启动计算机,再次登录到GRUB菜单页面的时候就会发现,这时已经不能直接使用e命令编辑启动标签了,须先使用p命令,输入正确的密码后才能够对启动标签进行编辑。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-disable-single-user/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>“懒惰”Linux：“懒惰”集群管理员的 11 个秘诀</title>
		<link>http://www.linuxsong.org/2010/09/linux-lazy-administrator/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-lazy-administrator/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 03:01:25 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=224</guid>
		<description><![CDATA[集群 对于不同的人有不同的含义。在本文的上下文中，集群最好定义为横向扩展（scale-out）—— 横向扩展集群一般包含大量相同类型的组件，比如 Web 场、表示场和高性能计算 (HPC) 系统。管理员会告诉您，对于横向扩展集群，必须百千次地重复修改，无论修改是多么小；最懒惰的管理员精通横向扩展管理技术，因此无论节点的数量有多少，需 要的工作量都是相同的。在本文中，作者将泄露世界上最懒惰的 Linux® 管理员的秘诀。 <a href="http://www.linuxsong.org/2010/09/linux-lazy-administrator/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p><em>集群</em> 对于不同的人有不同的含义。在本文的上下文中，集群最好定义为<em>横向扩展（scale-out）</em>—— 横向扩展集群一般包含大量相同类型的组件，比如 Web 场、表示场和高性能计算 (HPC) 系统。管理员会告诉您，对于横向扩展集群，必须百千次地重复修改，无论修改是多么小；最懒惰的管理员精通横向扩展管理技术，因此无论节点的数量有多少，需 要的工作量都是相同的。在本文中，作者将泄露世界上最懒惰的 Linux® 管理员的秘诀。</p></blockquote>
<p>自从世界上最快 的 500 台计算机清单于 1998 年首次发布以来，<a href="http://www.linuxsong.org/category/linux/">Linux</a> 集群已经从科学实验项目发展成了当今超级计算领域的主流技术。实际上，在 1998 年的 Top 500 清单中 Linux 集群只占据一席（一个集群，一个 Linux 操作系统），但是在 2008 年的清单中占据了五分之四（400 个集群，458 个 Linux 操作系统）。</p>
<p><span id="more-224"></span>管理 Linux 集群需要很独特的技能，单一系统或小型连网系统的 IT 管理员往往不具备这些技能。管理 Linux 集群要求管理员深入理解连网、操作系统和体系结构中的所有子系统。</p>
<p>但是，不仅如此：它还要求采取另一种态度。它要求 “懒惰”。它要求管理员听从 Scrooge McDuck 在 Duckburg 中对侄子们的教导：“工作越巧妙，就越轻松” 。</p>
<p>在本文中，我们讨论最懒惰的 Linux 集群管理员的一些秘诀。尽管它们并不是真正的秘诀，但是由于某种原因，人们要么不了解这些思想，要么低估了它们的作用。为了纠正这个问题，我们在讨论这些秘诀的同时会解释它们的重要性。</p>
<table border="0" cellspacing="0" cellpadding="0" width="40%" align="right">
<tbody>
<tr>
<td width="10"><img src="http://www.ibm.com/i/c.gif" alt="" width="10" height="1" /></td>
<td>
<table border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td bgcolor="#eeeeee"><a name="sidebar1"></a></p>
<ul>
<li><a href="http://www.linuxsong.org/2010/09/linux-administrator-skill/">“懒惰” Linux 管理员的 10 个关键技巧</a></li>
</ul>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>些秘诀是：</p>
<ol>
<li>不要开发已有的东西。</li>
<li>使用开放源码软件。</li>
<li>将所有东西自动化。</li>
<li>在设计时就考虑到可伸缩性 —— 从一开始就要计划偷懒。</li>
<li>在设计时就考虑到硬件的可管理性。</li>
<li>使用出色的集群管理软件 —— 工欲善其事，必先利其器。</li>
<li>使用开放源码的监视解决方案。</li>
<li>用队列系统控制用户。</li>
<li>检验付出所得到的回报 —— 执行基准测试！</li>
<li>管理集群管理员交流。</li>
<li>不断寻找更懒惰的办法。</li>
</ol>
<p><a name="N100EF"></a></p>
<p>懒惰的 Linux 集群管理员不会开发已有的东西；他们主要依靠别人的成果来完成自己的任务。如果已经有免费的得到良好支持的解决方案，那么浪费时间开发应用程序又有什么意义呢？</p>
<p>世 界上最稀少的东西之一是独创的思想或首次出现的问题，在 Linux 集群环境中尤其如此。很少会遇到在 2004 年出现并且没有解决的问题。这是好事情；您应该相信实际上没有什么问题是不能解决的（从技术上说是这样，但是在政治和社会方面就不一定了）。因此，要接受 这个现实：大多数问题都已经被发现、诊断和解决了。</p>
<p>为了少浪费时间，有经验的管理员会在以下方面多花些时间：</p>
<ul>
<li>研究现有的解决方案并根据自己的需要采用它们。牛顿在评价自己的成就时曾经引用 Bernard of Chartres 的话说，他是站在 “巨人的肩膀上”。如果他没有首先尝试理解欧几里得原理，就不可能建立自己的理论体系，但是这并不会抹杀他的成就。</li>
<li>对开放源码项目做贡献或进行定制，而不是重新发明已经存在的东西 —— 他完全明白，如果自己编写软件，那么在他跳槽时很可能会留下一个烂摊子，因为没有别人了解他写的软件。</li>
</ul>
<p>我们并不想扼杀您的创造力 —— 其实正好相反。利用别人已经完成的成果会帮助您进入更高的层次，这会使您的环境比其他组织的 IT 环境更出色更高效。</p>
<p><a name="N1010B"></a></p>
<p>我 们认识的最成功的 Linux 集群管理员都非常了解当前的开放源码项目。他们是邮件列表的积极参与者，当在网络上搜索时会发现他们的名字常常与热门的项目联系在一起。他们常常在 http://sourceforge.net 和 http://freshmeat.net 上寻找感兴趣的新项目。</p>
<p>开放源码工具的性质使它们的寿命很长，对于流行的工具尤其如此。例如，尽管 Ganglia、Nagios 和 TORQUE 等工具已经存在很长时间了，但是仍然有不少人在使用它们。它们很出色，能够帮助管理员节省软件成本并避免许可协议的限制。</p>
<p>最 懒惰的集群管理员的另一个特点是，他们对开放源码运动都非常热心，愿意在自己的工作中使用开放源码软件。他们可能在家里建立自己的 Web 服务器，或者在 Linux 笔记本计算机上运行应用程序。您会发现最懒惰的 Linux 管理员除了在工作中负责管理的集群之外，在他们生活中的其他方面也常常运行 Linux，包括 Pidgin 和 Firefox 等各种软件。</p>
<p><a name="N1011B"></a></p>
<p>在命令行上使用脚本和其他快速工具在 Linux 管理员的工作中占很大部分。脚本（只要不是重新发明任何东西）有两个优点：</p>
<ul>
<li>最显著的优点是，它节省了输入命令的时间，提供可重复执行的命令模式。</li>
<li>第二个优点是，它可以说明本身的用途，便于以后重用。</li>
</ul>
<p>我们常常发现，有经验的管理员会在自己的计算机上用专门的目录存储他们编写的脚本。这些脚本的用途五花八门，从检查节点上的防火墙版本到映射 InfiniBand 集群中的 GUID。</p>
<p>非 常适合使用脚本的一种情况是生成操作系统映像（无论是无状态的还是有状态的）。如果管理员有一个 “黄金映像”，需要把它传播到系统中的每个计算节点，那么他应该了解其中包含的内容。创建此映像的脚本就是最好的文档，因为它精确地解释了执行的操作，而 且是可重复执行的。如果没有构建映像的脚本，就会发生映像膨胀，导致占用的空间增加和系统速度下降。</p>
<p>我们常常遇到一些组织有黄金映像，他们自 2000 年以来一直使用这些映像。最大的原因是：他们不知道如何重新构建它。第二个（可能更重要的）原因是：他们的应用程序已经在此映像上测试和 “认证” 过了。<em>认证</em> 是经常会遇到的词，但是它的定义与<em>云计算</em> 一样含糊不清（顺便说一句，“云计算” 这个词汇不是专利，也不是商标词）。</p>
<p>应 该把工作自动化的原因是：避免工作比实际做工作需要更多的脑力。懒惰的 Linux 集群管理员不会做那些让他们的脑子变得迟钝的工作。如果您不得不在集群中的每台计算机上启动 ssh 并运行一个命令，那么您就是不够懒。对节点执行的所有命令都应该通过并行命令或过程自动执行。如果硬件厂商没有提供自动化的 Linux 工具来更新 BIOS 或刷新子系统，那么在考虑成本时要算上这个因素。</p>
<p>我们的前一篇文章 ““懒惰” Linux 管理员的 10 个关键技巧” 中的技巧 8 和技巧 10 讲解了我们常用的几种命令行脚本编程技术。还有其他许多方法，而且其中一部分可能效率更高，这些技巧只是提供一个思路，促使您思考脚本可以完成哪些工作。</p>
<p>第三个秘诀（自动化）是一个大目标，但它只是实现<em>完全清闲</em> 的过程中的一个步骤。对于最懒惰的管理员，“完全清闲” 只能通过自治的横向扩展管理来实现。实现此目标的第一步是在系统中避免不可伸缩的操作。</p>
<p>大 型横向扩展集群的主要麻烦是瓶颈。大多数横向扩展集群管理员使用 TFTP 执行网络引导或安装大量计算机。任何有经验的横向扩展集群管理员都会告诉您，TFTP 不可靠而且不可伸缩。如果没有适当的远程硬件控制，那么只要发生一次大规模的 TFTP 故障，管理员就不得不从椅子里跳起来，直奔数据中心，复位每台计算机（够他忙的）！即使有适当的远程硬件控制，管理员也必须长时间停止玩 <em>WoW</em>，因为必须一次又一次向集群中的节点发送复位命令（这也不轻松）。</p>
<p>只需提前做一点计划管理，就可以避免瓶颈（比如下面的瓶颈）。</p>
<p>DHCP、TFTP、HTTP、NFS 和 DNS 是集群最常用的服务。它们都会形成瓶颈 —— 在集群扩展时，TFTP 是最糟糕的。幸运的是，很容易通过复制它们来帮助伸缩。</p>
<p>提示：把 DHCP 和 TFTP 隔离在另一个 NIC 中，这会极大地提高可伸缩性。例如，如果与其他供应服务共享 NIC，我们度量出的 TFTP 伸缩比是 40:1；如果不共享或者采用无状态引导，结果是 80:1。</p>
<p>网络常常是设计中最容易被忽视的部分。这里说的网络是指用于管理的 GigE 网络，而不是专门用于应用程序通信的高性能网络。尽管在许多情况下只有一个网络必须是共享的（用于数据和管理），但是这可能导致许多伸缩问题。</p>
<p>在设计层次化网络时，一定要注意，不要太保守。如果要求节点与服务节点比例达到 80:1，那么要确保在整个结构中保持或超过此比例。</p>
<p>在 设计大型横向扩展集群时，我们采取 “集群的集群” 方式。每个子集群（即可伸缩单元，SU）是一个构造块，其本身可以针对所有集群操作（例如，安装、网络引导、BIOS 更新、监视等）扩展。每个 SU 有一个或多个服务节点（数量取决于 SU 的规模），它们提供对 SU 中所有节点进行控制、监视和供应所需的服务。为了进一步帮助可伸缩管理，每个 SU 有自己的广播域（路由 SU-to-SU 和 SU-to-World 通信 —— 检查瓶颈）。</p>
<p>中心管理节点和服务节点有一个私有的物理或虚拟网络，因此从服务节点发送出的信息和发送到服务节点的数据不会干扰其他集群的通信流。我们把此网络、管理节点和服务节点称为<em>层次化管理云 (hierarchal management cloud, HMC)</em>。它的设置和操作只在管理员的域中进行。</p>
<p>这种 “集群的集群” 方式使懒惰的管理员设计的系统能够超过预期规模，支持集中的管理控制，同时不必担心大规模操作失败。</p>
<p>许 多管理员在设计集群时并没有考虑到 “可控制” 方面。高效的管理员都操作可控制集群，也就是说他们的集群放置在黑屋子中，远离工作人员，在理想情况下人们几周或几个月都不必看到他们每天操作的物理机 器。在某些情况下，他们从来都没见过这些物理机器，因为他们是在世界的另一端管理它们。当然，最懒惰的管理员甚至不知道数据中心的具体位置 —— 对于他们来说，数据中心仅仅是一组主机名或 IP 地址。</p>
<p>数据中心噪音很大，有时候很冷，甚至可能有危险； 懒惰的管理员应该尽可能避免到数据中心去。有人甚至认为呆在充满大量机器的房间里可能有对健康有害，尽管还没有发现这方面的证据。随着电力/制冷/人力成 本的上升，越来越多的数据中心被转移到运营成本比较低的地方。因此，绝对的远程控制现在对于管理 Linux 集群越来越重要了，在不远的将来此功能可能是必需的。</p>
<p>硬件厂商非常重视客户对远程管理系统标准的需求。当 前，IPMI 2.0 已经成为大多数 Linux 集群的标准。IPMI 提供了远程控制机器电源的方法，还提供远程控制台，可以观察计算机的 BIOS 引导过程。在我们的一位客户的站点上，我们能够坐在客户的办公室中，舒舒服服地对 60 英里外的计算机进行调试。（这位客户的 Linux 管理员真的很懒惰，他的办公室只用墙上昏暗的霓虹灯来照明。这间办公室简直成了单身汉的公寓，这里有两个冰箱，装满了饮料和甜食。不用说，我们不愿意离开 那里）。</p>
<p>IPMI 是强大的 —— 我们可以修改 BIOS 设置，重新启动节点，观察它们的引导过程，查看屏幕转储，而根本不需要看到物理机器 —— 它应该安装在所有集群中。您至少需要以下功能：</p>
<ul>
<li>远程控制机器的电源</li>
<li>远程控制台或观察机器引导过程的更好方法，从而应付可能发生的引导问题</li>
</ul>
<p>有 了 IPMI，Linux 集群中就不太需要其他软件了，那些软件只提供运行 IPMI 的豪华界面，而不是管理节点。实际上，我们建议使用开放源码工具，比如大多数 Linux 发行版已经附带的 ipmitool。我们发现最懒惰的 Linux 集群管理员依赖于命令行。</p>
<p>对于 IPMI 远程控制台的可靠性还有争议。我们意识到，有时候真正的带外终端服务器是很有价值的。Cyclades ACS48 等终端服务器是合理的投资，它们提供带外访问和 IPMI 不具备的可靠性。</p>
<p>另 外，IPMI 1.5 不是最可靠的 IOHO（这是一个全行业范围的问题）。IPMI 2.0 在这方面好多了，而且许多厂商围绕它添加了新颖的网页，使它看起来更容易使用。是包含终端服务器，还是只在机器上直接使用 IPMI，对于这个问题还有争议。我们的大多数客户的想法是这样的：<em>每个懒惰的 Linux 管理员都知道，需要花费大量时间排除 5% 的节点的故障，而 95% 的节点都是正常的。在这种情况下，更好的办法是多购买 5% 的节点（而不是基础设施）当作备份。这意味着花费在计算能力上的预算比花费在基础设施上的预算多一些。</em></p>
<p>考虑到这一点，如果使用终端服务器可以避免管理员长途赶去排除节点的故障，那么终端服务器就是物有所值的。我们让懒惰的 Linux 管理员自己做决定 —— 毕竟，必须去赶飞机的是他。我们看到争论的双方似乎都有一定的道理。</p>
<p>自从 1999 年 Linux 集群首次出现以来，集群工具已经有了长足的进步。在当时，可用的集群管理工具并不多，因此大多数管理员用自己开发的工具集来部署、监视和管理他们的集群。</p>
<p>最 懒惰的管理员已经接受了开放源码工具，或者把他们在 1999 年开发的工具贡献给了社区。很少有开放源码工具无法应付的极其独特的集群环境。在大多数情况下，坚持使用自己的工具的管理员都很孤独，当他们离开组织时， 他们的工具也就随其消失了。但是，我们发现在许多站点上仍然在使用定制的工具。</p>
<p>如果您对自制的工具不满意，正在寻找更好的工具，那么可以考虑几个开放源码工具。最受欢迎的集群管理工具包括 OSCAR (System Imager)、ROCKS、Perceus 和我们喜爱的 xCAT 2。它们都是开放源码的。</p>
<p>当 今最流行的开放源码集群部署/控制解决方案可能是 ROCKS。ROCKS 是由 UCSD 开发和维护的，他们在集群的用户友好性方面完成了出色的工作。我们对它惟一的不满之处是，它的灵活性不足，主要在操作系统级。ROCKS 基于 Red Hat 发行版，这对于大多数人是合适的，但是对于使用 SUSE 或者希望使用在 RH 6.2 发行版上创建的映像的人就不合适了。另外，ROCKS 不是克隆解决方案，而我们发现许多 IT 组织都使用克隆解决方案。</p>
<p>Perceus 是另一个流行的解决方案。它与 ROCKS 的不同之处在于，它是无状态的。对于本文的上下文，我们把无状态计算定义为在内存中运行操作系统，而不是把操作系统放在磁盘上。不需要磁盘，但是可以使用磁盘执行本地操作或交换。</p>
<p>与 其他解决方案相比，我们更喜欢 xCAT（当然，我们必须坦白，我们向 xCAT 项目贡献了代码并积极参与开发，所以推荐它有点儿 “自买自夸”）。它的优点是比其他任何工具都要灵活、可伸缩且更强大。（它的代码贡献者也是最英俊最聪明的）。世界上最快的超级计算机 LANL RoadRunner 系统就是用 xCAT 来管理的（此系统是 Cell/B.E.™/Opteron™ 的混合体，是第一个 one-petaflops 系统，也是第一个 one-petaflops Linux 集群）。</p>
<p>xCAT 可以针对几乎所有企业 Linux 发行版实现映像生成、kickstart、autoyast、iscsi 和无状态。另外，它还提供命令行工具，这些工具对从远程电源控制到控制台设置的各种 IPMI 命令进行抽象，可以在同一框架中使用它们。xCAT 的开发从 1999 年 10 月 31 日开始，IBM 在 2007 年开放了它的源代码。</p>
<p>但是公正地说，xCAT 也有缺点：</p>
<ul>
<li>它的设置比较难；由于灵活性很强，它有许多可配置参数。我们建立了一个 wiki 来帮助管理员设置 xCAT，还可以通过邮件列表和 IRC 频道获得大量帮助。</li>
<li>xCAT 2 完全改写了古老的 xCAT 1.3，因此管理员需要学习许多新东西。</li>
<li>与许多开放源码工具一样，文档还有待改进。</li>
</ul>
<p>还有许多其他集群管理解决方案，我们可以就这个主题滔滔不绝地谈下去。但是，我们还是就此打住：如果您要寻找更好的工具或思想，请试试 xCAT。</p>
<p>在去年的 SC&#039;07 上，我们遇到了在几家美国大型实验室工作的朋友，我们谈到了在监视 Linux 集群方面遇到的难题。这促使我们在 2008 年初多次讨论这个问题。监视的困难源于几个原因：</p>
<ul>
<li>随着集群的增长，收集的数据越来越多，接收这些监视信息的计算机的性能就越来越差。例如，如果有 2,000 台计算机，每台计算机都把性能指标发送到一个基础设施节点，此节点就会非常缓慢。</li>
<li>在计算节点上通过代理收集数据会与用户的作业争夺内存和 CPU 时间。许多站点不希望节点上有代理，因为它会降低应用程序的性能。这就需要回答一个问题：花费 CPU 时间获取监视数据是值得的吗？</li>
<li>我们还没有找到一种可伸缩工具能够把用户作业与计算机性能联系起来，从而有效且直观地分析作业。</li>
<li>还 没有任何工具能够完全满足管理员的需求。这可能就是这个领域中最大的问题：使用的工具的功能不全面，至少缺乏人人都需要的某种功能。大多数管理员会结合使 用两三种管理工具。我们常常听到一些集群监视产品宣称比所有其他解决方案都优秀，但是我们很怀疑这种说法：每个集群都不一样，真的有万灵药吗？定制的监视 解决方案似乎是惟一的解决之道。</li>
</ul>
<p>既然监视的复杂性这么大，那么最懒惰的管理员会怎么解决这个问题呢？</p>
<p>在大型集群上（包括著名大学和政府的实验室），最常见的解决方案是使用 Nagios 实现报警，使用 Ganglia 进行监视。通过结合使用这两种可定制性很强的工具，管理员可以很好地了解集群中发生的大多数情况。事实证明 Ganglia 的可伸缩性非常强。</p>
<p>但是，其他人也有不同的观点。在 USC，Garrick Staples 编写了 pbstop 作为 TORQUE 的插件，它可以显示当前正在运行的每个作业以及运行的位置。他说，这就是他需要监视的，他不需要使用其他任何工具。</p>
<p>我们看到横向扩展集群使用的最流行的开放源码监视工具包括：</p>
<ul>
<li>Nagios</li>
<li>Ganglia</li>
<li>Cacti</li>
<li>Zenoss</li>
<li>CluMon</li>
</ul>
<p>我们可以说这些工具的实现大多利用了 RRDtool。CluMon 还在底层使用 Performance Co-Pilot (PCP)，PCP 也很流行。xCAT 在未来的版本中将支持 Ganglia 和 PCP。</p>
<p>重申一下，懒惰的 Linux 集群管理员知道：</p>
<ul>
<li>没有适合所有集群的监视解决方案。监视对于不同的人有不同的含义。一些人只对计算机报警感兴趣，一些人需要监视性能指标，一些人需要作业分析，其他人只希望知道某些服务或应用程序是否在运行。</li>
<li>对于不同的站点或相同站点中的不同集群，定制的方式也不一样。</li>
<li>要在监视的目标、监视的用途和所需的资源之间找到平衡点。</li>
</ul>
<p>懒惰的管理员都知道，用户是所有问题的根源。因此，防止用户获得根权限是极其重要的。甚至可以这样说：您应该尽一切努力把用户挡在您的计算机之外。</p>
<p>队列系统就提供这样的功能：用户提交作业，队列系统决定在哪些节点上运行此作业。除了运行作业之外，用户应该完全影响不了系统。</p>
<p>当今流行的队列系统包括一些付费产品，比如 LSF 和 PBS Pro。许多商业客户、政府实验室和大学使用这些产品。但是，对于许多系统，一般的开放源码解决方案（比如 TORQUE 和 SLURM）就很好了。</p>
<p>我们喜欢结合使用 TORQUE 和 Maui 调度程序来把用户挡在集群之外（除了运行作业）。在 Linux 上，这需要先设置 /etc/security/access.conf 文件，只允许根用户登录，拒绝其他任何人。例如，如果在每个节点上运行命令：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>echo "-:ALL EXCEPT root:ALL" &gt;&gt;/etc/security/access.conf</pre>
</td>
</tr>
</tbody>
</table>
<p>那么只有根用户能够登录此计算机。接下来，创建一个 TORQUE 序言脚本，它运行下面这样的命令：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>perl -pi -e "s/:ALL$/ $USER:ALL/" /etc/security/access.conf</pre>
</td>
</tr>
</tbody>
</table>
<p>（提示：<code>$USER</code> 变量是在运行脚本时 TORQUE 传递给脚本的第二个变量）。因为根用户运行序言脚本，所以此用户被允许登录集群。当作业完成时，运行收尾脚本，该脚本从 /etc/security/access.conf 中删除此用户，因此他无法再登录节点：<code>perl -pi -e "s/ $USER\b//g" /etc/security/access.conf</code>。这会防止用户相互冲突。</p>
<p>我们在集群上看到的一些 “性能” 问题实际上与计算机本身无关；真正的问题是多个用户在同一台计算机上运行作业，而他们运行的作业都要求占用全部 CPU 时间。</p>
<p>众 所周知，用户管理是必需的。但是，在排除故障时，管理员常常没有认识到用户本身正是问题的根源。我们强烈建议把用户挡在系统之外，只允许他们通过受控的环 境（比如资源调度程序）进入系统。另外，我们建议集群网络本身（千兆管理或用户网络）应该与公司或校园 WAN 的其余部分分开，只允许某些用户节点提供访问点。</p>
<p>很多人只有在集群性能急剧下降、计算结果不正确时，才会意识到危险迫在眉睫。所以要记住，在判断集群的性能时硬件诊断常常是惟一的测试方法，但是硬件诊断提供的信息可能不完整。</p>
<p>硬件诊断常常以厂商指定的阈值作为成功/失败的评判标准 —— 实际的阈值可能高些，也可能低些。如果硬件诊断测试失败了，那么您就遇到问题了；但是，即使没有失败，也不意味着没问题。</p>
<p>下面的这些问题会对系统性能产生实质性影响，但厂商无法诊断出这些问题：</p>
<ul>
<li>双位内存错误</li>
<li>单位内存错误</li>
<li>SRAM 奇偶错误</li>
<li>PCI 总线错误</li>
<li>数字错误</li>
<li>缓存错误</li>
<li>磁盘错误</li>
<li>性能不一致</li>
</ul>
<p>问题常常与硬件无关，而是与软件相关。应用程序、库、编译器、固件和操作系统的任何部分都可能是问题的根源，而硬件诊断探测不出这些问题。运行硬件诊断的运行时环境常常与应用程序的环境不一样，而且子系统承受的压力也不一样 —— 所以无法重现软件造成的问题。</p>
<p>显然，需要在操作环境中运行某种相应的工作负载，从而检查集群的实际工作情况。这可以通过运行几个行业认可的基准测试来完成。基准测试的目的不是要获得最好的结果，而是要获得一致的、可重复的、精确的结果（当然，这也是最好的结果）。</p>
<p>如何知道结果是否是最好的？集群可以划分为下面的主要子系统：</p>
<ul>
<li>内存</li>
<li>CPU</li>
<li>磁盘</li>
<li>网络</li>
</ul>
<p>硬件厂商应该有基准测试数据，这些数据说明预期的内存、CPU (FLOPS)、磁盘和网络性能。</p>
<p>采用统计学技术。在每个节点（对于多节点测试，是节点集）上运行每个基准测试一次或多次，然后把每个节点（或节点集）的最具代表性的数据集中在一起，并进行分析。结果的分布形态比结果本身更有意义。本文中所有基准测试的经验证明，结果都应该形成<em>正态分布</em>。正态分布是典型的钟形曲线，这在统计学中经常出现。它是更小的独立（可能无法察觉到的）恒等分布的变量或随机事件的综合结果。</p>
<p>基准测试也有许多很小的独立（可能无法察觉到的）恒等分布的变量，这些变量可能会影响性能，比如：</p>
<ul>
<li>小的竞争进程</li>
<li>上下文切换</li>
<li>硬件中断</li>
<li>软件中断</li>
<li>内存管理</li>
<li>进程/线程调度</li>
<li>宇宙射线</li>
</ul>
<p>这些变量可能是不可避免的，但是它们是形成正态分布的原因之一。</p>
<p>基准测试还可能有<em>非</em> 恒等分布的可观察到的变量，它们也会影响性能：</p>
<ul>
<li>大的竞争进程</li>
<li>内存配置</li>
<li>BIOS 版本和设置</li>
<li>处理器速度</li>
<li>操作系统</li>
<li>内核类型（比如 NUMA、SMP 和 UNI）和版本</li>
<li>坏内存（比如过多的 ECC）</li>
<li>芯片组修订</li>
<li>超线程或 SMT</li>
<li>不均衡的竞争进程（比如在某些节点上运行 <code>httpd</code>，但是在其他节点上不运行）</li>
<li>共享库版本</li>
</ul>
<p>这些变量是可避免的。可避免的不一致性可能导致多重模态分布或非正态分布，可能会对应用程序性能造成可度量的影响。</p>
<p>由于我们的目标是<em>一致的、可重复的、精确的结果</em>， 所以最好先尽可能减少变量。首先进行单节点基准测试，比如 STREAM。如果所有计算机都产生相似的 STREAM 结果，那么在其他基准测试出现异常时，就可以排除内存这个因素。接下来，做处理器和磁盘基准测试，然后是两节点（并行）基准测试，再执行多节点（并行）基 准测试。在完成每个更复杂的基准测试阶段之后，检查结果是否是一致的、可重复的、精确的，之后才能执行下一个测试。</p>
<p>下面是我们推荐的基准测试次序（报告组件性能的基准测试以<strong>粗体</strong>显示）。</p>
<ul>
<li>单节点（串行）基准测试：
<ol>
<li>STREAM（<strong>内存 MBps</strong>）</li>
<li>NPB Serial（<strong>单处理器 FLOPS</strong> 和内存）</li>
<li>NPB OpenMP（<strong>多处理器 FLOPS</strong> 和内存）</li>
<li>HPL MPI Shared Memory（<strong>多处理器 FLOPS</strong> 和内存）</li>
<li>IOzone（<strong>磁盘 MBps</strong>、内存和处理器）</li>
</ol>
</li>
<li>并行基准测试（只针对 MPI 系统）：
<ol>
<li>Ping-Pong（<strong>互连 microsec</strong> 和 <strong>MBps</strong>）</li>
<li>NAS Parallel（<strong>多节点 FLOPS</strong>、内存和互连）</li>
<li>HPL MPI Distributed Memory（<strong>多节点 FLOPS</strong>、内存和互连）</li>
</ol>
</li>
</ul>
<p>是这样的，但是如果您希望以后清闲的话，这也是必要的。幸运的是，可以通过工具和文档简化这些工作。提前做一点儿计划，以后就能够避免许多麻烦。我们将在以后的一篇文章中讨论基准测试工具和图表；在未来的 xCAT RPM 中也会提供这些工具，这会极大地提高生产力。</p>
<table border="0" cellspacing="0" cellpadding="0" width="40%" align="right">
<tbody>
<tr>
<td width="10"><img src="http://www.ibm.com/i/c.gif" alt="" width="10" height="1" /></td>
<td>
<table border="1" cellspacing="0" cellpadding="5" width="100%">
<tbody>
<tr>
<td bgcolor="#eeeeee">
要想设置 MediaWiki，首先要指定一个驻留它的服务器。如果没有其他节点可用的话，我们常常使用管理服务器：<br />
<code>ssh mgmt</code></p>
<p>现在，确保安装 http 服务器、mysql 服务器和 php5。如果使用 Red Hat 5.1 或其衍生版本，那么输入：<br />
<code>yum install http mysql php5 mysql-server</code></p>
<p>接下来，配置 mysql：<br />
<code>service mysqld start<br />
mysql_install_db<br />
mysqladmin -u root password 'mypasswd'<br />
</code><br />
下载安装媒体 wiki：<br />
<code>cd /tmp/<br />
wget http://download.wikimedia.org/mediawiki/1.13/mediawiki-1.13.0.tar.gz<br />
tar zxvf mediawiki-1.13.0.tar.gz<br />
mv mediawiki-1.13.0 /var/www/html/wiki<br />
chmod a+x /var/www/html/wiki/config</code></p>
<p>完成这些步骤之后，在 Web 浏览器中访问 http://localhost/wiki。然后，只需按照菜单安装其余部分。</p>
<p>安装完成之后，会提示您执行命令：<br />
<code>cd /var/www/html/wiki<br />
mv config/LocalSettings.php</code></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>收 集系统的相关信息之后，应该把这些信息存储在某个方便的位置，让其他集群管理员可以轻松地访问。请回想一下 2000 年的情况，那时候文档大都采用 Word 或 Excel 格式，这既不酷，效率也不高。目前，生产力最高的文档共享方法是设置一个内部 wiki。这是因为懒惰的管理员不喜欢反复回答相同的问题。有了 wiki，管理员就不必这么做了，他只需说：“您自己去查看 wiki”。然后就不关他的事儿了。</p>
<p>每个站点都应该维护一个内部 wiki，其中应该包含所有常常被问到的集群相关信息，比如：</p>
<ul>
<li>系统修改的日志记录，包括在集群上执行管理操作的时间。</li>
<li>集群的资产清单：固件版本、型号、序号、集群中的节点数量、处理器类型、内存。</li>
<li>向厂商要求技术支持的链接和获取更新的地址。</li>
<li>关于使用管理软件执行常见任务的文档。</li>
<li>关于创建操作系统映像的过程的信息。</li>
</ul>
<p>简 单地说，这个 wiki 包含的信息应该足够全面，如果有人询问关于此集群的问题，管理员只需回答 “您自己去查看 wiki”。另一方面，如果有人询问了一个 wiki 中没有涉及的问题，而您回答了他，那么您应该告诉他，作为回报他应该把您告诉他的知识添加到 wiki 中。另外，这也是对他的奖励，因为他发现了别人没有注意到的东西，这会让他在狂野的 IT 世界中获得尊敬。</p>
<p>为什么 wiki 比其他文档形式更好？</p>
<ul>
<li>wiki 是可编辑的，位于一个中心位置，可以根据需要授予用户对它的访问权。我们见过保存在共享信息库中的文档，但是要想查看这些文档，用户必须先导航到信息库，然后把文档保存到自己的硬盘上，然后再打开。效率太低了。对于 wiki，只需单击链接，这更快更简便。</li>
<li>Word 文档或电子表格中的信息是静态的，修改起来比较麻烦（编辑、重新保存和发送修订后的文档）。更不用说，常常会看到同一文档的许多修订版，人们无法确定他们 手里的版本是不是最新的。如果多个人编辑同一文档，就更混乱了。实际上，把文档放在 wiki 上，它们的寿命就会长得多。</li>
</ul>
<p>设置 wiki 是极其容易的。我们使用 MediaWiki。它是免费的，很容易安装和配置。（请参见边栏）。</p>
<p>Wiki 的语法比 HTML 简单得多，而且网上有许多讲解如何使用 wiki 的参考资料。还有一些用来突出显示 perl 或 bash 中的代码语法的扩展。</p>
<p>当我们提议通过安装 wiki 帮助管理员变得更懒惰时，没有遇到过任何阻力。</p>
<p>我们常常看到集群管理员总是按照自己的方式做事，这是因为他们习惯了。我们认为，这对于 Linux 集群不是好现象，这会磨灭管理员的才能，丧失进一步挖掘集群的潜力的机会。变化是很重要的，并且新的思想常常伴随变化出现。</p>
<p>当 然，我们并不指望任何人能够研究他们遇到的每个新思想，但是是否熟悉新的趋势是区分优秀的管理员和平庸的管理员的重要标志。在这个快速变化的世界里，没人 能够知晓所有东西，并且只很少一部分人精通某些东西。但是，优秀的管理员了解那些非常好的东西，乐于测试新产品，而且对于以前没听说过的东西很好奇。</p>
<p>因 此，如果有人谈到以前没听说过的东西，懒惰的 Linux 管理员会追问下去，因为他实在太懒了，很希望找到更偷懒的方法。他还会通过搜索引擎查找相关信息。最糟糕的 Linux 集群管理员就是那些从来不提问题的。懒惰的 Linux 集群管理员不怕承认自己不知道某个东西。他对自己的本事很自信，即使他不知道某个产品，也能很快掌握它。</p>
<p>目前，在 Linux 集群管理领域有一些非常好的趋势。我们最感兴趣的是：</p>
<ol>
<li>越来越多的集群向无状态计算迁移。这会使映像的管理和保持节点同步更加轻松。</li>
<li>从数据中心的角度看待集群。这意味着会考虑三年或更长时间内的电力、制冷和人员成本，而不仅仅考虑最初的采购成本。</li>
<li>从气体制冷向液体制冷发展。您知道吗？液体制冷的效率比气体制冷高 90%。</li>
<li>自适应式管理。按照这种管理方式，队列系统能够根据需要供应节点。这是真正的云计算，我们已经用 Moab 和 xCAT 证明了它的优越性。这是实现<em>完全清闲</em> 的最后一步。</li>
</ol>
<p>如 果本文达到了它的目的，那么您现在应该有了一些偷懒的好主意，应该会尝试减轻自己的工作，同时更好地控制您现有的 Linux 集群环境，还计划在下一个集群中更偷懒。我们相信本文提供的思想和实践有助于更好地使用集群，促使集群管理成为更专业的科学，帮助造就更高效的集群管理 员。</p>
<p>问题越少，要开的会和要做的工作就越少，管理员就有更多时间玩 <em>WoW</em>、睡觉或做懒鬼们喜欢做的任何事情。</p>
<p><strong>获得产品和技术</strong><br />
本文中提到的一些软件：</p>
<ul>
<li><a href="http://www.rocksclusters.org/wordpress/?page_id=57" target="_blank">Rocks</a> 是一个开放源码的 Linux 集群发行版，它让最终用户能够轻松地构建计算型集群、网格端点和拼接式显示器墙。它的目标是使实现集群更轻松。</li>
<li><a href="http://svn.oscar.openclustergroup.org/trac/oscar" target="_blank">OSCAR</a> (Open Source Cluster Application Resources) 让具有不同 *NIX 经验水平的用户都能够安装 Beowulf 类型的 HPC 集群。</li>
<li><a href="http://www.perceus.org/portal/project/perceus" target="_blank">Perceus</a> 是 Warewulf 的开发人员创建的下一代企业和集群供应工具集。</li>
<li><a href="http://xcat.sourceforge.net/" target="_blank">xCAT</a> (eXtreme Cluster Administration Toolkit) 是一种可伸缩的分布式计算管理和供应工具，它为硬件控制、发现和有磁盘/无磁盘操作系统部署提供一个统一的界面。</li>
<li><a href="http://www.nagios.org/" target="_blank">Nagios</a> 是一个主机和服务监视程序，用于提示网络问题。它是为 Linux 设计的，但是可以在大多数 *NIX 变体下工作。</li>
<li><a href="http://ganglia.info/" target="_blank">Ganglia</a> 是一种可伸缩的分布式监视系统，用于监视以集群联合体为目标的采用层次化设计的 HPC 集群和网格。</li>
<li><a href="http://www-rcf.usc.edu/~garrick/perl-PBS/" target="_blank">pbstop</a> 是一种在 perl-PBS (Portable Batch System) 内部分发的 ncurses 监视和管理工具，世界上最大的一些集群使用此工具。</li>
<li><a href="http://www.clusterresources.com/pages/products/torque-resource-manager.php" target="_blank">TORQUE</a> 是一种开放源码的资源管理程序，可以控制批量作业和分布式计算节点，它是社区基于原来的 *PBS 项目开发的。</li>
<li><a href="http://www.cacti.net/" target="_blank">Cacti</a> 是一个完整的网络绘图解决方案，其设计目的是利用 RRDTool 的数据存储和绘图功能；它包含一个快速投票程序、高级的图形模板功能、多种数据获取方法和开箱即用的用户管理特性。</li>
<li><a href="http://www.zenoss.com/" target="_blank">Zenoss</a> 提供商业开放源码 IT 管理解决方案。</li>
<li><a href="http://clumon.ncsa.uiuc.edu/" target="_blank">CluMon</a> 是 National Center for Supercomputing Applications 开发的集群监视系统，用来跟踪它的 Linux 超级集群；它是一个可调优的系统，可以适应几乎任何 Linux 计算机集。</li>
<li><a href="http://oss.oetiker.ch/rrdtool" target="_blank">RRDtool</a> 是一个开放源码的高性能数据日志记录和绘图系统，用于处理时间系列数据。</li>
<li><a href="http://oss.sgi.com/projects/pcp/" target="_blank">Performance Co-Pilot</a> 提供一个支持系统级性能监视和性能管理的框架和服务；SGI 在 2000 年提供了一个开放源码版本。</li>
<li><a href="https://computing.llnl.gov/linux/slurm/" target="_blank">SLURM</a> 是 “具备高可伸缩性的资源管理程序”（在漫画 <em>Futurama</em> 中，一种用虫子制作的软饮料也叫作 SLURM）。它是一种为所有规模的 Linux 集群设计的开放源码资源管理程序，提供三种关键功能 —— 分配对资源的排他和/或非排他访问；提供一个用于在分配的节点集上启动、执行和监视工作的框架；通过管理一个未完成工作队列来解决对资源的争用。</li>
<li><a href="http://www.clusterresources.com/pages/products/moab-cluster-suite/workload-manager.php" target="_blank">Moab Workload Manager</a> 是一个基于策略的作业调度程序和事件引擎，支持在集群上进行基于实用程序的计算。</li>
</ul>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td colspan="3"><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="5" /></td>
</tr>
<tr align="left" valign="top">
<td></td>
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="4" height="5" /></td>
<td width="100%">Vallard Benincosa 是一位 “懒惰” 的 Linux 认证 IT 专家，在 IBM Linux Clusters 团队工作。他和他的妻子、两个小孩住在俄勒冈州波特兰市。</td>
</tr>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td colspan="3"><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="5" /></td>
</tr>
<tr align="left" valign="top">
<td></td>
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="4" height="5" /></td>
<td width="100%">Egan Ford 从 1999 年开始构建 Web 和 HPC Linux 集群，曾经担任 IBM 的第一个大型 HPC 集群（位于 University of New Mexico 的 Los Lobos）的首席架构师。在此之后，Egan 领导了 IBM 的一些大型系统的设计和实现，包括 AIST、LANL Roadrunner 和 US National Science Foundation Teragrid (teragrid.org)。Egan 是 IBM 的第一个集群管理解决方案 (xCAT) 的创建者，还是两份关于 Linux HPC 的 IBM 红皮书的合著者。</td>
</tr>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td colspan="3"><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="5" /></td>
</tr>
<tr align="left" valign="top">
<td></td>
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="4" height="5" /></td>
<td width="100%">Vallard Benincosa 是一位 “懒惰” 的 Linux 认证 IT 专家，在 IBM Linux Clusters 团队工作。他和他的妻子、两个小孩住在俄勒冈州波特兰市。</td>
</tr>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td colspan="3"><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="5" /></td>
</tr>
<tr align="left" valign="top">
<td></td>
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="4" height="5" /></td>
<td width="100%">Egan Ford 从 1999 年开始构建 Web 和 HPC Linux 集群，曾经担任 IBM 的第一个大型 HPC 集群（位于 University of New Mexico 的 Los Lobos）的首席架构师。在此之后，Egan 领导了 IBM 的一些大型系统的设计和实现，包括 AIST、LANL Roadrunner 和 US National Science Foundation Teragrid (teragrid.org)。Egan 是 IBM 的第一个集群管理解决方案 (xCAT) 的创建者，还是两份关于 Linux HPC 的 IBM 红皮书的合著者。</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-lazy-administrator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>无根的根：无名师的Unix心传</title>
		<link>http://www.linuxsong.org/2010/09/unix-tao/</link>
		<comments>http://www.linuxsong.org/2010/09/unix-tao/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 02:54:03 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[未分类]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=218</guid>
		<description><![CDATA[一、无名师与万行码
无名师曾对来访的程序员说：“Unix传统上认为，一行shell脚本胜过万行C程序。”
这个程序员自以为对C极其精通，说：“这不可能。UNIX内核正是用C实现的。”
无名师回道：“确是如此。不过，UNIX传统上认为，一行shell脚本胜过万行C程序。“
程序员颇为沮丧：”但是在C中我们可领会到尊者Ritchie的智慧。我们与操作系统和机器合而为一，可以获取无与伦比的性能。” <a href="http://www.linuxsong.org/2010/09/unix-tao/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>一、无名师与万行码<br />
无名师曾对来访的程序员说：“Unix传统上认为，一行<a href="http://www.linuxsong.org/category/shell/">shell</a>脚本胜过万行C程序。”<br />
这个程序员自以为对C极其精通，说：“这不可能。UNIX内核正是用C实现的。”<br />
无名师回道：“确是如此。不过，UNIX传统上认为，一行shell脚本胜过万行<a href="http://www.linuxsong.org/category/c/">C</a>程序。“<br />
程序员颇为沮丧：”但是在C中我们可领会到尊者Ritchie的智慧。我们与操作系统和机器合而为一，可以获取无与伦比的性能。”<br />
无名师回道：“诚如你言。不过，Unix传统上认为，一行shell脚本胜过万行C程序。”<br />
程序员冷笑着想愤然离去。无名师向学生Nubi颔首示意，Nubi在黑板上写下一行shell脚本，问道：“尊敬的程序员，看看这行管道，用纯C实现，是不是要一万行C代码？”<br />
程序员沉吟念诵。最终他承认如此。<br />
“你需要多长时间来实现和调试那个C程序？”Nubi问道。<br />
“很长”，来访的程序员承认。“但傻子才会干这个而不去完成更有价值的任务。”<br />
“那么谁更了解Unix传统？”无名师问道。“是写一万行代码的，还是看到任务的无谓而不去编码的？”<br />
听到此，程序员眼中一亮。</p>
<p><span id="more-218"></span>二、无名师与脚本狂<br />
无名师和学生吃早饭时，从黑客大陆来了个陌生访客。<br />
“Ihear y00 are very l33t,”他说。“Pl33z teach m3 all y00 know”。（我听说你很牛，请把你会的都教给我。）<br />
无名师的学生面面相觑，都没听懂这类粗鄙言语。无名师微笑道：“你想弄懂Unix？”<br />
“I want to b3 a wizard hax0r”，陌生人回答，“and 0wn ever3one&#039;s b0xen。”（我想当个顶尖黑客，能掌握所有人的机器。）<br />
“我不教这个”，无名师答道。<br />
陌生人很激动。“D00d， y00 r nothing but a p0ser。”，他说。“If y00 n00 anything, y00 wud t33ch m3。”（哥们儿，敢情你没真本事啊，你要知道点儿东西就教给我了。）<br />
“有条路，”无名师说，“可以将你带入真知。”他在纸上写了个IP地址。“黑掉这台机器，这对你来说应该不费什么力气，它的管理员不称职。回来后告诉我你发现了什么。“<br />
陌生人鞠了一躬就离开了。无名师把他的早饭吃完。<br />
几天过去了，几个月过去了。没人再想起陌生人。<br />
数年过去了，黑客大陆来的陌生人回来了。<br />
”你混蛋！“他说，”我黑掉了那台机器，你说的没错，太容易了。但是我被FBI抓起来扔进监狱了。“<br />
”好“，无名师说，”你可以继续下一课了。“他在另一张纸上写了个IP地址交给陌生人。<br />
”你疯了？“陌生人喊道。”经过这事，我再也不黑别人的机器了。”<br />
无名师脸现微笑。“这里就是”，他说，“真知的开始。”<br />
听到此，陌生人眼中一亮。</p>
<p>三、无名师的双路论<br />
无名师如是教导学生：<br />
“达摩教义有条准线，这在尊者McIlroy的符咒“做一件事并做好”中得到体现。它强调软件应当具有简单一致的行为，这符合Unix惯例，人和其它程序便都很容易想象其心理模型。<br />
“但达摩教义还有另一条准线，体现在尊者Thompson的符咒“有怀疑，用穷举”中，很多经文都教导我们现在得到的90%，比等不来的100%更有价值。它强调实现的健壮性和简单性。<br />
“现在告诉我：什么程序符合Unix传统？“<br />
想了一会儿后，Nubi沉思道：<br />
“老师，这些教义有冲突。”<br />
“简单的实现往往对边缘情况有欠考虑，比如资源耗竭、无法关闭竞争窗口以及在未完成事务中超时等等。”<br />
“发生边缘情况时，软件行为往往不规律、难以猜测。这当然不是Unix传统。“<br />
无名师颔首同意。<br />
“另一方面，大家都知道精巧的程序很脆弱。更进一步说，每个对边缘情况的修正往往牵扯到程序的核心算法，还牵扯处理其它边缘情况的代码。”<br />
“于是，对边缘情况防患于未然、确保描述的简单性，反而会使得代码过分复杂、bug成堆、根本无法发售。这当然不是Unix传统。”<br />
无名师颔首同意。<br />
“那么，什么是正确的达摩道？”Nubi问道。<br />
无名师说：<br />
“当鹰飞翔时，它忘记爪子与地面相触？当虎捕食时，它忘记腾空的一刻？VAX只重三斤！”<br />
听到此，Nubi眼中一亮。</p>
<p>四、无名师与方法论<br />
无名师和学生Nubi在圣地行走，无名师习惯在晚间为城市和乡村的Unix新门徒布道。<br />
一次，聆听者中混入了一名方法论者。<br />
“优化程序时不对热点进行反复衡量，就像渔夫把网撒入空湖中。”无名师说。<br />
“那么，”方法论者说，“管理资源时不持续地衡量你的产能，不也像渔夫将网撒入空湖中么？”<br />
“我一次碰到一个渔夫时，他正将网撒入船下的湖中，”无名师说，“他摸了好一会儿船底，像在寻找他的船。”<br />
“但是，”方法论者说，“如果他把网撒入湖中，为什么还要找船呢？”<br />
“因为他不会游泳。”无名师答道。<br />
听到此，方法论者眼中一亮。</p>
<p>五、无名师的GUI论<br />
一晚，无名师和Nubi参加一个程序员的探讨会。有个程序员问Nubi和他的老师来自哪看看学校。当得知他们是Unix大道的追随者时，程序员颇为不屑。<br />
“Unix命令行工具太粗糙太落后”，他讥讽道。“现代的、设计得当的操作系统可以在图形用户界面中做任何事情。”<br />
无名师一言不发，只是指着月亮。旁边的一条狗对着他的手狂吠。<br />
“我不明白。”程序员说。<br />
无名师依然缄默，指着一幅佛祖像，然后又指着一扇窗。<br />
“你想说什么？”程序员问。<br />
无名师指着程序员的头，接着指着一块大石。<br />
“请把话说清楚！”程序员要求道。<br />
无名师深深蹙眉，轻拍程序员的鼻子两下，把他扔到旁边的垃圾箱中。<br />
程序员试图从垃圾堆挣扎出来之时，那条狗跑过来在他身上便溺。<br />
此时，程序员眼中一亮。</p>
<p>六、无名师与Unix班<br />
一个Unix狂热者听说无名师掌握Unix大道真知，便跑来求教。无名师对他说：<br />
“当尊者Thompson发明Unix时，他并不理解它。随后他理解了，受益了，不再发明了。“<br />
“当尊者McIlroy发明管道时，他只知道它将传递软件，并不知道它能传递思想。”<br />
“当尊者Ritchie发明C时，他将程序员放到缓冲溢出、堆损坏和烂指针bug的地狱中惩罚。”<br />
“说实话，这些尊者又瞎又蠢！”<br />
狂热者对无名师的用词极为愤怒。<br />
“这些智者”，他抗议道，“给了我们Unix的大道。我们嘲笑他们，就是混淆是非，比转世为牲畜和MCSE还不如。”<br />
“你的代码全无污点和缺陷？”无名师问。<br />
“不，”狂热者承认，“没人不犯猎。”<br />
“这些尊者之智，”无名师说，“就是了解自身之愚。”<br />
听到此，狂热者眼中一亮。</p>
<p>七、无名师的Unix传统论<br />
一学生对无名师说：“我们听说SCO公司把握着纯正的Unix。”<br />
无名师颔首。<br />
学生继续说，“我们还听说OpenGroup公司也把握着纯正的Unix。”<br />
无名师颔首。<br />
“这怎么可能？”学生问。<br />
无名师答道：<br />
“SCO确实把握着Unix源码，但是Unix的源码不是Unix。OpenGroup确实把握着Unix的名称，但Unix的名称不是Unix。”<br />
“那么，什么是Unix传统？”学生问。<br />
无名师答道：<br />
“非源码。非名称。非思想。非实物。恒变。不变。”<br />
“Unix传统是简单和空。正是简单，正是空，才使得它更强胜飓风。”<br />
“以自然法则前行，在程序员手中，吸纳各种优良设计。与之竞争的软件最终必与之想像；空，空，真空，虚无，万岁！”<br />
听到此，学生眼中一亮。</p>
<p>无名师与最终用户<br />
无名师又一次布道时，一个最终用户听说了他的智慧，跑来求教。<br />
他对无名师三鞠躬。“我欲学习Unix大道，”他说，“但是弄不懂命令行。”<br />
一个旁观的新门徒开始嘲讽最终用户，说他脑子一锅粥，说只有经训练者、有智慧者才配使用Unix。<br />
无名师抚手不语，命这个嘲笑最终用户的新门徒前坐，坐到最终用户身边。<br />
“告诉我，”他对新门徒说，“你写过什么代码，有过什么突出设计。”<br />
新门徒嗫嚅了两句，然后沉默了。<br />
无名师转向最终用户。“告诉我”，他问，“为何你要寻求大道？”<br />
“我用的软件并不能令我满意”，最终用户答，“既不稳定，也不美观。听说Unix之道尽管艰难，但超越一切，我愿抛去一切诱饵和虚像。”<br />
“那么，”无名师问，“你为何想尽办法让软件帮你做事？”<br />
“我是个建筑工”，最终用户答道，“这座城里的很多房屋都出自我手。”<br />
无名师转向新门徒。“家猫也能欺负老虎”，无名师说，“但是猫叫永远比不过虎吼。”<br />
听到此，新门徒眼中一亮。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/unix-tao/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux 管理员的 10 个关键技巧</title>
		<link>http://www.linuxsong.org/2010/09/linux-administrator-skill/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-administrator-skill/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 02:51:35 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=216</guid>
		<description><![CDATA[学会这 10 个技巧后，您将成为世界上最强大的 Linux® 系统管理员，整个世界是有点夸张，但要在一个大团队中工作，这些技巧是十分必要的。学习 SHH 通道、VNC、密码恢复、控制台侦察等等。各个技巧都附有例子，可以将这些例子复制到自己的系统中。 <a href="http://www.linuxsong.org/2010/09/linux-administrator-skill/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p>学会这 10 个技巧后，您将成为世界上最强大的 <a href="http://www.linuxsong.org/category/linux/">Linux</a>® 系统管理员，整个世界是有点夸张，但要在一个大团队中工作，这些技巧是十分必要的。学习 SHH 通道、VNC、密码恢复、控制台侦察等等。各个技巧都附有例子，可以将这些例子复制到自己的系统中。</p></blockquote>
<p>好的系统管理员区分在效率上。如果一位高效的系统管理员能在 10 分钟内完成一件他人需要 2 个小时才能完成的任务，那么他应该受到奖励（得到更多报酬），因为他为公司节约了时间，而时间就是金钱，不是吗？</p>
<p>技巧是为了提高管理效率。虽然本文不打算对<em>所有</em> 技巧进行讨论，但是我会介绍 “懒惰” 管理员所用的 10 个基本法宝。这些技巧可以节约时间 —— 即使没有因为高效而得到更多的报酬，但至少可以有更多的时间去玩。</p>
<p><a name="T1"><span id="more-216"></span>技巧 1：卸载无响应的 DVD 驱动器</a></p>
<p>网 络新手的经历：按下服务器（运行基于 Redmond 的操作系统）DVD 驱动器上的 Eject 按钮时，它会立即弹出。他然后抱怨说，在大多数企业 Linux 服务器中，如果在那个目录中运行某个进程，弹出就不会发生。作为一名长期的 Linux 管理员，我会重启机器。如果我不清楚正在运行什么，以及为何不释放 DVD 驱动器，我则会弹出磁盘。但这样效率很低。</p>
<p>下面介绍如何找到保持 DVD 驱动器的进程，并轻松弹出 DVD 驱动器：首先进行模拟。在 DVD 驱动器中放入磁盘，打开一个终端，装载 DVD 驱动器：</p>
<p><code># mount /media/cdrom<br />
# cd /media/cdrom<br />
# while [ 1 ]; do echo "All your drives are belong to us!"; sleep 30; done</code></p>
<p>现在打开第二个终端并试着弹出 DVD 驱动器：</p>
<p><code># eject</code></p>
<p>将得到以下消息：</p>
<p><code>umount: /media/cdrom: device is busy</code></p>
<p>在释放该设备之前，让我们找出谁在使用它。</p>
<p><code># fuser /media/cdrom</code></p>
<p>进程正在运行，无法弹出磁盘其实是我们的错误。</p>
<p>现在，如果您是根用户，可以随意终止进程：</p>
<p><code># fuser -k /media/cdrom</code></p>
<p>现在终于可以卸载驱动器了：</p>
<p><code># eject</code></p>
<p><code>fuser</code> 很正常。</p>
<p><a name="T2">技巧 2：恢复出现问题的屏幕</a></p>
<p>尝试以下操作：</p>
<p><code># cat /bin/cat</code></p>
<p>注意！终端就想垃圾一样。输入的所有内容非常零乱。那么该怎么做呢？</p>
<p>输入 <code>reset</code>。但是，输入 <code>reset</code> 与 输入 <code>reboot</code> 或 <code>shutdown</code> 太接近了。吓得手心冒汗了吧 — 特别是在生产机器上执行这个操作时。</p>
<p>放心吧，在进行此操作时，机器不会重启。继续操作：</p>
<p><code># reset</code></p>
<p>现在屏幕恢复正常了。这比关闭窗口后再次登陆好多了，特别是必须经过 5 台机器和 SSH 才能到达这台机器时。</p>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" alt="" width="100%" height="4" /></td>
</tr>
</tbody>
</table>
<p><a name="T3">技巧 3：屏幕协作</a></p>
<p>来自产品工程的高级维护用户 David 打电话说：“为什么我不能在您部署的这些新机器上编译 supercode.c”。</p>
<p>您会问他：“您运行的是什么机器？”</p>
<p>David 答道：“ Posh”。（这个虚够的公司将它的 5 台生产服务器以纪念 Spice Girls 的方式命名）。这下您可以大显身手了，另一台机器由 David 操作：</p>
<p><code># su - david</code></p>
<p>转到 posh：</p>
<p><code># ssh posh</code></p>
<p>到达之后，运行以下代码：</p>
<p><code># screen -S foo</code></p>
<p>然后呼叫 David：</p>
<p>“David，在终端运行命令 <code># screen -x foo</code>”。</p>
<p>这使您和 David 的会话在 Linux <a href="http://www.linuxsong.org/category/shell/">shell</a> 中联接在一起。您可以输入，他也可以输入，但彼此可以看到对方所做的事情。这避免了进入其他层次，而且双方都有相同的控制权。这样做的好处是 David 可以观察到您的故障诊断技巧，并能准确了解如何解决问题。</p>
<p>最后大家都能看到问题所在：David 的编译脚本对一个不在此新服务器上的旧目录进行了硬编码。将它装载后再次编译即可解决问题，然后 David 继续工作。您则可以继续之前的娱乐活动。</p>
<p>关于此技巧需要注意的一点是，双方需要以同一用户登录。<code>screen</code> 命令还可以：实现多个窗口和拆分屏幕。请阅读手册页获取更多相关信息。</p>
<p>对于 <code>screen</code> 会话，我还有最后一个技巧。要从中分离并让它打开，请输入 <code>Ctrl-A D </code>（即按住 <strong>Ctrl</strong> 键并点击 <strong>A</strong> 键。然后按 <strong>D</strong> 键）。</p>
<p>然后通过再次运行 <code>screen -x foo</code> 命令可以重新拼接起来。</p>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td></td>
</tr>
</tbody>
</table>
<p><a name="T4">技巧 4：找回根密码</a></p>
<p>如果忘记根密码，就必须重新安装整台机器。更惨的是，许多人都会这样做。但是启动机器并更改密码却十分简单。这并非在所有情况下都适用（比如设置了一个 GRUB 密码，但也忘记了），但这里介绍一个 Cent OS Linux 示例，说明一般情况下的操作。</p>
<p>首先重启系统。重启时会跳出如图 1 所示的 GRUB 屏幕。移动箭头键，这样可以保留在此屏幕上，而不是进入正常启动。<br />
<a name="fig1"><strong>图 1. 重启后的 GRUB 屏幕</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/linux/l-10sysadtips/figure1.jpg" alt="重启后的 GRUB 屏幕" /></p>
<p>然后，使用箭头键选择要启动的内核，并输入 <strong>E</strong> 编辑内核行。然后便可看到如图 2 所示的屏幕：<br />
<a name="fig2"><strong>图 2：准备编辑内核行</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/linux/l-10sysadtips/figure2.jpg" alt="准备编辑内核行" /></p>
<p>再次使用箭头键突出显示以 <code>kernel</code> 开始的行，按 <strong>E</strong> 编辑内核参数。到达如图 3 所示的屏幕时，在图 3 中所示的参数后追加数字 1 即可：<br />
<a name="fig3"><strong>图 3. 在参数后追加数字 1</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/linux/l-10sysadtips/figure3.jpg" alt="在参数后追加数字 1" /></p>
<p>然后按 <strong>Enter</strong> 和 <strong>B</strong>，内核会启动到单用户模式。然后运行 <code>passwd</code> 命令，更改用户根密码：</p>
<p><code>sh-3.00# passwd<br />
New UNIX password:<br />
Retype new UNIX password:<br />
passwd: all authentication tokens updated successfully</code></p>
<p>现在可以重启了，机器将使用新密码启动。</p>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td></td>
</tr>
</tbody>
</table>
<p><a name="T5">技巧 5：SSH 后门</a></p>
<p>有很多次，我所在的站点需要某人的远程支持，而他却被公司防火强阻挡在外。很少有人意识到，如果能通过防火墙到达外部，那么也能轻松实现让外部的信息进来。</p>
<p>从本意讲，这称为 “在防火墙上砸一个洞”。我称之为 <em>SSH 后门</em>。为了使用它，必须有一台作为中介的连接到 Internet 的机器。</p>
<p>在本例中，将这样台机器称为 blackbox.example.com。公司防火墙后面的机器称为 ginger。此技术支持的机器称为 tech。图 4 解释了设置过程。<br />
<a name="fig4"><strong>图 4. 在防火墙上砸一个洞</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/linux/l-10sysadtips/figure4.gif" alt="在防火墙上砸一个洞" /></p>
<p>以下是操作步骤：</p>
<ol>
<li>检查什么是允许做的，但要确保您问对了人。大多数人都担心您打开了防火墙，但他们不明白这是完全加密的。而且，必须破解外部机器才能进入公司内部。不过，您可能属于 “敢作敢为” 型的人物。自己进行判断应该选择的方式，但不如意时不抱怨别人。</li>
<li>使用 <code>-R</code> 标记通过 SSH 从 ginger 连接到 blackbox.example.com。假设您是 ginger 上的根用户，tech 需要根用户 ID 来帮助使用系统。使用 <code>-R</code>标记将 blackbox 上端口 2222 的说明转发到 ginger 的端口 22 上。这就设置了 SSH 通道。注意，只有 SSH 通信可以进入 ginger：您不会将 ginger 放在无保护的 Internet 上。可以使用以下语法实现此操作：
<p><code>~# ssh -R 2222:localhost:22 thedude@blackbox.example.com</code></p>
<p>进入 blackbox 后，只需一直保持登录状态。我总是输入以下命令：</p>
<p><code>thedude@blackbox:~$ while [ 1 ]; do date; sleep 300; done</code></p>
<p>使机器保持忙碌状态。然后最小化窗口。</li>
<li>现在指示 tech 上的朋友使用 SSH 连接到 blackbox，而不需要使用任何特殊的 SSH 标记。但必须把密码给他们：<code>root@tech:~# ssh thedude@blackbox.example.com </code>.</li>
<li>tech 位于 blackbox 上后，可以使用以下命令从 SSH 连接到 ginger：<code>thedude@blackbox:~$: ssh -p 2222 root@localhost</code></li>
<li>Tech 将提示输入密码。应该输入 ginger 的根密码。</li>
<li>现在您和来自 tech 的支持可以一起工作并解决问题。甚至需要一起使用屏幕！（参见 <a href="http://www.linuxsong.org/2008/11/linux-10.html#T4">技巧 4</a>）。</li>
</ol>
<p><a name="T6">技巧 6：通过 SSH 通道进行远程 VNC 会话</a></p>
<p>VNC 或虚拟网络计算已经存在很长时间了。通常，当远程服务器上的某类图形程序只能在此服务器上使用时，我才需要 VNC。</p>
<p>例如，假设在 技巧 5 中，ginger 是一台存储服务器。许多设备都使用 GUI 程序来管理存储控制器。这些 GUI 管理工具通常需要通过一个网络直接连接到存储服务器，而这个网络有时保存在专用的子网络中。因此，只能通过 ginger 访问这个 GUI。</p>
<p>可以尝试使用 <code>-X</code> 选项通过 SSH 连接到 ginger 并启动它，但这对带宽要求很高，您需要忍受等待的痛苦。VNC 是一个网络友好的工具，几乎适用于所有操作系统。</p>
<p>假设设置与技巧 5 中的一样，但希望 tech 能访问 VNC 而不是 SSH。对于这种情况，需要进行一些类似的操作，不过转发的是 VNC 端口。执行以下操作步骤：</p>
<ol>
<li>在 ginger 上启动一个 VNC 服务器会话。运行以下命令：<code>root@ginger:~# vncserver -geometry 1024x768 -depth 24 :99</code>
<p>这些选项指示启动服务器，分辨率为 1024&#215;768，像素深度为每像素 24 位。如果使用较慢的连接设置，8 也许是更好的选项。使用 <code>:99</code> 指定可访问 VNC 服务器的端口。VNC 协议在 5900 处启动，因此 <code>:99</code> 表示服务器可从端口 5999 访问。</p>
<p>启动该会话时，要求您指定密码。用户 ID 与启动 VNC 服务器时的用户相同（本例中就是根用户）。</li>
<li>从 ginger 连接到 blackbox.example.com 的 SSH 将 blackbox 上的端口 5999 转发到 ginger。这通过运行以下命令在 ginger 中完成：<code>root@ginger:~# ssh -R 5999:localhost:5999 thedude@blackbox.example.com</code>
<p>运行此命令后，需要将此 SSH 会话保持为打开状态，以便保留转发到 ginger 的端口。此时，如果在 blackbox 上，那么运行以下命令即可访问 ginger 上的 VNC 会话：</p>
<p><code>thedude@blackbox:~$ vncviewer localhost:99</code></p>
<p>这将通过 SSH 将端口转发给 ginger，但我们希望通过 tech 让 VNC 访问 ginger。为此，需要另一个通道。</li>
<li>在 tech 中，打开一个通道，通过 SHH 将端口 5999 转发到 blackbox 上的端口 5999。这通过运行以下命令完成：<code>root@tech:~# ssh -L 5999:localhost:5999 thedude@blackbox.example.com</code>
<p>这次使用的 SSH 标记为 <code>-L</code>，它不是将 5999 放到 blackbox，而是从中获取。到达 blackbox 后，需要保持此会话为打开状态。现在即可在 tech 中使用 VNC 了！</li>
<li>在 tech 中，运行以下命令使 VNC 连接到 ginger：<code>root@tech:~# vncviewer localhost:99 </code>.
<p>Tech 现在将拥有一个直接到 ginger 的 VNC 会话。</li>
</ol>
<p>设置虽然有点麻烦，但比为修复存储阵列而四处奔波强多了。不过多实践几次这就变得容易了。</p>
<p>对 此技巧我还要补充一点：如果 tech 运行的是 Windows® 操作系统，并且没有命令行 SSH 客户端，那么 tech 可以运行 Putty。Putty 可以设置为通过查找侧栏中的选项来转发 SSH 端口。如果端口是 5902 而不是本例中的 5999，则可以输入图 5 中的内容。<br />
<a name="fig5"><strong>图 5. Putty 可以转发用作通道的 SSH</strong></a><br />
<img src="http://www.ibm.com/developerworks/cn/linux/l-10sysadtips/figure5.jpg" alt="Putty 可以转发用作通道的 SSH 端口" width="332" height="448" /></p>
<p>如果进行了此设置，那么 tech 就可以使用 VNC 连接到 localhost:2，如同 tech 正在 Linux 操作系统上运行一样。</p>
<p><a name="T7">技巧 7：检查带宽</a></p>
<p>设想：公司 A 有一个名为 ginger 的存储服务器，并通过名为 beckham 的客户端节点装载 NFS。公司 A 确定他们需要从 ginger 得到更多的带宽，因为有大量的节点需要 NFS 装载 ginger 的共享文件系统。</p>
<p>实现此操作的最常用和最便宜的方式是将两个吉比特以太网 NIC 组合在一起。这是最便宜的，因为您通常会有一个额外的可用 NIC 和一个额外的端口。</p>
<p>所以采取此这个方法。不过现在的问题是：到底需要多少带宽？</p>
<p>吉比特以太网理论上的限制是 128MBit/s。这个数字从何而来？看看这些计算：</p>
<p><em>1Gb = 1024Mb</em>；<em>1024Mb/8 = 128MB</em>；&quot;b&quot; = &quot;bits,&quot;、&quot;B&quot; = &quot;bytes&quot;</p>
<p>但实际看到的是什么呢，有什么好的测量方法呢？我推荐一个工具 iperf。可以按照以下方法获得 iperf：</p>
<p><code># wget http://dast.nlanr.net/Projects/Iperf2.0/iperf-2.0.2.tar.gz</code></p>
<p>需要在 ginger 和 beckham 均可见的共享文件系统上安装此工具，或者在两个节点上编译并安装。我将在两个节点均可见的 bob 用户的主目录中编译它：</p>
<p><code>tar zxvf iperf*gz<br />
cd iperf-2.0.2<br />
./configure -prefix=/home/bob/perf<br />
make<br />
make install</code></p>
<p>在 ginger 上，运行：</p>
<p><code># /home/bob/perf/bin/iperf -s -f M</code></p>
<p>这台机器将用作服务器并以 MBit/s 为单位输出执行速度。</p>
<p>在 beckham 节点上，运行：</p>
<p><code># /home/bob/perf/bin/iperf -c ginger -P 4 -f M -w 256k -t 60</code></p>
<p>两 个屏幕上的结果都指示了速度是多少。在使用吉比特适配器的普通服务器上，可能会看到速度约为 112MBit/s。这是 TCP 堆栈和物理电缆中的常用带宽。通过以端到端的方式连接两台服务器，每台服务器使用两个联结的以太网卡，我获得了约 220MBit/s 的带宽。</p>
<p>事实上，在联结的网络上看到的 NFS 约为 150-160MBit/s。这仍然表示带宽可以达到预期效果。如果看到更小的值，则应该检查是否有问题。</p>
<p>我最近碰到一种情况，即通过连接驱动程序连接两个使用了不同驱动程序的 NIC。这导致性能非常低，带宽约为 20MBit/s，比不连接以太网卡时的带宽还小！</p>
<p><a name="T8">技巧 8：命令行脚本和实用程序</a></p>
<p>Linux 系统管理员通过使用权威的命令行脚本会变得更高效。这包括巧妙使用循环和知道如何使用 <code>awk</code>、<code>grep</code> 和 <code>sed</code> 等的实用程序解析数据。通常这可以减少击键次数，降低用户出错率。</p>
<p>例如，假设需要为即将安装的 Linux 集群生成一个新的 /etc/hosts 文件。一般的做法是在 vi 或文本编辑器中添加 IP 地址。不过，可以通过使用现有 /etc/hosts 文件并将以下内容追加到此文件来实现。在命令行上运行：</p>
<p><code># P=1; for i in $(seq -w 200); do echo "192.168.99.$P n$i"; P=$(expr $P + 1);<br />
done &gt;&gt;/etc/hosts</code></p>
<p>200 个主机名（n001 到 n200）将由 IP 地址（192.168.99.1 到 192.168.99.200）来创建。手动填充这样的文件有可能会创建重复的 IP 地址或主机名，因此这是使用内置命令行消除用户错误的好例子。请注意，这是在 bash shell（大多数 Linux 发行版的默认值）内完成的。</p>
<p>再举一个例子，假设要检查 Linux 集群中的各个计算节点中的内存大小是否一样。通常，拥有一个发行版或类似的 shell 是最好的。但是为了演示，以下使用 SSH。</p>
<p>假设 SSH 设置为不使用密码验证。然后运行：</p>
<p><code># for num in $(seq -w 200); do ssh n$num free -tm | grep Mem | awk '{print $2}';<br />
done | sort | uniq</code></p>
<p>这样的命令行相当简洁。（如果在其中放入正则表达式情况会更糟）。让我们对它进行细分，详细讨论各部分。</p>
<p>首先从 001 循环到 200。使用 <code>seq</code> 命令的 <code>-w</code> 选项在前面填充 0。 然后替换 <code>num</code> 变量，创建通过 SSH 连接的主机。有了目标主机后，向它发出命令。本例中是：</p>
<p><code>free -m | grep Mem | awk '{print $2}'</code></p>
<p>这个命令的意思是：</p>
<ul>
<li>使用 <code>free</code> 命令获取以兆字节为单位的内存大小。</li>
<li>获取这个命令的结果，并使用 <code>grep</code> 获取包含字符串 <code>Mem</code> 的行。</li>
<li>获取那一行并使用 <code>awk</code> 输出第二个字段，它是节点中的总内存。</li>
</ul>
<p>在每个节点上执行这个操作。</p>
<p>在每个节点上执行命令后，200 个节点的整个输出就传送（<code>|</code>d）到 <code>sort</code> 命令，以对所有内存值进行排序。</p>
<p>最后，使用 <code>uniq</code> 命令消除重复项。这个命令会导致以下情况中的一种：</p>
<ul>
<li>如果所有节点（n001 到 n200）拥有相同的内存大小，则只显示一个数字。这个数字就是每个操作系统看到的内存大小。</li>
<li>如果节点内存大小不同，将会看到几个内存大小的值。</li>
<li>最后，如果某个节点上的 SSH 出现故障，则会看到一些错误消息。</li>
</ul>
<p>这个命令并不是完美无缺的。如果发现与预期不同的内存值，您就不知道是哪一个节点出了问题，或者有多少个节点。为此需要发出另一个命令。</p>
<p>这个技巧提供了一种查看某些内容的快速方式，而且如果发生错误，您可以立刻知道。其价值在于快速检查。</p>
<p><a name="T9">技巧 9：控制台侦察</a></p>
<p>有些软件会向控制台输出错误消息，而控制台不一定会显示在 SHH 会话中。使用 vcs 设备可以进行检查。在 SSH 会话中，在远程服务器 <code># cat /dev/vcs1</code> 上运行以下命令。这将显示第一个控制台中的内容。也可以使用 2、3 等查看其他虚拟终端。如果某个用户在远程系统上输入，您将看到他输入的内容。</p>
<p>在大多数数据场中，使用远程终端服务器、KVM 甚至 Serial Over LAN 是查看这类信息的最好方式；它也提供了带外查看功能的一些好处。使用 vcs 设备能够提供一种快速带内方法，这能节省去机房查看控制台的时间。</p>
<p><a name="T10">技巧 10：随机系统信息收集</a></p>
<p>在 <a href="http://www.ibm.com/developerworks/cn/linux/l-10sysadtips/index.html?ca=drs-cn-0811#T8">技巧 8</a> 中，介绍了一个使用命令行获取有关系统中总内存信息的例子。在这个技巧中，我将介绍几个其他方法，用于从需要进行验证、故障诊断或给予远程支持的系统收集重要信息。</p>
<p>首先，收集关于处理器的信息。通过以下命令很容易实现：</p>
<p><code># cat /proc/cpuinfo </code>。</p>
<p>这个命令给出关于处理器的速度、数量和型号的信息。在许多情况下使用 <code>grep</code> 可以得到需要的值。</p>
<p>我经常做的检查是确定系统中处理器的数量。因此，如果我买了一台带双核处理器的四核服务器，我可以运行以下命令：</p>
<p><code># cat /proc/cpuinfo | grep processor | wc -l </code>。</p>
<p>然后我看到值应该是 8。如果不是，我会打电话给供应商，让他们给我派送另一台处理器。</p>
<p>我需要的另一条信息是磁盘信息。可以使用 <code>df</code> 命令获得。我总是添加 <code>-h</code> 标记，以便看到以十亿字节或兆字节为单位的输出。<code># df -h</code> 还会显示磁盘的分区情况。</p>
<p>列表最后是查看系统固件的方式 —— 一个获取 BIOS 级别和 NIC 上的固件信息的方法。</p>
<p>要检查 BIOS 版本，可以运行 <code>dmidecode</code> 命令。遗憾的是，不能轻易使用 <code>grep</code> 获取信息，所以这不是一个很有效的方法。对于我的 Lenovo T61 laptop，输出如下：</p>
<p><code>#dmidecode | less<br />
...<br />
BIOS Information<br />
Vendor: LENOVO<br />
Version: 7LET52WW (1.22 )<br />
Release Date: 08/27/2007<br />
...</code></p>
<p>这比重启机器并查看 POST 输出有效得多。</p>
<p>要检查以太网适配器的驱动程序和固件版本，请运行 <code>ethtool</code>：</p>
<p><code># ethtool -i eth0<br />
driver: e1000<br />
version: 7.3.20-k2-NAPI<br />
firmware-version: 0.3-0</code></p>
<p><a name="N10471">结束语</a></p>
<p>可以从精通命令行的人那里学习很多技巧。最好的学习方式是：</p>
<ul>
<li>与其他人一起工作。共享屏幕会话并观察其他人是如何工作的 —— 您会发现新的做事方法。可能需要谦虚一点，让其他人引导，不过通常可以学到很多东西。</li>
<li>阅读手册页。认真阅读手册页，即使是熟知的命令，也能获得更深的见解。例如，您以前可能根本不知道可以使用 <code>awk</code> 进行网络编程。</li>
<li>解决问题。作为系统管理员，总是要解决问题，不管是您还是其他人引起的问题。这就是经验，经验可以使您更优秀、更高效。</li>
</ul>
<p>我 希望至少有一个技巧能帮助您学习到您不知道的知识。像这样的基本技巧可以使您更高效，并且能增长经验，但最重要的是，技巧可以让您有更多的空闲时间去做自 己感兴趣的事情，比如玩电子游戏。最好的管理员比较悠闲，因为他们不喜欢工作。他们能找到完成任务的最快方法，并且能快速完成任务，从而保持休闲的生活。</p>
<p><a name="author">关于作者</a></p>
<p><a name="author">Vallard Benincosa 是一位 “懒惰” 的 Linux 认证 IT 专家，在 IBM Linux Clusters 团队工作。他和他的妻子、两个小孩住在俄勒冈州波特兰市.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-administrator-skill/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Linux进程调度程序的具体细节</title>
		<link>http://www.linuxsong.org/2010/09/linux-process-scheduler/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-process-scheduler/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 02:46:26 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=213</guid>
		<description><![CDATA[性别之间的一个差别，据说，是处理多任务的能力。现在，就看你说话的人是持有这种看法的女人还是男人，但是，我还没有那么大胆参加这种争论。然而，我能够告诉你的是，Linux明确无疑地这么做。而且，事实上，许多系统也许没有充分利用多任务。理由在这里。 <a href="http://www.linuxsong.org/2010/09/linux-process-scheduler/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em>性别之间的一个差别，据说，是处理多任务的能力。现在，就看你说话的人是持有这种看法的女人还是男人，但是，我还没有那么大胆参加这种争论。然而，我能够告诉你的是，<a href="http://www.linuxsong.org/category/linux/">Linux</a></em><em>明确无疑地这么做。而且，事实上，许多系统也许没有充分利用多任务。理由在这里。</em></p>
<p>追溯从前，桌面计算机没有多任务。这些计算机每次运行一个专门的任务。这些日子过去了；现在，甚至连最小型的嵌入式操作系统一般也有某些方面的多任务处理能力。</p>
<p>对于操作系统开发者来说，实现多任务并不简单。但解释起来却足够简单——必须在所有不同任务之间分配CPU时间。然而，不仅如此，还有一大堆问题。一些进程比另一些进程更重要并且必须有定期运行。其他不太重要的可以闲着无事坐在背后。而且为了其他人，应该让程序决定何时放弃控制，返回操作系统，抑或应由OS决定给各任务在挂起前一个指定的运行时间？</p>
<p><span id="more-213"></span>Linux监督所有这一切的部分就是调度程序，事实上，调度程序提供若干处理多任务的不同算法。没有一个算法单独对于每一个场合都是完美的；例如，一个用于负荷交互式用户的通用Linux服务器可能需要与专用网络服务器不同的分时处理方法。Linux内核实际上允许用户在启动时选择将要使用的是哪一种调度方法。这得不到广泛的赏识，因此，许多Linux系统事实上可能按对它来说也许是次优的方式进行调度。</p>
<p>事实上，调度程序自身不是真正分离的程序，而是每一个进程执行的进程。无论何时，任何正在运行的进程入睡或者因等待输入输出不得不阻塞，就调用调度例行程 序，弄清楚是否需要将控制切换到另一个任务，而且，如果是这样的话，还要确定是哪一个任务。这不会因应用程序开发者的吩咐而发生，因为这些对调度程序的调 用都嵌入Linux内核之中的系统调用。</p>
<p>任何定期与设备——象磁盘和键盘——通信的进程，要花大量等待时间，因为CPU比任何I/O设备要快得多。这个空闲时间让给其他进程运行更好。相反，复杂数学计算的程序可能把大量时间花在捣弄数字而没有任何I/O活动。</p>
<p>操作系统有两条路可以走下去：操作系统可能让进程放弃控制（CPU），只要它们因等待某事某物而阻塞，这称为协同多任务处理。或者，OS可能获得控制并强制进程暂时放弃（CPU），因而另一个进程可以运行。后一种情形更适合强计算的实例并通称为抢先式多任务处理。</p>
<p>Linux使用协同和抢先多任务处理两者。如果一个进程没有自动定期地把控制退还，它就是抢先的。</p>
<p>每一个Linux进程分配一定数量的时间——即时间片——执行任务，在内核停下它让另一个进程运行之前。如果进程自愿放弃，则是冷静的；只要进程要求读或写I/O设备，这件事一般就自动发生。在这种情况下，我们说，这个进程让出CPU。如果时间片期满，那么，内核停止这个进程。我们说，这些进程被抢占。</p>
<p>不只这两种情形。一个进程可能等待某事发生——例如，象Web服务器或者SMTP一样的网络服务——在它们有任何工作要做之前，无所事事等待客户的连接。这不仅仅是从慢速磁盘或者打字缓慢的用户读数据的问题，而且实际上在事件发生之前没有什么活动。</p>
<p>在这种情况下，我们说，进程被阻塞。直到事件发生，它才再次运行。一个阻塞进程根本就不能使用CPU，而且在唤醒它的事件发生之前，完全不必调度它再次运行。</p>
<p>调度程序还有更多的事情。无论何时，给予进程运行机会的时机一到，调度程序就要计算出应该选择哪一个进程。为了帮助做出选择，Linux给每个进程一个优先权。较高优先权者可能在较低优先权者之前运行。虽然优先权受用户影响，但最终由内核控制，而且随着时间的推移，优先权可能增加或者降低。特别地，奖励运行得好的进程——即那些因频繁让出而罕有被抢占者。</p>
<p>恰好地，这种奖励方案趋向照顾与用户交互的进程。一个定期从键盘获取输入的应用程序将定期让出，只要它等待输入。另一方面，执行大量计算因而不得不被抢占的程序实际上根本不涉及用户。这类进程将收到一个负的奖励。</p>
<p>你可参见下列两个脚本图示。一个将做得非常多，另一个做得不多。</p>
<pre class="brush: bash;">

#!/bin/bash

while [ true ]

do

sleep 0.1

done

and

#!/bin/bash

x = 0

while [ true ]

do

x = $(($x + 1))

done
</pre>
<p>第一个脚本花全部时间睡觉。另一个坚持不懈地给一个数增值。这毫无意义，但目的是没完没了地消耗CPU。让我们分别把它们称为yielder.sh和preempter.sh。</p>
<p>设置这样运行：</p>
<p>./yielder.sh &amp;</p>
<p>./preempter.sh &amp;</p>
<p>接下来，重复运行这个命令检查它们的优先级：</p>
<p>ps –C yielder –C preempter –o etime,pri,cmd</p>
<p>你看到什么？</p>
<p>使用向上箭头键并回车，每隔几秒重复调用ps。很快就会看到这两个脚本优先数的变化——PRI栏。yielder.sh的优先权增加，而preempter.sh的优先权减少。这是因为调度程序分别给一个正的和负的奖励。</p>
<p>如果没有运行别的程序，那么，这两个进程将稳定在给它们的奖励不再改变的一点。在一个忙碌的服务器上，奖励可能连续上下浮动，因为其他进程也在启动和终止。</p>
<p>如果你真诚希望系统尽其最大努力运行你的复杂计算，你马上就会明白，这恐怕是不可能的。一方面，Linux有这样一个动机：想要确保对于任何交互式使用系统的用户性能不会下降。另一方面，这是你的系统，它应当做你要做的。</p>
<p>而要达到预定目标，做你希望你可以做的，可通过另一个称为“nice”的值直接改变调度程序的决定。这样说是因为nice值让你细致入微地对待系统中的其他任务。给进程一个正的nice值，进程将有一个较低的总优先权。相反，给它一个负的nice值，调度程序将提升其优先权。只有超级用户可以分配一个负的nice值；非特权用户可做的唯一事情是降低自己进程的优先权，在优先队列颠簸而行。</p>
<p>用负的nice值再运行preempter.sh进程如下：</p>
<p>sudo nice –n -5 ./preempter.sh &amp;</p>
<p>通过如上所述的ps命令检验有影响的优先权并与前面的结果相比。</p>
<p>nice值一经设置，它在进程生命期就是固定的，除非使用称为renice的命令改变它。除此之外，没有别的可以影响它。使用renice更改现有进程的nice值的命令是这样的：</p>
<p>sudo renice -10 –p 50432</p>
<p>（其中，50432是进程ID即想要renice的进程的pid。）此命令将告诉你，前一个优先权和新的优先权。</p>
<p>再一次，非特权用户也许只能增加nice值；即使已经是正的值，这些用户也不能降低它。</p>
<p>现在有些不同：一切都适用于“正常”进程。有一些事情尚未讨论，就是紧要的实时应用，它必须绝对保证，软件在事件发生后的某一时间间隔内作出反应。与生命 监测硬件相互作用的医学上的应用程序不过是一个例子；如果这种应用程序在应该运行的时候不能运行，那么，生命可能会失去。</p>
<p>Linux专门给实时应用程序提供平常得不到的优先级范围。命令chrt启动这样的应用软件。当它们的优先权超出正常应用的范围时，保证它们经常地运行。值得注意还有，实时进程没有nice值或奖励；这些进程永远固定在某个值。</p>
<p>下次回来，关于Linux进程，我会告诉你更多，包括如何把内核拧成适合你特殊的多任务需要。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-process-scheduler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>黑客文化简史</title>
		<link>http://www.linuxsong.org/2010/09/hacker-history/</link>
		<comments>http://www.linuxsong.org/2010/09/hacker-history/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:57:50 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=181</guid>
		<description><![CDATA[本篇原作者为Eric S. Raymond esr@snark.thyrsus.com，他是一位大哥级的 Hacker，写了很多自由软件，知名著作有Jargon File等，近年来发表“大教堂与集市”论文为Opensource software努力，Netscape 愿意公开Navigator的原始码，与这篇文章有很大的关系。 <a href="http://www.linuxsong.org/2010/09/hacker-history/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.linuxsong.org/wp-content/uploads/2010/09/hackers.jpg"><img class="alignnone size-full wp-image-193" title="hackers" src="http://www.linuxsong.org/wp-content/uploads/2010/09/hackers.jpg" alt="hackers" width="400" height="256" /></a></p>
<p>本篇原作者为Eric S. Raymond esr@snark.thyrsus.com，他是一位大哥级的 Hacker，写了很多自由软件，知名著作有Jargon File等，近年来发表“<a href="http://www.linuxsong.org/2010/09/the-cathedral-and-the-bazaar/">大教堂与集市</a>”论文为Opensource software努力，Netscape 愿意公开Navigator的原始码，与这篇文章有很大的关系。</p>
<p>Hacker文化简史</p>
<p>序曲: Real Programmer<br />
故事一开始，我要介绍的是所谓的Real Programmer。<br />
他们从不自称是Real Programmer、Hacker或任何特殊的称号；`Real Programmer&#039; 这个名词是在1980年代才出现，但早自1945年起，电脑科学便不断地吸引世界上头脑最顶尖、想像力最丰富的人投入其中。从Eckert &amp;Mauchly发明ENIAC後，便不断有狂热的programmer投入其中，他们以撰写软件与玩弄各种程式设计技巧为乐，逐渐形成具有自我意识的一套科技文化。当时这批Real Programmers主要来自工程界与物理界，他们戴著厚厚的眼镜， 穿聚酯纤维T恤与纯白袜子，用机器语言、汇编语言、FORTRAN及很多古老的 语言写程式。他们是Hacker时代的先驱者，默默贡献，却鲜为人知。</p>
<p><span id="more-181"></span>从二次大战结束後到1970早期，是打卡计算机与所谓&quot;大铁块&quot;的mainframes 流行的年代，由Real Programmer主宰电脑文化。Hacker传奇故事如有名的 Mel (收录在Jargon File中)、Murphy&#039;s Law的各种版本、mock- German`Blinkenlight&#039; 文章都是流传久远的老掉牙笑话了。</p>
<p>※译者：<br />
Jargon File亦是本文原作者所编写的，里面收录了很多Hacker用语、缩写意 义、传奇故事等等。Jargon File有出版成一本书：The New Hacker&#039;s Dictionary，MIT PRESS出版。也有Online版本: http://www.ccil.org/jargon</p>
<p>※译者：<br />
莫非定律是：当有两条路让你抉择，若其中一条会导致失败，你一定会选到它。 它有很多衍生说法：比如一个程式在demo前测试几千几万次都正确无误，但demo 那一天偏偏就会出bug。</p>
<p>一些Real Programmer仍在世且十分活跃 (本文写在1996年)。超级电脑Cray 的设计者Seymour Cray，据说亲手设计Cray全部的硬体与其操作系统，作业 系统是他用机器码硬干出来的，没有出过任何bug或error。Real Programmer 真是超强！</p>
<p>举个比较不那么夸张的例子：Stan Kelly-Bootle，The Devil&#039;s DP Dictionary 一书的作者(McGraw-Hill，1981年初版，ISBN 0-07-034022-6)与Hacker 传奇专家，当年在一台Manchester Mark I开发程式。他现在是电脑杂志的专栏 作家，写一些科学幽默小品，文笔生动有趣投今日hackers所好，所以很受欢迎。 其他人像David E. Lundstorm，写了许多关於Real Programmer的小故事， 收录在A few Good Men From UNIVAC这本书，1987年出版，ISBN-0- 262-62075-8。</p>
<p>※译：看到这里，大家应该能了解，所谓Real Programmer指的就是用组合语 言或甚至机器码，把程式用打卡机punch出一片片纸卡片，由主机读卡机输入电 脑的那种石器时代Programmer。</p>
<p>Real Programmer的时代步入尾声，取而代之的是逐渐盛行的Interactive computing，大学成立电算相关科系及电脑网络。它们催生了另一个持续的工程传统，并最终演化为今天的开放代码黑客文化。</p>
<p><big><big><strong>早期的黑客</strong></big></big></p>
<p>Hacker时代的滥觞始於1961<br />
年MIT出现第一台电脑DEC PDP-1。MIT的Tech Model Railroad Club(简称TMRC)的Power and Signals Group买了这台机器後，把它当成最时髦的科技玩具，各种程式工具与电脑术语开始出现，整个环境与文化一直发展下去至今日。 这在Steven Levy的书`Hackers&#039; 前段有详细的记载(Anchor/Doubleday 公司，1984年出版，ISBN 0-385-19195-2)。</p>
<p>※译：Interactive computing并非指Windows、GUI、WYSIWYG等介面， 当时有terminal、有shell可以下指令就算是Interactive computing了。 最先使用Hacker这个字应该是MIT。1980年代早期学术界人工智慧的权威：MIT 的Artificial Intelligence Laboratory，其核心人物皆来自TMRC。从1969年 起，正好是ARPANET建置的第一年，这群人在电脑科学界便不断有重大突破与 贡献。</p>
<p>ARPANET是第一个横跨美国的高速网络。由美国国防部所出资兴建，一个实验性 质的数位通讯网络，逐渐成长成联系各大学、国防部承包商及研究机构的大网络。 各地研究人员能以史无前例的速度与弹性交流资讯，超高效率的合作模式导致科技 的突飞猛进。</p>
<p>ARPANET另一项好处是，资讯高速公路使得全世界的hackers能聚在一起，不再像以前孤立在各地形成一股股的短命文化，网络把他们汇流成一股强大力量。 开始有人感受到Hacker文化的存在，动手整理术语放上网络，在网上发表讽刺文学与讨论Hacker所应有的道德规范。(Jargon File的第一版出现在1973年，就是一个好例子)，Hacker文化在有接上ARPANET的各大学间快速发展，特别是(但不全是)在信息相关科系。</p>
<p>一开始，整个Hacker文化的发展以MIT的AI Lab为中心，但Stanford University 的Artificial Intelligence Laboratory(简称SAIL)与稍後的Carnegie-Mellon University(简称CMU)正快速崛起中。三个都是大型的资讯科学研究中心及人工智慧的权威，聚集著世界各地的精英，不论在技术上或精神层次上， 对Hacker文<br />
化都有极高的贡献。</p>
<p>为能了解後来的故事，我们得先看看电脑本身的变化；随著科技的进步，主角MIT AI Lab也从红极一时到最後淡出舞台。</p>
<p>从MIT那台PDP-1开始，Hacker们主要程式开发平台都是Digital Equipment Corporation 的PDP迷你电脑序列。DEC率先发展出商业用途为主的interactive computing及time-sharing操作系统，当时许多的大学都是买DEC的机器， 因为它兼具弹性与速度，还很便宜(相对於较快的大型电脑mainframe)。 便宜的分时系统是Hacker文化能快速成长因素之一，在PDP流行的时代， ARPANET上是DEC机器的天下，其中最重要的便属PDP-10，PDP-10受到 Hacker们的青睐达十五年；TOPS-10(DEC的操作系统)与MACRO-10(它的组译器)，许多怀旧的术语及Hacker传奇中仍常出现这两个字。</p>
<p>MIT像大家一样用PDP-10，但他们不屑用DEC的操作系统。他们偏要自己写一个：传说中赫赫有名的ITS。</p>
<p>ITS全名是`Incompatible Timesharing System&#039;，取这个怪名果然符合MIT的搞怪作风 -- 就是要与众不同，他们很臭屁但够本事自己去写一套操作系统。ITS始终不稳，设计古怪，bug也不少，但仍有许多独到的创见，似乎还是分时系统 中开机时间最久的纪录保持者。</p>
<p>ITS本身是用汇编语言写的，其他部分由LISP写成。LISP在当时是一个威力强大与极具弹性的程式语言；事实上，二十五年後的今天，它的设计仍优於目前大多数的程式语言。LISP让ITS的Hacker得以尽情发挥想像力与搞怪能力。LISP是MIT AI Lab成功的最大功臣，现在它仍是Hacker们的最爱之一。</p>
<p>很多ITS的产物到现在仍活著；EMACS大概是最有名的一个，而ITS的稗官野史仍为今日的Hacker们所津津乐道，就如同你在Jargon File中所读到的一般。 在MIT红得发紫之际，SAIL与CMU也没闲著。SAIL的中坚份子後来成为PC 界或图形使用者介面研发的要角。CMU的Hacker则开发出第一个实用的大型专 家系统与工业用机器人。</p>
<p>另一个Hacker重镇是XEROX PARC公司的Palo Alto Research Center。从 1970初期到1980中期这十几年间，PARC不断出现惊人的突破与发明，不论质或量，软件或硬体方面。如现今的视窗滑鼠介面，雷射印表机与区域网络； 其D系列的机器，催生了能与迷你电脑一较长短的强力个人电脑。不幸这群先知先觉者并不受到公司高层的赏识；PARC是家专门提供好点子帮别人赚钱的公司成 为众所皆知的大笑话。即使如此，PARC这群人对Hacker文化仍有不可抹灭的贡献。 1970年代与PDP-10文化迅速成长茁壮。Mailing list的出现使世界各地的人得以组成许多SIG(Special-interest group)，不只在电脑方面，也有社会与娱乐方面的。DARPA对这些非`正当性&#039;活动睁一只眼闭一只眼，因为靠这些活动会吸引更多的聪明小夥子们投入 电脑领域呢。</p>
<p>有名的非电脑技术相关的ARPANET mailing list首推科幻小说迷的，时至今日ARPANET变成Internet，愈来愈多的读者参与讨论。Mailing list逐渐成为一种公众讨论的媒介，导致许多商业化上网服务如CompuServe、Genie与Prodigy 的成立。</p>
<p><big><big><strong>Unix 的兴起</strong></big></big><br />
此时在新泽西州的郊外，另一股神秘力量积极入侵Hacker社会，终於席卷整个PDP-10的传统。它诞生在1969年，也就是ARPANET成立的那一年，有个在AT&amp;T Bell Labs的年轻小夥子Ken Thompson发明了Unix。</p>
<p>Thomspon曾经参与Multics的开发，Multics是源自ITS的操作系统，用来实做当时一些较新的OS理论，如把操作系统较复杂的内部结构隐藏起来，提供一个介面，使的programmer能不用深入了解操作系统与硬体设备，也能快速开发程式。</p>
<p>译：那时的programmer写个程式必须彻底了解操作系统内部，或硬体设备。比方说写有IO的程式，对於硬碟的转速，磁轨与磁头数量等等都要搞的一清二楚才行。</p>
<p>在发现继续开发Multics是做白工时，Bell Labs很快的退出了(後来有一家公司Honeywell出售Multics，赔的很惨)。Ken Thompson很喜欢Multics上的作业环境，於是他在实验室里一台报废的DEC PDP-7上胡乱写了一个操作系统， 该系统在设计上有从Multics抄来的也有他自己的构想。他将这个操作系统命名Unix，用来反讽Multics。</p>
<p>译：其实是Ken Thompson写了一个游戏`Star Travel&#039; 没地方跑，就去找一台的报废机器PDP-7来玩。他同事Brian Kernighan嘲笑Ken Thompson说：「你写的系统好逊哦，乾脆叫Unics算了。」（Unics发音与太监的英文eunuches一样），後来才改为Unix。</p>
<p>他的同事Dennis Ritchie，发明了一个新的程式语言C，於是他与Thompson用C把原来用汇编语言写的Unix重写一遍。C的设计原则就是好用，自由与弹性， C与Unix很快地在Bell Labs得到欢迎。1971年Thompson与Ritchie争取到一个办公室自动化系统的专案，Unix开始在Bell Labs中流行。不过Thompson与Ritchie的雄心壮志还不止於此。</p>
<p>那时的传统是，一个操作系统必须完全用汇编语言写成，始能让机器发挥最高的效能。Thompson与Ritchie，是头几位领悟硬体与编译器的技术，已经进步到作业系统可以完全用高阶语言如C来写，仍保有不错的效能。五年後，Unix已经成功地移植到数种机器上。</p>
<p>译：Ken Thompson与Dennis Ritchie是唯一两位获得Turing Award(电脑界的诺贝尔奖)的工程师(其他都是学者)。</p>
<p>这当时是一件不可思议的事！它意味著，如果Unix可以在各种平台上跑的话，Unix 软件就能移植到各种机器上。再也用不著为特定的机器写软件了，能在Unix上跑最重要，重新发明轮子已经成为过去式了。</p>
<p>除了跨平台的优点外，Unix与C还有许多显著的优势。Unix与C的设计哲学是Keep It Simple, Stupid&#039;。programmer可以轻易掌握整个C的逻辑结构（不像其他之前或以後的程式语言）而不用一天到晚翻手册写程式。而Unix提供许多有用的小工具程式，经过适当的组合（写成Shell script或Perl script），可以发<br />
挥强大的威力。</p>
<p>※注：The C Programming Language是所有程式语言书最薄的一本，只有两百多页哦。作者是Brian Kernighan与Dennis Ritchie，所以这本C语言的圣经又称`K&amp;R&#039;。</p>
<p>※注：`Keep It Simple, Stupid&#039; 简称KISS，今日Unix已不follow这个原则，几乎所有Unix都是要灌一堆有的没的utilities，唯一例外是MINIX。</p>
<p>C与Unix的应用范围之广，出乎原设计者之意料，很多领域的研究要用到电脑时，他们是最佳拍档。尽管缺乏一个正式支援的机构，它们仍在AT&amp;T 内部中疯狂的散播。到了1980年，已蔓延到大学与研究机构，还有数以千计的hacker想把Unix装在家里的机器上。</p>
<p>当时跑Unix的主力机器是PDP-11、VAX系列的机器。不过由於UNIX的高移植性，它几乎可安装在所有的电脑机型上。一旦新型机器上的UNIX安 装好，把软件的C原始码抓来重新编译就一切OK了，谁还要用汇编语言来开发软件？ 有一套专为UNIX设计的网络 --- UUCP：一种低速、不稳但很成本低廉的网络。 两台UNIX机器用条电话线连起来，就可以使用互传电子邮件。UUCP是内建在UNIX系统中的，不用另外安装。於是UNIX站台连成了专属的一套网络， 形成其Hacker文化。在1980第一个USENET站台成立之後，组成了一个特大号的分散式布告栏系统，吸引而来的人数很快地超过了ARPANET。</p>
<p>少数UNIX站台有连上ARPANET。PDP-10与UNIX的Hacker文化开始交流， 不过一开始不怎么愉快就是了。PDP-10的Hacker们觉得UNIX的拥护者都是些什么也不懂的新手，比起他们那复杂华丽，令人爱不释手的LISP与ITS，C与<br />
UNIX简直原始的令人好笑。『一群穿兽皮拿石斧的野蛮人』他们咕哝著。</p>
<p>在这当时，又有另一股新潮流风行起来。第一部PC出现在1975年；苹果电脑在1977年成立，以飞快的速度成长。微电脑的潜力，立刻吸引了另一批年轻的 Hackers。他们最爱的程式语言是BASIC，由於它过於简陋，PDP-10的死忠派与UNIX迷们根本不屑用它，更看不起使用它的人。</p>
<p>译：这群Hacker中有一位大家一定认识，他的名字叫Bill Gates，最初就是他在8080上发展BASIC compiler的。</p>
<p><big><big><strong>古老时代的终结</strong></big></big><br />
1980年同时有三个Hacker文化在发展，尽管彼此偶有接触与交流，但还是各玩 各的。ARPANET/PDP-10文化，玩的是LISP、MACRO、TOPS-10与ITS。UNIX与C的拥护者用电话线把他们的PDP-11与VAX机器串起来玩。还有另一群散乱无秩序的微电脑迷，致力於将电脑科技平民化。</p>
<p>三者中ITS文化（也就是以MIT AI LAB为中心的Hacker文化）可说在此时达到全盛时期，但乌云逐渐笼罩这个实验室。ITS赖以维生的PDP-10逐渐过时，开始有人离开实验室去外面开公司，将人工智慧的科技商业化。MIT AI Lab的高手挡不住新公司的高薪挖角而纷纷出走，SAIL与CMU也遭遇到同样的问题。</p>
<p>译：这个情况在GNU宣言中有详细的描述，请参阅：(特别感谢由AKA的chuhaibo翻成中文)<br />
<a href="http://www.aka.citf.net/Magazine/Gnu/manifesto.html" target="_blank">http://www.aka.citf.net/Magazine/Gnu/manifesto.html</a></p>
<p>致命一击终於来临，1983年DEC宣布：为了要集中在PDP-11与VAX生产线， 将停止生产PDP-10；ITS没搞头了，因为它无法移植到其他机器上，或说根本没人办的到。而Berkeley Univeristy修改过的UNIX在新型的VAX跑得很顺，是 ITS理想的取代品。有远见的人都看得出，在快速成长的微电脑科技下，Unix一<br />
统江湖是迟早的事。</p>
<p>差不多在此时Steven Levy完成``Hackers&#039;&#039; 这本书，主要的资料来源是Richard M. Stallman(RMS)的故事，他是MIT AI Lab领袖人物，坚决反对实验室的研 究成果商业化。</p>
<p>Stallman接著创办了Free Software Foundation，全力投入写出高品质的自由软件。Levy以哀悼的笔调描述他是`the last true hacker&#039;，还好事实证明Levy完全错了。</p>
<p>译：Richard M. Stallman的相关事迹请参考:<a href="http://www.aka.citf.net/Magazine/Gnu/cover.htm" target="_blank">http://www.aka.citf.net/Magazine/Gnu/cover.htm</a></p>
<p>Stallman的宏大计划可说是80年代早期Hacker文化的缩影 -- 在1982年他 开始建构一个与UNIX相容但全新的操作系统，以C来写并完全免费。整个ITS 的精神与传统，经由RMS的努力，被整合在一个新的，UNIX与VAX机器上的 Hacker文化。 微电脑与区域网络的科技，开始对Hacker文化产生影响。Motorola 68000 CPU 加Ethernet是个有力的组合，也有几家公司相继成立生产第一代的工作站。 1982年，一群Berkeley出来的UNIX Hacker成立了Sun Microsystems，他们的算盘打的是：把UNIX架在以68000为CPU的机器，物美价廉又符合多数<br />
应用程式的要求。他们的高瞻远嘱为整个工业界树立了新的里程碑。虽然对个人而言，工作站仍太昂贵，不过在公司与学校眼中，工作站真是比迷你电脑便宜太多了。在这些机构里，工作站（几乎是一人一台）很快地取代了老旧庞大的VAX等timesharing机器。 译：Sun一开始生产的工作站CPU是用Motorola 68000系列，到1989才<br />
推出自行研发的以SPARC系列为CPU的SPARCstation。</p>
<p><big><big><strong>私有Unix时代</strong></big></big></p>
<p>1984年AT&amp;T解散了，UNIX正式成为一个商品。当时的Hacker文化分成两大类，一类集中在Internet与USENET上（主要是跑UNIX的迷你电脑或工作站连上网络），以及另一类PC迷，他们绝大多数没有连上Internet。<br />
※译：台湾在1992年左右连上Internet前，玩家们主要以电话拨接BBS交换资讯，但是有区域性的限制，发展性也大不如USENET。 Sun与其他厂商制造的工作站为Hacker们开启了另一个美丽新世界。工作站诉求的是高效能的绘图与网络，1980年代Hacker们致力为工作站撰写软件，不断挑战及突破以求将这些功能发挥到百分之一百零一。Berkeley发展出一套内建支援ARPANET protocols的UNIX，让UNIX能轻松连上网络，Internet也成长<br />
的更加迅速。<br />
除了Berkeley让UNIX网络功能大幅提升外，尝试为工作站开发一套图形界面也不少。最有名的要算MIT开发的X window了。X window成功的关键在完全公开原始码，展现出Hacker一贯作风，并散播到Internet上。X成功的干掉其他商业化的图形界面的例子，对数年後UNIX的发展有著深远的启发与影响。 少数ITS死忠派仍在顽抗著，到1990年最後一台ITS也永远关机长眠了；那些死忠派在穷途末路下只有悻悻地投向UNIX的怀抱。</p>
<p>UNIX们此时也分裂为Berkeley UNIX与AT&amp;T两大阵营，也许你看过一些当时的海报，上面画著一台钛翼战机全速飞离一个爆炸中、上面印著AT&amp;T的商标的死星。 Berkeley UNIX的拥护者自喻为冷酷无情的公司帝国的反抗军。就销售量来说，AT&amp;T UNIX始终赶不上BSD/Sun，但它赢了标准制订的战争。到1990年，AT&amp;T与BSD版本已难明显区分，因为彼此都有采用对方的新发明。 随著90年代的来到，工作站的地位逐渐受到新型廉价的高档PC的威胁，他们主要是用Intel 80386系列CPU。第一次Hacker能买一台威力等同於十年前的迷你电脑的机器，上面跑著一个完整的UNIX，且能轻易的连上网络。 沈浸在MS-DOS世界的井底蛙对这些巨变仍一无所知，从早期只有少数人对微电脑有兴趣，到此时玩DOS与Mac的人数已超过所谓的&quot;网络民族&quot;的文化， 但他们始终没成什么气候或搞出什么飞机，虽然聊有佳作光芒乍现，却没有稳定发展出统一的文化传统，术语字典，传奇故事与神话般的历史。它们没有真正的网 络，只能聚在小型的BBS站或一些失败的网络如FIDONET。 提供上网服务的公司如CompuServe或Genie生意日益兴隆，事实显示non-UNIX的操作系统因为并没有内附如compiler等程式发展工 具，很少有source 在网络上流传，也因此无法形成合作开发软件的风气。 Hacker文化的主力，是散布在Internet各地，几乎可说是玩UNIX的文化。他们玩电脑才不在乎什么售後服务之类，他们要的是更好的工具、更多 的上网时间、<br />
还有一台便宜32-bit PC。</p>
<p>机器有了，可以上网了，但软件去哪找？商业的UNIX贵的要命，一套要好几千大洋($)。90年代早期，开始有公司将AT&amp;T 与BSD UNIX移植到PC上出售。 成功与否不论，价格并没有降下来，更要紧的是没有附原始码，你根本不能也不准 修改它，以符合自己的需要或拿去分享给别人。传统的商业软件并没有给Hacker<br />
们真正想要的。</p>
<p>即使是Free Software Foundation(FSF)也没有写出Hacker想要的操作系统，<br />
RMS承诺的GNU操作系统 -- HURD说了好久了，到1996年都没看到影子(虽<br />
然1990年开始，FSF的软件已经可以在所有的UNIX平台执行)。</p>
<p><big><big><strong>早期的免费Unix</strong></big></big></p>
<p>在这空窗期中，1992年一位芬兰Helsinki University的学生 -- Linus Torvalds 开始在一台386PC上发展一个自由软件的UNIX kernel，使用FSF的程式开发工具。</p>
<p>他很快的写好简单的版本，丢到网络上分享给大家，吸引了非常多的Hacker来帮 忙一起发展Linux -- 一个功能完整的UNIX，完全免费且附上全部的原始码。 Linux最大的特色，不是功能上的先进而是全新的软件开发模式。直到Linux的 成功前，人人都认为像操作系统这么复杂的软件，非得要靠一个开发团队密切合作， 互相协调与分工才有可能写的出来。商业软件公司与80年代的Free Software Foundation所采用都是这种发展模式。</p>
<p>Linux则迥异於前者。一开始它就是一大群Hacker在网络上一起涂涂抹抹出来 的。没有严格品质控制与高层决策发展方针，靠的是每周发表新版供大家下载测试， 测试者再把bug与patch贴到网络上改进下一版。一种全新的物竞天择、去芜存菁的快速发展模式。令大夥傻眼的是，东修西改出来的Linux，跑的顺极了。</p>
<p>1993年底，Linux发展趋於成熟稳定，能与商业的UNIX一分高下，渐渐有商业应用软件移植到Linux上。不过小型UNIX厂商也因为Linux的出现而关门大吉 - 因为再没有人要买他们的东西。幸存者都是靠提供BSD为基础的UNIX的完整原 始码，有Hacker加入发展才能继续生存。</p>
<p>Hacker文化，一次次被人预测即将毁灭，却在商业软件充斥的世界中，披荆斩棘，<br />
筚路蓝缕，开创出另一番自己的天地。</p>
<p><big><big><strong>网络大爆炸时代</strong></big></big></p>
<p><a href="http://www.linuxsong.org/category/linux/">Linux</a>能快速成长的来自令一个事实：Internet大受欢迎，90年代早期ISP如雨後春笋般的冒出来，World-Wide Web的出现，使得Internet成长的速度， 快到有令人窒息的感觉。</p>
<p>BSD专案在1994正式宣布结束，Hacker们用的主要是免费的UNIX(Linux与一些4.4BSD的衍生版本)。而Linux CD-ROM销路非常好(好到像卖煎饼般)。 近几年来Hacker们主要活跃在Linux与Internet发展上。World Wide Web<br />
让Internet成为世界最大的传输媒体，很多80年代与90年代早期的Hacker们现在都在经营ISP。</p>
<p>Internet的盛行，Hacker文化受到重视并发挥其政治影响力。94、95年美国政府打算把一些较安全、难解的编码学加以监控，不容许外流与使用。这个称为Clipper proposal的专案引起了Hacker们的群起反对与强烈抗议而半途夭折。 96年Hacker又发起了另一项抗议运动对付那取名不当的&quot;Communications<br />
Decency Act&quot;，誓言维护Internet上的言论自由。</p>
<p>电脑与Internet在21世纪将是大家不可或缺的生活用品，现代孩子在使用 Internet科技迟早会接触到Hacker文化。它的故事传奇与哲学，将吸引更多人投入。未来对Hacker们是充满光明的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/hacker-history/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>不安装rpm包提取rpm软件包中的文件</title>
		<link>http://www.linuxsong.org/2010/09/cpio/</link>
		<comments>http://www.linuxsong.org/2010/09/cpio/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:51:55 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=179</guid>
		<description><![CDATA[有时我们需要取出rpm包中的文件，但是不想安装。Linux提供的丰富工具让我们可以轻易解决这个问题，方法是用rpm2cpio将rpm文件转换成cpio格式，然后再从cpio中提取文件。 <a href="http://www.linuxsong.org/2010/09/cpio/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>有时我们需要取出rpm包中的文件，但是不想安装。<a href="http://www.linuxsong.org/category/linux/">Linux</a>提供的丰富工具让我们可以轻易解决这个问题，方法是用rpm2cpio将rpm文件转换成cpio格式，然后再从cpio中提取文件，下面是详细命令：</p>
<p>rpm2cpio foo.rpm | cpio -idmv</p>
<p>rpm2cpio可以将rpm包转换成cpio格式<br />
cpio命令中的-i是提取文件，-d表示根据rpm包中文件原来的路径建立目, -m是保持文件的更新时间, -v是显示处理的文件列表。</p>
<p>这样就会把foo.rpm文件中的所有文件放在当前目录中。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/cpio/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Linux man手册的章节分类</title>
		<link>http://www.linuxsong.org/2010/09/linux-man/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-man/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:50:01 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=177</guid>
		<description><![CDATA[Linux提供了丰富的帮助手册，当你需要查看某个命令的参数时不必到处上网查找，只要man一下即可。 <a href="http://www.linuxsong.org/2010/09/linux-man/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Linux提供了丰富的帮助手册，当你需要查看某个命令的参数时不必到处上网查找，只要man一下即可。<br />
<a href="http://www.linuxsong.org/category/linux/">Linux</a>的man手册共有以下几个章节：</p>
<p>1、Standard commands （标准命令）<br />
2、System calls （系统调用）<br />
3、Library functions （库函数）<br />
4、Special devices （设备说明）<br />
5、File formats （文件格式）<br />
6、Games and toys （游戏和娱乐）<br />
7、Miscellaneous （杂项）<br />
8、Administrative Commands （管理员命令）</p>
<p>例如：我们输入 man ls，它会在最左上角显示“LS（1）”，在这里，“LS”表示手册名称，而“（1）”表示该手册位于第一节章，同样，我们输入“man ifconfig”它会在最左上角显示“IFCONFIG（8）”。也可以这样输入命令：“man [章节号] 手册名称”。</p>
<p>man是按照手册的章节号的顺序进行搜索的，比如：</p>
<p>man sleep</p>
<p>只会显示sleep命令的手册,如果想查看库函数sleep，就要输入:</p>
<p>man 3 sleep</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-man/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux设置shell提示符的方法</title>
		<link>http://www.linuxsong.org/2010/09/setup-shell-prompt/</link>
		<comments>http://www.linuxsong.org/2010/09/setup-shell-prompt/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:46:15 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=174</guid>
		<description><![CDATA[Linux系统终端提示符的特征由系统环境变量PS1定义。通过命令echo $PS1查看当前设置。 <a href="http://www.linuxsong.org/2010/09/setup-shell-prompt/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.linuxsong.org/category/linux/">Linux</a>系统终端提示符的特征由系统环境变量PS1定义。通过命令echo $PS1查看当前设置。</p>
<p>PS1的值由一系列静态文本或\和转义字符序列组成，如:<br />
PS1=&quot;\u@\H \w$ &quot;</p>
<p>比较有用的转义序列有：<br />
\a ASCII 响铃字符（也可以键入 \007）<br />
\d &quot;Wed Sep 06&quot; 格式的日期<br />
\e ASCII转义字符<br />
\h 主机名<br />
\H 完整的主机名<br />
\j 在此 shell 中通过按 ^Z 挂起的进程数<br />
\l 此 shell 的终端设备名（如 &quot;ttyp1&quot;）<br />
\n 换行符<br />
\r 回车符<br />
\s shell 的名称（如 &quot;bash&quot;）<br />
\t 24小时制时间<br />
\T 12小时制时间<br />
\@ 带有 am/pm 的 12 小时制时间<br />
\v bash 的版本（如 2.04）<br />
\V Bash 版本（包括补丁级别）<br />
\u 用户名<br />
\w 当前工作目录（绝对路径）<br />
\w 当前工作目录（basename）<br />
\! 当前命令在历史缓冲区的位置<br />
\$ 如果当前用户是super user，则插入字符#；否则插入字符$<br />
\\ 反斜杠<br />
\[ 出现在不移动光标的字符序列之前<br />
\] 出现在非打印字符之后<br />
\xxx 插入一个用三位数 xxx（用零代替未使用的数字，如 &quot;\007&quot;）表示的 ASCII 字符</p>
<p>我们可以通过设置PS1变量使提示符成为彩色。在PS1中设置字符序列颜色的格式为：<br />
\[\e[F;Bm\]<br />
其中``F&#039;&#039;为字体颜色，编号30~37；``B&#039;&#039;为背景色，编号40~47。<br />
可通过``\e[0m''关闭颜色输出；特别的，当B为1时，将显示加亮加粗的文字，详细请看下面的颜色表与代码表。</p>
<p>颜色表</p>
<p>前景 背景 颜色<br />
---------------------------------------<br />
30 40 黑色<br />
31 41 紅色<br />
32 42 綠色<br />
33 43 黃色<br />
34 44 藍色<br />
35 45 紫紅色<br />
36 46 青藍色<br />
37 47 白色</p>
<p>代码 意义<br />
-------------------------<br />
0 OFF<br />
1 高亮显示<br />
4 underline<br />
5 闪烁<br />
7 反白显示<br />
8 不可见</p>
<p>如果想要设置终端提示符的样式只要把$PS1在~/.bahrc指定即可比，比如我的设置如下：</p>
<p>PS1="\[\e[32m\][\u@\h \w]$\[\e[m\]&quot;<br />
export PS1<br />
效果：<br />
[LinuxSong@test ~]$</p>
<p>根据你的爱好，设置自己喜欢的样式吧:)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/setup-shell-prompt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何用正确的方法来写出质量好的软件的75条体会</title>
		<link>http://www.linuxsong.org/2010/09/write-good-software/</link>
		<comments>http://www.linuxsong.org/2010/09/write-good-software/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:43:54 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=171</guid>
		<description><![CDATA[1. 你们的项目组使用源代码管理工具了么？
应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。

2. 你们的项目组使用缺陷管理系统了么？
应该用。ClearQuest太复杂，我的推荐是BugZilla。 <a href="http://www.linuxsong.org/2010/09/write-good-software/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>1. 你们的项目组使用源代码管理工具了么？<br />
应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。</p>
<p>2. 你们的项目组使用缺陷管理系统了么？<br />
应该用。ClearQuest太复杂，我的推荐是BugZilla。</p>
<p>3. 你们的测试组还在用Word写测试用例么？<br />
不要用Word写测试用例（Test Case）。应该用一个专门的系统，可以是Test Manager，也可以是自己开发一个ASP.NET的小网站。主要目的是Track和Browse。</p>
<p>4. 你们的项目组有没有建立一个门户网站？<br />
要 有一个门户网站，用来放Contact Info、Baselined Schedule、News等等。推荐Sharepoint PortalServer 2003来实现，15分钟就搞定。买不起SPS 2003可以用WSS (Windows Sharepoint Service)。</p>
<p>5. 你们的项目组用了你能买到最好的工具么？<br />
应该用尽量好的工具来工作。比如，应该用VS.NET而不是Notepad来写C#。用Notepad写程序多半只是一种炫耀。但也要考虑到经费，所以说是“你能买到最好的”。</p>
<p>6. 你们的程序员工作在安静的环境里么？<br />
需要安静环境。这点极端重要，而且要保证每个人的空间大于一定面积。</p>
<p>7. 你们的员工每个人都有一部电话么？<br />
需要每人一部电话。而且电话最好是带留言功能的。当然，上这么一套带留言电话系统开销不小。不过至少每人一部电话要有，千万别搞得经常有人站起来喊：“某某某电话”。《人件》里面就强烈谴责这种做法。</p>
<p>8. 你们每个人都知道出了问题应该找谁么？<br />
应该知道。任何一个Feature至少都应该有一个Owner，当然，Owner可以继续Dispatch给其他人。</p>
<p>9. 你遇到过有人说“我以为…”么？<br />
要消灭“我以为”。Never assume anything。</p>
<p>10. 你们的项目组中所有的人都坐在一起么？<br />
需要。我反对Virtual Team，也反对Dev在美国、Test在中国这种开发方式。能坐在一起就最好坐在一起，好处多得不得了。<br />
<span id="more-171"></span><br />
11. 你们的进度表是否反映最新开发进展情况？<br />
应该反映。但是，应该用Baseline的方法来管理进度表：维护一份稳定的Schedule，再维护一份最新更改。Baseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手段。</p>
<p>12. 你们的工作量是先由每个人自己估算的么？<br />
应该让每个人自己估算。要从下而上估算工作量，而不是从上往下分派。除非有其他原因，比如政治任务工期固定等。</p>
<p>13. 你们的开发人员从项目一开始就加班么？<br />
不要这样。不要一开始就搞疲劳战。从项目一开始就加班，只能说明项目进度不合理。当然，一些对日软件外包必须天天加班，那属于剥削的范畴。</p>
<p>14. 你们的项目计划中Buffer Time是加在每个小任务后面的么？<br />
不要。Buffer Time加在每个小任务后面，很容易轻易的就被消耗掉。Buffer Time要整段的加在一个Milestone或者checkpoint前面。</p>
<p>15. 值得再多花一些时间，从95%做到100%好<br />
值得，非常值得。尤其当项目后期人困马乏的时候，要坚持。这会给产品带来质的区别。</p>
<p>16. 登记新缺陷时，是否写清了重现步骤？<br />
要。这属于Dev和Test之间的沟通手段。面对面沟通需要，详细填写Repro Steps也需要。</p>
<p>17. 写新代码前会把已知缺陷解决么？<br />
要。每个人的缺陷不能超过10个或15个，否则必须先解决老的bug才能继续写新代码。</p>
<p>18. 你们对缺陷的轻重缓急有事先的约定么？<br />
必须有定义。Severity要分1、2、3，约定好：蓝屏和Data Lost算Sev 1，Function Error算Sev 2，界面上的算Sev 3。但这种约定可以根据产品质量现状适当进行调整。</p>
<p>19. 你们对意见不一的缺陷有三国会议么？<br />
必须要有。要有一个明确的决策过程。这类似于CCB (Change Control Board)的概念。</p>
<p>20. 所有的缺陷都是由登记的人最后关闭的么？<br />
Bug应该由Opener关闭。Dev不能私自关闭Bug。</p>
<p>21. 你们的程序员厌恶修改老的代码么？<br />
厌恶是正常的。解决方法是组织Code Review，单独留出时间来。XP也是一个方法。</p>
<p>22. 你们项目组有Team Morale Activity么？<br />
每个月都要搞一次，吃饭、唱歌、Outing、打球、开卡丁车等等，一定要有。不要剩这些钱。</p>
<p>23. 你们项目组有自己的Logo么？<br />
要有自己的Logo。至少应该有自己的Codename。</p>
<p>24. 你们的员工有印有公司Logo的T-Shirt么？<br />
要有。能增强归属感。当然，T-Shirt要做的好看一些，最好用80支的棉来做。别没穿几次就破破烂烂的。</p>
<p>25. 总经理至少每月参加次项目组会议<br />
要的。要让team member觉得高层关注这个项目。</p>
<p>26. 你们是给每个Dev开一个分支么？<br />
反对。Branch的管理以及Merge的工作量太大，而且容易出错。</p>
<p>27. 有人长期不Check-In代码么？<br />
不可以。对大部分项目来说，最多两三天就应该Check-In。</p>
<p>28. 在Check-In代码时都填写注释了么？<br />
要写的，至少一两句话，比如“解决了Bug No.225”。如果往高处拔，这也算做“配置审计”的一部分。</p>
<p>29. 有没有设定每天Check-In的最后期限？<br />
要的，要明确Check-In Deadline。否则会Build Break。</p>
<p>30. 你们能把所有源码一下子编译成安装文件吗？<br />
要的。这是每日编译（Daily Build）的基础。而且必须要能够做成自动的。</p>
<p>31. 你们的项目组做每日编译么？<br />
当然要做。有三样东西是软件项目/产品开发必备的：1. bug management; 2. source control; 3. daily build。</p>
<p>32. 你们公司有没有积累一个项目风险列表？<br />
要。Risk Inventory。否则，下个项目开始的时候，又只能拍脑袋分析Risk了。</p>
<p>33. 设计越简单越好<br />
越简单越好。设计时候多一句话，将来可能就带来无穷无尽的烦恼。应该从一开始就勇敢的砍。这叫scope management。</p>
<p>34. 尽量利用现有的产品、技术、代码<br />
千 万别什么东西都自己Coding。BizTalk和Sharepoint就是最好的例子，有这两个作为基础，可以把起点提高很多。或者可以尽量多用现成的 Control之类的。或者尽量用XML，而不是自己去Parse一个文本文件；尽量用RegExp，而不是自己从头操作字符串，等等等等。这就是“软件 复用”的体现。</p>
<p>35. 你们会隔一段时间就停下来夯实代码么？<br />
要。最好一个月左右一次。传言去年年初Windows组在Stevb的命令下停过一个月增强安全。Btw，“夯”这个字念“hang”，第一声。</p>
<p>36. 你们的项目组每个人都写Daily Report么？<br />
要写。五分钟就够了，写10句话左右，告诉自己小组的人今天我干了什么。一则为了沟通，二则鞭策自己（要是游手好闲一天，自己都会不好意思写的）。</p>
<p>37. 你们的项目经理会发出Weekly Report么？<br />
要。也是为了沟通。内容包括目前进度，可能的风险，质量状况，各种工作的进展等。</p>
<p>38. 你们项目组是否至少每周全体开会一次？<br />
要。一定要开会。程序员讨厌开会，但每个礼拜开会时间加起来至少应该有4小时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code。</p>
<p>39. 你们项目组的会议、讨论都有记录么？<br />
会前发meeting request和agenda，会中有人负责主持和记录，会后有人负责发meeting minutes，这都是effective meeting的要点。而且，每个会议都要形成agreements和action items。</p>
<p>40. 其他部门知道你们项目组在干什么么？<br />
要发一些Newsflash给整个大组织。Show your team’s value。否则，当你坐在电梯里面，其他部门的人问：“你们在干嘛”，你回答“ABC项目”的时候，别人全然不知，那种感觉不太好。</p>
<p>41. 通过Email进行所有正式沟通<br />
Email的好处是免得抵赖。但也要避免矫枉过正，最好的方法是先用电话和当面说，然后Email来确认。</p>
<p>42. 为项目组建立多个Mailing Group<br />
如 果在AD+Exchange里面，就建Distribution List。比如，我会建ABC Project Core Team，ABCProject Dev Team，ABC Project All Testers，ABC Project ExtendedTeam等等。这样发起Email来方便，而且能让该收到email的人都收到、不该收到不被骚扰。</p>
<p>43. 每个人都知道哪里可以找到全部的文档么？<br />
应该每个人都知道。这叫做知识管理（Knowledge Management）。最方便的就是把文档放在一个集中的File Share，更好的方法是用Sharepoint。</p>
<p>44. 你做决定、做变化时，告诉大家原因了么？<br />
要 告诉大家原因。Empower teammember的手段之一是提供足够的information，这是MSF一开篇的几个原则之一。的确如此，tell me why是人之常情，tellmewhy了才能有understanding。中国人做事喜欢搞限制，限制信息，似乎能够看到某一份文件的人就是有身份的 人。大错特错。权威、权力，不在于是不是能access information/data，而在于是不是掌握资源。</p>
<p>45. Stay agile and expect change<br />
要这样。需求一定会变的，已经写好的代码一定会被要求修改的。做好心理准备，对change不要抗拒，而是expect change。</p>
<p>46. 你们有没有专职的软件测试人员？<br />
要有专职测试。如果人手不够，可以peer test，交换了测试。千万别自己测试自己的。</p>
<p>47. 你们的测试有一份总的计划来规定做什么和怎么做么？<br />
这就是Test Plan。要不要做性能测试？要不要做Usability测试？什么时候开始测试性能？测试通过的标准是什么？用什么手段，自动的还是手动的？这些问题需要用Test Plan来回答。</p>
<p>48. 你是先写Test Case然后再测试的么？<br />
应该如此。应该先设计再编程、先test case再测试。当然，事情是灵活的。我有时候在做第一遍测试的同时补上test case。至于先test case再开发，我不喜欢，因为不习惯，太麻烦，至于别人推荐，那试试看也无妨。</p>
<p>49. 你是否会为各种输入组合创建测试用例？<br />
不要，不要搞边界条件组合。当心组合爆炸。有很多test case工具能够自动生成各种边界条件的组合——但要想清楚，你是否有时间去运行那么多test case。</p>
<p>50. 你们的程序员能看到测试用例么？<br />
要。让Dev看到Test Case吧。我们都是为了同一个目的走到一起来的：提高质量。</p>
<p>51. 你们是否随便抓一些人来做易用性测试？<br />
要这么做。自己看自己写的程序界面，怎么看都是顺眼的。这叫做审美疲劳——臭的看久了也就不臭了，不方便的永久了也就习惯了。</p>
<p>52. 你对自动测试的期望正确么？<br />
别期望太高。依我看，除了性能测试以外，还是暂时先忘掉“自动测试”吧，忘掉WinRunner和LoadRunner吧。对于国内的软件测试的现状来说，只能“矫枉必须过正”了。</p>
<p>53. 你们的性能测试是等所有功能都开发完才做的么？<br />
不能这样。性能测试不能被归到所谓的“系统测试”阶段。早测早改正，早死早升天。</p>
<p>54. 你注意到测试中的杀虫剂效应了么？<br />
虫子有抗药性，Bug也有。发现的新Bug越来越少是正常的。这时候，最好大家交换一下测试的area，或者用用看其他工具和手法，就又会发现一些新bug了。</p>
<p>55. 你们项目组中有人能说出产品的当前整体质量情况么？<br />
要有。当老板问起这个产品目前质量如何，Test Lead/Manager应该负责回答。</p>
<p>56. 你们有单元测试么？<br />
单元测试要有的。不过没有单元测试也不是不可以，我做过没有单元测试的项目，也做成功了——可能是侥幸，可能是大家都是熟手的关系。还是那句话，软件工程是非常实践、非常工程、非常灵活的一套方法，某些方法在某些情况下会比另一些方法好，反之亦然。</p>
<p>57. 你们的程序员是写完代码就扔过墙的么？<br />
大忌。写好一块程序以后，即便不做单元测试，也应该自己先跑一跑。虽然有了专门的测试人员，做开发的人也不可以一点测试都不做。微软还有Test Release Document的说法，程序太烂的话，测试有权踢回去。</p>
<p>58. 你们的程序中所有的函数都有输入检查么？<br />
不要。虽然说做输入检查是write secure code的要点，但不要做太多的输入检查，有些内部函数之间的参数传递就不必检查输入了，省点功夫。同样的道理，未必要给所有的函数都写注释。写一部分主要的就够了。</p>
<p>59. 产品有统一的错误处理机制和报错界面么？<br />
要 有。最好能有统一的error message，然后每个error message都带一个errornumber。这样，用户可以自己根据error number到user manual里面去看看错误的具体描述和可能原因，就像SQLServer的错误那样。同样，ASP.NET也要有统一的Exception处理。可以参 考有关的Application Block。</p>
<p>60. 你们有统一的代码书写规范么？<br />
要有。Code Convention很多，搞一份来发给大家就可以了。当然，要是有FxCop这种工具来检查代码就更好了。</p>
<p>61. 你们的每个人都了解项目的商业意义么？<br />
要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在为中国某某行业的信息化作先驱者，或者时不时的告诉team member，这个项目能够为某某某国家部门每年节省多少多少百万的纳税人的钱，这样就有动力了。平凡的事情也是可以有个崇高的目标的。</p>
<p>62. 产品各部分的界面和操作习惯一致么？<br />
要这样。要让用户觉得整个程序好像是一个人写出来的那样。</p>
<p>63. 有可以作为宣传亮点的Cool Feature么？<br />
要。这是增强团队凝聚力、信心的。而且，“一俊遮百丑”，有亮点就可以掩盖一些问题。这样，对于客户来说，会感觉产品从质量角度来说还是acceptable的。或者说，cool feature或者说亮点可以作为质量问题的一个事后弥补措施。</p>
<p>64. 尽可能缩短产品的启动时间<br />
要这样。软件启动时间（Start-Up time）是客户对性能好坏的第一印象。</p>
<p>65. 不要过于注重内在品质而忽视了第一眼的外在印象<br />
程序员容易犯这个错误：太看重性能、稳定性、存储效率，但忽视了外在感受。而高层经理、客户正相反。这两方面要兼顾，协调这些是PM的工作。</p>
<p>66. 你们根据详细产品功能说明书做开发么？<br />
要这样。要有设计才能开发，这是必须的。设计文档，应该说清楚这个产品会怎么运行，应该采取一些讲故事的方法。设计的时候千万别钻细节，别钻到数据库、代码等具体实现里面去，那些是后面的事情，一步步来不能着急。</p>
<p>67. 开始开发和测试之前每个人都仔细审阅功能设计么？<br />
要做。Function Spec review是用来统一思想的。而且，review过以后形成了一致意见，将来再也没有人可以说“你看，当初我就是反对这么设计的，现在吃苦头了吧”</p>
<p>68. 所有人都始终想着The Whole Image么？<br />
要这样。项目里面每个人虽然都只是在制造一片叶子，但每个人都应该知道自己在制造的那片叶子所在的树是怎么样子的。我反对软件蓝领，反对过分的把软件制造看成流水线、车间。参见第61条。</p>
<p>69. Dev工作的划分是单纯纵向或横向的么？<br />
不能单纯的根据功能模块分，或者单纯根据表现层、中间层、数据库层分。我推荐这么做：首先根据功能模块分，然后每个“层”都有一个Owner来Review所有人的设计和代码，保证consistency。</p>
<p>70. 你们的程序员写程序设计说明文档么？<br />
要。不过我听说微软的程序员1999年以前也不写。所以说，写不写也不是绝对的，偷懒有时候也是可以的。参见第56条。</p>
<p>71. 你在招人面试时让他写一段程序么？<br />
要的。我最喜欢让人做字符串和链表一类的题目。这种题目有很多循环、判断、指针、递归等，既不偏向过于考算法，也不偏向过于考特定的API。</p>
<p>72. 你们有没有技术交流讲座？<br />
要的。每一两个礼拜搞一次内部的Tech Talk或者Chalk Talk吧。让组员之间分享技术心得，这笔花钱送到外面去培训划算。</p>
<p>73. 你们的程序员都能专注于一件事情么？<br />
要 让程序员专注一件事。例如说，一个部门有两个项目和10个人，一种方法是让10个人同时参加两个项目，每个项目上每个人都花50%时间；另一种方法是5个 人去项目A，5个人去项目B，每个人都100%在某一个项目上。我一定选后面一种。这个道理很多人都懂，但很多领导实践起来就把属下当成可以任意拆分的资 源了。</p>
<p>74. 你们的程序员会夸大完成某项工作所需要的时间么？<br />
会的，这是常见的，尤其会在项目后期夸大做某个change所需要的时间，以次来抵制change。解决的方法是坐下来慢慢磨，磨掉程序员的逆反心理，一起分析，并把估算时间的颗粒度变小。</p>
<p>75. 尽量不要用Virtual Heads<br />
最 好不要用Virtual Heads。Virtual heads意味着resource is not secure，sharedresource会降低resource的工作效率，容易增加出错的机会，会让一心二用的人没有太多时间去review spec、reviewdesign。一个dedicated的人，要强过两个只能投入50%时间和精力的人。我是吃过亏的：7个parttime的 tester，发现的Bug和干的活，加起来还不如两个full-time的。参见第73条。73条是针对程序员的，75条是针对Resource Manager的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/write-good-software/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux内存使用情况详解</title>
		<link>http://www.linuxsong.org/2010/09/linux-memory-use/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-memory-use/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:39:20 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=169</guid>
		<description><![CDATA[Linux内存使用情况详解,通常我们用free 命令来查看内存使用情况。 <a href="http://www.linuxsong.org/2010/09/linux-memory-use/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>通常我们用free 命令来查看内存使用情况：</p>
<p>$ free -m (-m参数是指以M为单位显示内存使用情况）</p>
<pre>
           total       used       free     shared    buffers     cached
Mem:          2021       1544        477          0        320        805
-/+ buffers/cache:        417       1603
Swap:         1983          0       1983</pre>
<p>Mem：表示物理内存统计<br />
-/+ buffers/cached：表示物理内存的缓存统计<br />
Swap：表示硬盘上交换分区的使用情况，这里我们不去关心。<br />
系统的总物理内存：2021M，但系统当前真正可用的内存并不是第一行free 标记的 477M，它仅代表未被分配的内存。</p>
<p>我们使用total1、used1、free1、used2、free2 等名称来代表上面统计数据的各值，1、2 分别代表第一行和第二行的数据。</p>
<p>total1：表示物理内存总量。<br />
used1：表示总计分配给缓存（包含buffers 与cache ）使用的数量，但其中可能部分缓存并未实际使用。<br />
free1：未被分配的内存。<br />
shared1：共享内存，一般系统不会用到，这里也不讨论。<br />
buffers1：系统分配但未被使用的buffers 数量。<br />
cached1：系统分配但未被使用的cache 数量。buffer 与cache 的区别见后面。<br />
used2：实际使用的buffers 与cache 总量，也是实际使用的内存总量。<br />
free2：未被使用的buffers 与cache 和未被分配的内存之和，这就是系统当前实际可用内存。<br />
可以整理出如下等式：</p>
<p>total1 = used1 + free1total1 = used2 + free2used1 = buffers1 + cached1 + used2free2 = buffers1 + cached1 + free1</p>
<p>很多人误以为free1是实际的剩余内存，还在奇怪为什么<a href="http://www.linuxsong.org/category/linux/">Linux</a>系统占用了如此大的内存，其实这是正常的。</p>
<p>二.buffer 与cache 的区别<br />
A buffer is something that has yet to be &quot;written&quot; to disk. A cache is something that has been &quot;read&quot; from the disk and stored for later use.<br />
三.对于共享内存（Shared memory）<strong><br />
</strong>主要用于在UNIX 环境下不同进程之间共享数据，是进程间通信的一种方法.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-memory-use/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>端口列表及功能详解</title>
		<link>http://www.linuxsong.org/2010/09/service-port/</link>
		<comments>http://www.linuxsong.org/2010/09/service-port/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:37:05 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=166</guid>
		<description><![CDATA[1　tcpmux　TCP Port Service Multiplexer　　 传输控制协议端口服务多路开关选择器
2　compressnet　Management Utility　　　　 compressnet 管理实用程序
3　compressnet　Compression Process　　　　 压缩进程
5　rje　Remote Job Entry　　　　　　　　　 远程作业登录 <a href="http://www.linuxsong.org/2010/09/service-port/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>1　tcpmux　TCP Port Service Multiplexer　　 传输控制协议端口服务多路开关选择器<br />
2　compressnet　Management Utility　　　　 compressnet 管理实用程序<br />
3　compressnet　Compression Process　　　　 压缩进程<br />
5　rje　Remote Job Entry　　　　　　　　　 远程作业登录<br />
7　echo　Echo　　　　　　　　　　　　　　　 回显<br />
9　discard　Discard　　　　　　　　　　　　 丢弃<br />
11　systat　Active Users　　　　　　　　　 在线用户<br />
13　daytime　Daytime　　　　　　　　　　　 时间<br />
17　qotd　Quote of the Day　　　　　　　　 每日引用<br />
18　msp　Message Send Protocol　　　　　　 消息发送协议<br />
19　chargen　Character Generator　　　　　 字符发生器<br />
20　ftp-data　File Transfer[Default Data]　 文件传输协议(默认数据口)</p>
<p>21　ftp　File Transfer[Control]　　　　　　 文件传输协议(控制)<br />
22　ssh　SSH Remote Login Protocol　　　　 SSH远程登录协议<br />
23　telnet　Telnet　　　　　　　　　　　　 终端仿真协议<br />
24　?　any private mail system　　　　　　 预留给个人用邮件系统<br />
25　smtp　Simple Mail Transfer　　　　　　 简单邮件发送协议<br />
27　nsw-fe　NSW User System FE　　　　　　 NSW 用户系统现场工程师<br />
29　msg-icp　MSG ICP　　　　　　　　　　　 MSG　ICP<br />
31　msg-auth　MSG Authentication　　　　　 MSG验证<br />
33　dsp　Display Support Protocol　　　　　 显示支持协议<br />
35　?　any private printer server　　　　　 预留给个人打印机服务<br />
37　time　Time　　　　　　　　　　　　　　 时间<br />
38　rap　Route Access Protocol　　　　　　 路由访问协议<br />
39　rlp　Resource Location Protocol　　　　 资源定位协议<br />
41　graphics　Graphics　　　　　　　　　　 图形<br />
42　nameserver　WINS Host Name Server　　　 WINS 主机名服务<br />
43　nicname　Who Is　　　　　　　　　　　　 &quot;绰号&quot; who is服务<br />
44　mpm-flags　MPM FLAGS Protocol　　　　　 MPM(消息处理模块)标志协议<br />
45　mpm　Message Processing Module [recv]　 消息处理模块<br />
46　mpm-snd　MPM [default send]　　　　　　 消息处理模块(默认发送口)<br />
47　ni-ftp　NI FTP　　　　　　　　　　　　 NI FTP<br />
48　auditd　Digital Audit Daemon　　　　　 数码音频后台服务<br />
49　tacacs　Login Host Protocol (TACACS)　 TACACS登录主机协议<br />
50　re-mail-ck Remote Mail Checking Protocol　 远程邮件检查协议<br />
<span id="more-166"></span>51　la-maint　IMP Logical Address Maintenance　 IMP(接口信息处理机)逻辑地址维护<br />
52　xns-time　XNS Time Protocol　　　　　　 施乐网络服务系统时间协议<br />
53　domain　Domain Name Server　　　　　　 域名服务器<br />
54　xns-ch　XNS Clearinghouse　　　　　　　 施乐网络服务系统票据交换<br />
55　isi-gl　ISI Graphics Language　　　　　 ISI图形语言<br />
56　xns-auth　XNS Authentication　　　　　 施乐网络服务系统验证<br />
57　?　any private terminal access　　　　 预留个人用终端访问<br />
58　xns-mail　XNS Mail　　　　　　　　　　 施乐网络服务系统邮件<br />
59　?　any private file service　　　　　　 预留个人文件服务<br />
60　?　Unassigned　　　　　　　　　　　　　 未定义<br />
61　ni-mail　NI MAIL　　　　　　　　　　　 NI邮件?<br />
62　acas　ACA Services　　　　　　　　　? 异步通讯适配器服务<br />
63　whois+ whois+　　　　　　　　　　　　　 WHOIS+<br />
64　covia　Communications Integrator (CI)　 通讯接口<br />
65　tacacs-ds　TACACS-Database Service　　 TACACS数据库服务<br />
66　sql*net　Oracle SQL*NET　　　　　　　　 Oracle SQL*NET<br />
67　bootps　Bootstrap Protocol Server　　　 引导程序协议服务端<br />
68　bootpc　Bootstrap Protocol Client　　　 引导程序协议客户端<br />
69　tftp　Trivial File Transfer　　　　　　 小型文件传输协议<br />
70　gopher　Gopher　　　　　　　　　　　　 信息检索协议<br />
71　netrjs-1　Remote Job Service　　　　　 远程作业服务<br />
72　netrjs-2　Remote Job Service　　　　　 远程作业服务<br />
73　netrjs-3　Remote Job Service　　　　　 远程作业服务<br />
74　netrjs-4　Remote Job Service　　　　　 远程作业服务<br />
75　?　any private dial out service　　　　 预留给个人拨出服务<br />
76　deos　Distributed External Object Store 分布式外部对象存储<br />
77　?　any private RJE service　　　　　 　 预留给个人远程作业输入服务<br />
78　vettcp　vettcp　　　　　　　　　　　　 修正TCP?<br />
79　finger　Finger　　　　　　　　　　　　 查询远程主机在线用户等信息<br />
80　http　World Wide Web HTTP　　　　　　　 全球信息网超文本传输协议<br />
81　hosts2-ns　HOSTS2 Name Server　　　　　 HOST2名称服务<br />
82　xfer　XFER Utility　　　　　　　　　　 传输实用程序<br />
83　mit-ml-dev　MIT ML Device　　　　　　　 模块化智能终端ML设备<br />
84　ctf　Common Trace Facility　　　　　　 公用追踪设备<br />
85　mit-ml-dev　MIT ML Device　　　　　　　 模块化智能终端ML设备<br />
86　mfcobol　Micro Focus Cobol　　　　　　 Micro Focus Cobol编程语言<br />
87　?　any private terminal link　　　　　 预留给个人终端连接<br />
88　kerberos　Kerberos　　　　　　　　　　 Kerberros安全认证系统<br />
89　su-mit-tg　SU/MIT Telnet Gateway　　　 SU/MIT终端仿真网关<br />
90　dnsix　DNSIX Securit Attribute Token Map　 DNSIX 安全属性标记图<br />
91　mit-dov　MIT Dover Spooler　　　　　　 MIT Dover假脱机<br />
92　npp　Network Printing Protocol　　　　 网络打印协议<br />
93　dcp　Device Control Protocol　　　　　 设备控制协议<br />
94　objcall　Tivoli Object Dispatcher　　　 Tivoli对象调度<br />
95　supdup　 SUPDUP<br />
96　dixie　DIXIE Protocol Specification　　 DIXIE协议规范<br />
97　swift-rvf（Swift Remote Virtural File Protocol）快速远程虚拟文件协议<br />
98　tacnews　TAC News　　　　　　　　　　　 TAC新闻协议<br />
99　metagram　Metagram Relay<br />
100　newacct　[unauthorized use]</p>
<p>101/tcp hostname NIC Host Name Server<br />
102/tcp iso-tsap ISO-TSAP Class 0<br />
103/tcp gppitnp Genesis Point-to-Point Trans Net<br />
104/tcp acr-nema ACR-NEMA Digital Imag. &amp; Comm. 300<br />
105/tcp cso CCSO name server protocol<br />
105/tcp csnet-ns Mailbox Name Nameserver<br />
106/tcp 3com-tsmux 3COM-TSMUX<br />
107/tcp rtelnet Remote Telnet Service<br />
108/tcp snagas SNA Gateway Access Server<br />
109/tcp pop2 Post Office Protocol - Version 2<br />
110/tcp pop3 Post Office Protocol - Version 3<br />
111/tcp sunrpc SUN Remote Procedure Call<br />
112/tcp mcidas McIDAS Data Transmission Protocol<br />
113/tcp ident<br />
114/tcp audionews Audio News Multicast<br />
115/tcp sftp Simple File Transfer Protocol<br />
116/tcp ansanotify ANSA REX Notify<br />
117/tcp uucp-path UUCP Path Service<br />
118/tcp sqlserv SQL Services<br />
119/tcp nntp Network News Transfer Protocol<br />
120/tcp cfdptkt CFDPTKT<br />
121/tcp erpc Encore Expedited Remote Pro.Call<br />
122/tcp smakynet SMAKYNET<br />
123/tcp ntp Network Time Protocol<br />
124/tcp ansatrader ANSA REX Trader<br />
125/tcp locus-map Locus PC-Interface Net Map Ser<br />
126/tcp unitary Unisys Unitary Login<br />
127/tcp locus-con Locus PC-Interface Conn Server<br />
128/tcp gss-xlicen GSS X License Verification<br />
129/tcp pwdgen Password Generator Protocol<br />
130/tcp cisco-fna cisco FNATIVE<br />
131/tcp cisco-tna cisco TNATIVE<br />
132/tcp cisco-sys cisco SYSMAINT<br />
133/tcp statsrv Statistics Service<br />
134/tcp ingres-net INGRES-NET Service<br />
135/tcp epmap DCE endpoint resolution<br />
136/tcp profile PROFILE Naming System<br />
137/tcp netbios-ns NETBIOS Name Service<br />
138/tcp netbios-dgm NETBIOS Datagram Service<br />
139/tcp netbios-ssn NETBIOS Session Service<br />
140/tcp emfis-data EMFIS Data Service<br />
141/tcp emfis-cntl EMFIS Control Service<br />
142/tcp bl-idm Britton-Lee IDM<br />
143/tcp imap Internet Message Access Protocol<br />
144/tcp uma Universal Management Architecture<br />
145/tcp uaac UAAC Protocol<br />
146/tcp iso-tp0 ISO-IP0<br />
147/tcp iso-ip ISO-IP<br />
148/tcp jargon Jargon<br />
149/tcp aed-512 AED 512 Emulation Service<br />
150/tcp sql-net SQL-NET<br />
151/tcp hems HEMS<br />
152/tcp bftp Background File Transfer Program<br />
153/tcp sgmp SGMP<br />
154/tcp netsc-prod NETSC<br />
155/tcp netsc-dev NETSC<br />
156/tcp sqlsrv SQL Service<br />
157/tcp knet-cmp KNET/VM Command/Message Protocol<br />
158/tcp pcmail-srv PCMail Server<br />
159/tcp nss-routing NSS-Routing<br />
160/tcp sgmp-traps SGMP-TRAPS<br />
161/tcp snmp SNMP<br />
162/tcp snmptrap SNMPTRAP<br />
163/tcp cmip-man CMIP/TCP Manager<br />
164/tcp cmip-agent CMIP/TCP Agent<br />
165/tcp xns-courier Xerox<br />
166/tcp s-net Sirius Systems<br />
167/tcp namp NAMP<br />
168/tcp rsvd RSVD<br />
169/tcp send SEND<br />
170/tcp print-srv Network PostScript<br />
171/tcp multiplex Network Innovations Multiplex<br />
172/tcp cl/1 Network Innovations CL/1<br />
173/tcp xyplex-mux Xyplex<br />
174/tcp mailq MAILQ<br />
175/tcp vmnet VMNET<br />
176/tcp genrad-mux GENRAD-MUX<br />
177/tcp xdmcp X Display Manager Control Protocol<br />
178/tcp nextstep NextStep Window Server<br />
179/tcp bgp Border Gateway Protocol<br />
180/tcp ris Intergraph<br />
181/tcp unify Unify<br />
182/tcp audit Unisys Audit SITP<br />
183/tcp ocbinder OCBinder<br />
184/tcp ocserver OCServer<br />
185/tcp remote-kis Remote-KIS<br />
186/tcp kis KIS Protocol<br />
187/tcp aci Application Communication Interface<br />
188/tcp mumps Plus Five磗 MUMPS<br />
189/tcp qft Queued File Transport<br />
190/tcp gacp Gateway Access Control Protocol<br />
191/tcp prospero Prospero Directory Service<br />
192/tcp osu-nms OSU Network Monitoring System<br />
193/tcp srmp Spider Remote Monitoring Protocol<br />
194/tcp irc Internet Relay Chat Protocol<br />
195/tcp dn6-nlm-aud DNSIX Network Level Module Audit<br />
196/tcp dn6-smm-red DNSIX Session Mgt Module Audit Redir<br />
197/tcp dls Directory Location Service<br />
198/tcp dls-mon Directory Location Service Monitor<br />
199/tcp smux SMUX<br />
200/tcp src IBM System Resource Controller<br />
201/tcp at-rtmp AppleTalk Routing Maintenance<br />
202/tcp at-nbp AppleTalk Name Binding<br />
203/tcp at-3 AppleTalk Unused<br />
204/tcp at-echo AppleTalk Echo<br />
205/tcp at-5 AppleTalk Unused<br />
206/tcp at-zis AppleTalk Zone Information<br />
207/tcp at-7 AppleTalk Unused<br />
208/tcp at-8 AppleTalk Unused<br />
209/tcp qmtp The Quick Mail Transfer Protocol<br />
210/tcp z39.50 ANSI Z39.50<br />
211/tcp 914c/g Texas Instruments 914C/G Terminal<br />
212/tcp anet ATEXSSTR<br />
214/tcp vmpwscs VM PWSCS<br />
215/tcp softpc Insignia Solutions<br />
216/tcp CAIlic Computer Associates Int磍 License Server<br />
217/tcp dbase dBASE Unix<br />
218/tcp mpp Netix Message Posting Protocol<br />
219/tcp uarps Unisys ARPs<br />
220/tcp imap3 Interactive Mail Access Protocol v3<br />
221/tcp fln-spx Berkeley rlogind with SPX auth<br />
222/tcp rsh-spx Berkeley rshd with SPX auth<br />
223/tcp cdc Certificate Distribution Center<br />
242/tcp direct Direct<br />
243/tcp sur-meas Survey Measurement<br />
244/tcp dayna Dayna<br />
245/tcp link LINK<br />
246/tcp dsp3270 Display Systems Protocol<br />
247/tcp subntbcst_tftp SUBNTBCST_TFTP<br />
248/tcp bhfhs bhfhs<br />
256/tcp rap RAP<br />
257/tcp set Secure Electronic Transaction<br />
258/tcp yak-chat Yak Winsock Personal Chat<br />
259/tcp esro-gen Efficient Short Remote Operations<br />
260/tcp openport Openport<br />
263/tcp hdap HDAP<br />
264/tcp bgmp BGMP<br />
280/tcp http-mgmt http-mgmt<br />
309/tcp entrusttime EntrustTime<br />
310/tcp bhmds bhmds<br />
312/tcp vslmp VSLMP<br />
315/tcp dpsi DPSI<br />
316/tcp decauth decAuth<br />
317/tcp zannet Zannet<br />
321/tcp pip PIP<br />
344/tcp pdap Prospero Data Access Protocol<br />
345/tcp pawserv Perf Analysis Workbench<br />
346/tcp zserv Zebra server<br />
347/tcp fatserv Fatmen Server<br />
348/tcp csi-sgwp Cabletron Management Protocol<br />
349/tcp mftp mftp<br />
351/tcp matip-type-b MATIP Type B<br />
351/tcp bhoetty bhoetty (added 5/21/97)<br />
353/tcp ndsauth NDSAUTH<br />
354/tcp bh611 bh611<br />
357/tcp bhevent bhevent<br />
362/tcp srssend SRS Send<br />
365/tcp dtk DTK<br />
366/tcp odmr ODMR<br />
368/tcp qbikgdp QbikGDP<br />
371/tcp clearcase Clearcase<br />
372/tcp ulistproc ListProcessor<br />
373/tcp legent-1 Legent Corporation<br />
374/tcp legent-2<br />
__________________________________________________________<br />
以下是bingtang补充：<br />
0 通常用于分析操作系统。这一方法能够工作是因为在一些系统中“0”是无效端口，当你试图使用一种通常的闭合端口连接它时将产生不同的结果。一种典型的扫描：使用IP地址为0.0.0.0，设置ACK位并在以太网层广播。</p>
<p>1 tcpmux 这显示有人在寻找SGI Irix机器。Irix是实现tcpmux的主要提供者，缺省情况下tcpmux在这种系统中被打开。Iris机器在发布时含有几个缺省的无密码的帐户， 如lp, guest, uucp, nuucp, demos, tutor, diag, EZsetup, OutOfBox, 和4Dgifts。许多管理员安装后忘记删除这些帐户。因此Hacker们在Internet上搜索tcpmux并利用这些帐户。</p>
<p>7 Echo 你能看到许多人们搜索Fraggle放大器时，发送到x.x.x.0和x.x.x.255的信息。常见的一种DoS攻击是echo循环（echo- loop），攻击者伪造从一个机器发送到另一个机器的UDP数据包，而两个机器分别以它们最快的方式回应这些数据包。另一种东西是由 DoubleClick在词端口建立的TCP连接。有一种产品叫做“Resonate Global Dispatch”，它与DNS的这一端口连接以确定最近的路由。Harvest/squid cache将从3130端口发送UDP echo：“如果将cache的source_ping on选项打开，它将对原始主机的UDP echo端口回应一个HIT reply。”这将会产生许多这类数据包。</p>
<p>11 sysstat 这是一种UNIX服务，它会列出机器上所有正在运行的进程以及是什么启动了这些进程。这为入侵者提供了许多信息而威胁机器的安全，如暴露已知某些弱点或帐 户的程序。这与UNIX系统中“ps”命令的结果相似。再说一遍：ICMP没有端口，ICMP port 11通常是ICMP type=11。</p>
<p>19 chargen 这是一种仅仅发送字符的服务。UDP版本将会在收到UDP包后回应含有垃圾字符的包。TCP连接时，会发送含有垃圾字符的数据流知道连接关闭。 Hacker利用IP欺骗可以发动DoS攻击。伪造两个chargen服务器之间的UDP包。由于服务器企图回应两个服务器之间的无限的往返数据通讯一个 chargen和echo将导致服务器过载。同样fraggle DoS攻击向目标地址的这个端口广播一个带有伪造受害者IP的数据包，受害者为了回应这些数据而过载。</p>
<p>21 ftp 最常见的攻击者用于寻找打开“anonymous”的ftp服务器的方法。这些服务器带有可读写的目录。Hackers或Crackers 利用这些服务器作为传送warez (私有程序) 和pr0n(故意拼错词而避免被搜索引擎分类)的节点。</p>
<p>22 ssh PcAnywhere 建立TCP和这一端口的连接可能是为了寻找ssh。这一服务有许多弱点。如果配置成特定的模式，许多使用RSAREF库的版本有不少漏洞。（建议在其它端 口运行ssh）。还应该注意的是ssh工具包带有一个称为make-ssh-known-hosts的程序。它会扫描整个域的ssh主机。你有时会被使用 这一程序的人无意中扫描到。UDP（而不是TCP）与另一端的5632端口相连意味着存在搜索pcAnywhere的扫描。5632（十六进制的 0&#215;1600）位交换后是0&#215;0016（使进制的22）。</p>
<p>23 Telnet 入侵者在搜索远程登陆UNIX的服务。大多数情况下入侵者扫描这一端口是为了找到机器运行的操作系统。此外使用其它技术，入侵者会找到密码。</p>
<p>25 smtp 攻击者（spammer）寻找SMTP服务器是为了传递他们的spam。入侵者的帐户总被关闭，他们需要拨号连接到高带宽的e-mail服务器上，将简单 的信息传递到不同的地址。SMTP服务器（尤其是sendmail）是进入系统的最常用方法之一，因为它们必须完整的暴露于Internet且邮件的路由 是复杂的（暴露+复杂=弱点）。</p>
<p>53 DNS Hacker或crackers可能是试图进行区域传递（TCP），欺骗DNS（UDP）或隐藏其它通讯。因此防火墙常常过滤或记录53端口。需要注意的 是你常会看到53端口做为UDP源端口。不稳定的防火墙通常允许这种通讯并假设这是对DNS查询的回复。Hacker常使用这种方法穿透防火墙。</p>
<p>67&amp;68 Bootp和DHCP UDP上的Bootp/DHCP：通过DSL和cable-modem的防火墙常会看见大量发送到广播地址255.255.255.255的数据。这些机 器在向DHCP服务器请求一个地址分配。Hacker常进入它们分配一个地址把自己作为局部路由器而发起大量的“中间人”（man-in-middle） 攻击。客户端向68端口（bootps）广播请求配置，服务器向67端口（bootpc）广播回应请求。这种回应使用广播是因为客户端还不知道可以发送的 IP地址。</p>
<p>69 TFTP(UDP) 许多服务器与bootp一起提供这项服务，便于从系统下载启动代码。但是它们常常错误配置而从系统提供任何文件，如密码文件。它们也可用于向系统写入文件。</p>
<p>79 finger Hacker用于获得用户信息，查询操作系统，探测已知的缓冲区溢出错误，回应从自己机器到其它机器finger扫描。</p>
<p>98 linuxconf 这个程序提供linux boxen的简单管理。通过整合的HTTP服务器在98端口提供基于Web界面的服务。它已发现有许多安全问题。一些版本setuid root，信任局域网，在/tmp下建立Internet可访问的文件，LANG环境变量有缓冲区溢出。此外因为它包含整合的服务器，许多典型的HTTP 漏洞可能存在（缓冲区溢出，历遍目录等）</p>
<p>109 POP2 并不象POP3那样有名，但许多服务器同时提供两种服务（向后兼容）。在同一个服务器上POP3的漏洞在POP2中同样存在。</p>
<p>110 POP3 用于客户端访问服务器端的邮件服务。POP3服务有许多公认的弱点。关于用户名和密码交换缓冲区溢出的弱点至少有20个（这意味着Hacker可以在真正登陆前进入系统）。成功登陆后还有其它缓冲区溢出错误。</p>
<p>111 sunrpc portmap rpcbind Sun RPC PortMapper/RPCBIND。访问portmapper是扫描系统查看允许哪些RPC服务的最早的一步。常见RPC服务有： rpc.mountd, NFS, rpc.statd, rpc.csmd, rpc.ttybd, amd等。入侵者发现了允许的RPC服务将转向提供服务的特定端口测试漏洞。记住一定要记录线路中的daemon, IDS, 或sniffer，你可以发现入侵者正使用什么程序访问以便发现到底发生了什么。</p>
<p>113 Ident auth 这是一个许多机器上运行的协议，用于鉴别TCP连接的用户。使用标准的这种服务可以获得许多机器的信息（会被Hacker利用）。但是它可作为许多服务的 记录器，尤其是FTP, POP, IMAP, SMTP和IRC等服务。通常如果有许多客户通过防火墙访问这些服务，你将会看到许多这个端口的连接请求。记住，如果你阻断这个端口客户端会感觉到在防火 墙另一边与e-mail服务器的缓慢连接。许多防火墙支持在TCP连接的阻断过程中发回RST，着将回停止这一缓慢的连接。</p>
<p>119 NNTP news 新闻组传输协议，承载USENET通讯。当你链接到诸如：news://comp.security.firewalls/. 的地址时通常使用这个端口。这个端口的连接企图通常是人们在寻找USENET服务器。多数ISP限制只有他们的客户才能访问他们的新闻组服务器。打开新闻 组服务器将允许发/读任何人的帖子，访问被限制的新闻组服务器，匿名发帖或发送spam。</p>
<p>135 oc-serv MS RPC end-point mapper Microsoft在这个端口运行DCE RPC end-point mapper为它的DCOM服务。这与UNIX 111端口的功能很相似。使用DCOM和/或RPC的服务利用机器上的end-point mapper注册它们的位置。远端客户连接到机器时，它们查询end-point mapper找到服务的位置。同样Hacker扫描机器的这个端口是为了找到诸如：这个机器上运行Exchange Server吗？是什么版本？这个端口除了被用来查询服务（如使用epdump）还可以被用于直接攻击。有一些DoS攻击直接针对这个端口。</p>
<p>137 NetBIOS name service nbtstat (UDP) 这是防火墙管理员最常见的信息。</p>
<p>139 NetBIOS File and Print Sharing 通过这个端口进入的连接试图获得NetBIOS/SMB服务。这个协议被用于Windows“文件和打印机共享”和SAMBA。在Internet上共享 自己的硬盘是可能是最常见的问题。大量针对这一端口始于1999，后来逐渐变少。2000年又有回升。一些VBS（IE5 VisualBasic Scripting）开始将它们自己拷贝到这个端口，试图在这个端口繁殖。</p>
<p>143 IMAP 和上面POP3的安全问题一样，许多IMAP服务器有缓冲区溢出漏洞运行登陆过程中进入。记住：一种Linux蠕虫（admw0rm）会通过这个端口繁 殖，因此许多这个端口的扫描来自不知情的已被感染的用户。当RadHat在他们的Linux发布版本中默认允许IMAP后，这些漏洞变得流行起来。 Morris蠕虫以后这还是第一次广泛传播的蠕虫。这一端口还被用于IMAP2，但并不流行。已有一些报道发现有些0到143端口的攻击源于脚本。</p>
<p>161 SNMP(UDP) 入侵者常探测的端口。SNMP允许远程管理设备。所有配置和运行信息都储存在数据库中，通过SNMP客获得这些信息。许多管理员错误配置将它们暴露于 Internet。Crackers将试图使用缺省的密码“public”“private”访问系统。他们可能会试验所有可能的组合。SNMP包可能会 被错误的指向你的网络。Windows机器常会因为错误配置将HP JetDirect remote management软件使用SNMP。HP OBJECT IDENTIFIER将收到SNMP包。新版的Win98使用SNMP解析域名，你会看见这种包在子网内广播（cable modem, DSL）查询sysName和其它信息。</p>
<p>162 SNMP trap 可能是由于错误配置</p>
<p>177 xdmcp 许多Hacker通过它访问X-Windows控制台， 它同时需要打开6000端口。</p>
<p>513 rwho 可能是从使用cable modem或DSL登陆到的子网中的UNIX机器发出的广播。这些人为Hacker进入他们的系统提供了很有趣的信息。</p>
<p>553 CORBA IIOP (UDP) 如果你使用cable modem或DSL VLAN，你将会看到这个端口的广播。CORBA是一种面向对象的RPC（remote procedure call）系统。Hacker会利用这些信息进入系统。</p>
<p>600 Pcserver backdoor 请查看1524端口。<br />
一些玩script的孩子认为他们通过修改ingreslock和pcserver文件已经完全攻破了系统-- Alan J. Rosenthal.</p>
<p>635 mountd Linux的mountd Bug。这是人们扫描的一个流行的Bug。大多数对这个端口的扫描是基于UDP的，但基于TCP的mountd有所增加（mountd同时运行于两个端 口）。记住，mountd可运行于任何端口（到底在哪个端口，需要在端口111做portmap查询），只是Linux默认为635端口，就象NFS通常 运行于2049端口。</p>
<p>1024 许多人问这个端口是干什么的。它是动态端口的开始。许多程序并不在乎用哪个端口连接网络，它们请求操作系统为它们分配“下一个闲置端口”。基于这一点分配 从端口1024开始。这意味着第一个向系统请求分配动态端口的程序将被分配端口1024。为了验证这一点，你可以重启机器，打开Telnet，再打开一个 窗口运行“natstat -a”，你将会看到Telnet被分配1024端口。请求的程序越多，动态端口也越多。操作系统分配的端口将逐渐变大。再来一遍，当你浏览Web页时用 “netstat”查看，每个Web页需要一个新端口。<br />
1025，1026 参见1024</p>
<p>1080 SOCKS 这一协议以管道方式穿过防火墙，允许防火墙后面的许多人通过一个IP地址访问Internet。理论上它应该只允许内部的通信向外达到Internet。 但是由于错误的配置，它会允许Hacker/Cracker的位于防火墙外部的攻击穿过防火墙。或者简单地回应位于Internet上的计算机，从而掩饰 他们对你的直接攻击。WinGate是一种常见的Windows个人防火墙，常会发生上述的错误配置。在加入IRC聊天室时常会看到这种情况。</p>
<p>1114 SQL 系统本身很少扫描这个端口，但常常是sscan脚本的一部分。</p>
<p>1243 Sub-7木马（TCP）</p>
<p>1524 ingreslock 后门许多攻击脚本将安装一个后门Shell于这个端口（尤其是那些针对Sun系统中sendmail和RPC服务漏洞的脚本，如statd, ttdbserver和cmsd）。如果你刚刚安装了你的防火墙就看到在这个端口上的连接企图，很可能是上述原因。你可以试试Telnet到你的机器上的 这个端口，看看它是否会给你一个Shell。连接到600/pcserver也存在这个问题。</p>
<p>2049 NFS NFS程序常运行于这个端口。通常需要访问portmapper查询这个服务运行于哪个端口，但是大部分情况是安装后NFS运行于这个端口，Hacker/Cracker因而可以闭开portmapper直接测试这个端口。</p>
<p>3128 squid 这是Squid HTTP代理服务器的默认端口。攻击者扫描这个端口是为了搜寻一个代理服务器而匿名访问Internet。你也会看到搜索其它代理服务器的端口： 8000/8001/8080/8888。扫描这一端口的另一原因是：用户正在进入聊天室。其它用户（或服务器本身）也会检验这个端口以确定用户的机器是 否支持代理。</p>
<p>5632 pcAnywere 你会看到很多这个端口的扫描，这依赖于你所在的位置。当用户打开pcAnywere时，它会自动扫描局域网C类网以寻找可能得代理（译者：指agent而 不是proxy）。Hacker/cracker也会寻找开放这种服务的机器，所以应该查看这种扫描的源地址。一些搜寻pcAnywere的扫描常包含端 口22的UDP数据包。</p>
<p>6776 Sub-7 artifact 这个端口是从Sub-7主端口分离出来的用于传送数据的端口。例如当控制者通过电话线控制另一台机器，而被控机器挂断时你将会看到这种情况。因此当另一人 以此IP拨入时，他们将会看到持续的，在这个端口的连接企图。（译者：即看到防火墙报告这一端口的连接企图时，并不表示你已被Sub-7控制。）</p>
<p>6970 RealAudio RealAudio客户将从服务器的6970-7170的UDP端口接收音频数据流。这是由TCP7070端口外向控制连接设置的。</p>
<p>13223 PowWow PowWow 是Tribal Voice的聊天程序。它允许用户在此端口打开私人聊天的连接。这一程序对于建立连接非常具有“进攻性”。它会“驻扎”在这一TCP端口等待回应。这造成 类似心跳间隔的连接企图。如果你是一个拨号用户，从另一个聊天者手中“继承”了IP地址这种情况就会发生：好象很多不同的人在测试这一端口。这一协议使用 “OPNG”作为其连接企图的前四个字节。</p>
<p>17027 Conducent 这是一个外向连接。这是由于公司内部有人安装了带有Conducent &quot;adbot&quot; 的共享软件。Conducent &quot;adbot&quot;是为共享软件显示广告服务的。使用这种服务的一种流行的软件是Pkware。有人试验：阻断这一外向连接不会有任何问题，但是封掉IP地址 本身将会导致adbots持续在每秒内试图连接多次而导致连接过载：<br />
机器会不断试图解析DNS名—ads.conducent.com，即IP地址216.33.210.40 ；216.33.199.77 ；216.33.199.80 ；216.33.199.81；216.33.210.41。（译者：不知NetAnts使用的Radiate是否也有这种现象）</p>
<p>27374 Sub-7木马(TCP)</p>
<p>30100 NetSphere木马(TCP) 通常这一端口的扫描是为了寻找中了NetSphere木马。</p>
<p>31337 Back Orifice “elite” Hacker中31337读做“elite”/ei’li:t/（译者：法语，译为中坚力量，精华。即3=E, 1=L, 7=T）。因此许多后门程序运行于这一端口。其中最有名的是Back Orifice。曾经一段时间内这是Internet上最常见的扫描。现在它的流行越来越少，其它的木马程序越来越流行。</p>
<p>31789 Hack-a-tack 这一端口的UDP通讯通常是由于&quot;Hack-a-tack&quot;远程访问木马（RAT, Remote Access Trojan）。这种木马包含内置的31790端口扫描器，因此任何31789端口到317890端口的连接意味着已经有这种入侵。（31789端口是控 制连接，317890端口是文件传输连接）</p>
<p>32770~32900 RPC服务 Sun Solaris的RPC服务在这一范围内。详细的说：早期版本的Solaris（2.5.1之前）将portmapper置于这一范围内，即使低端口被防 火墙封闭仍然允许Hacker/cracker访问这一端口。扫描这一范围内的端口不是为了寻找portmapper，就是为了寻找可被攻击的已知的 RPC服务。</p>
<p>33434~33600 traceroute 如果你看到这一端口范围内的UDP数据包（且只在此范围之内）则可能是由于traceroute。参见本站相关部分。<br />
374/tcp legent-2 Legent Corporation<br />
375/tcp hassle Hassle<br />
376/tcp nip Amiga Envoy Network Inquiry Proto<br />
377/tcp tnETOS NEC Corporation<br />
378/tcp dsETOS NEC Corporation<br />
379/tcp is99c TIA/EIA/IS-99 modem client<br />
380/tcp is99s TIA/EIA/IS-99 modem server<br />
381/tcp hp-collector hp performance data collector<br />
383/tcp hp-alarm-mgr hp performance data alarm manager<br />
384/tcp arns A Remote Network Server System<br />
385/tcp ibm-app IBM Application<br />
386/tcp asa ASA Message Router Object Def.<br />
387/tcp aurp Appletalk Update-Based Routing Pro.<br />
388/tcp unidata-ldm Unidata LDM Version 4<br />
389/tcp ldap Lightweight Directory Access Protocol<br />
390/tcp uis UIS<br />
391/tcp synotics-relay SynOptics SNMP Relay Port<br />
393/tcp dis Data Interpretation System<br />
394/tcp embl-ndt EMBL Nucleic Data Transfer<br />
395/tcp netcp NETscout Control Protocol<br />
396/tcp netware-ip Novell Netware over IP<br />
397/tcp mptn Multi Protocol Trans. Net.<br />
398/tcp kryptolan Kryptolan<br />
399/tcp iso-tsap-c2 ISO Transport Class 2 Non-Control over TCP<br />
400/tcp work-sol Workstation Solutions<br />
401/tcp ups Uninterruptible Power Supply<br />
402/tcp genie Genie Protocol<br />
403/tcp decap decap<br />
404/tcp nced nced<br />
405/tcp ncld ncld<br />
406/tcp imsp Interactive Mail Support Protocol<br />
407/tcp timbuktu Timbuktu<br />
408/tcp prm-sm Prospero Resource Manager Sys. Man.<br />
409/tcp prm-nm Prospero Resource Manager Node Man.<br />
410/tcp decladebug DECLadebug Remote Debug Protocol<br />
411/tcp rmt Remote MT Protocol<br />
412/tcp synoptics-trap Trap Convention Port<br />
413/tcp smsp SMSP<br />
414/tcp infoseek InfoSeek<br />
415/tcp bnet BNet<br />
416/tcp silverplatter Silverplatter<br />
417/tcp onmux Onmux<br />
418/tcp hyper-g Hyper-G<br />
419/tcp ariel1 Ariel<br />
420/tcp smpte SMPTE<br />
421/tcp ariel2 Ariel<br />
422/tcp ariel3 Ariel<br />
423/tcp opc-job-start IBM Operations Planning and Control Start<br />
424/tcp opc-job-track IBM Operations Planning and Control Track<br />
425/tcp icad-el ICAD<br />
426/tcp smartsdp smartsdp<br />
427/tcp svrloc Server Location<br />
428/tcp ocs_cmu OCS_CMU<br />
429/tcp ocs_amu OCS_AMU<br />
430/tcp utmpsd UTMPSD<br />
431/tcp utmpcd UTMPCD<br />
432/tcp iasd IASD<br />
433/tcp nnsp NNSP<br />
434/tcp mobileip-agent MobileIP-Agent<br />
435/tcp mobilip-mn MobilIP-MN<br />
436/tcp dna-cml DNA-CML<br />
437/tcp comscm comscm<br />
438/tcp dsfgw dsfgw<br />
439/tcp dasp dasp Thomas Obermair<br />
440/tcp sgcp sgcp<br />
441/tcp decvms-sysmgt decvms-sysmgt<br />
442/tcp cvc_hostd cvc_hostd<br />
443/tcp https http protocol over TLS/SSL<br />
444/tcp snpp Simple Network Paging Protocol<br />
445/tcp microsoft-ds Microsoft-DS<br />
446/tcp ddm-rdb DDM-RDB<br />
447/tcp ddm-dfm DDM-RFM<br />
448/tcp ddm-ssl DDM-SSL<br />
449/tcp as-servermap AS Server Mapper<br />
450/tcp tserver TServer<br />
451/tcp sfs-smp-net Cray Network Semaphore server<br />
453/tcp creativeserver CreativeServer<br />
454/tcp contentserver ContentServer<br />
455/tcp creativepartnr CreativePartnr<br />
456/tcp macon-tcp macon-tcp<br />
457/tcp scohelp scohelp<br />
458/tcp appleqtc apple quick time<br />
459/tcp ampr-rcmd ampr-rcmd<br />
460/tcp skronk skronk<br />
461/tcp datasurfsrv DataRampSrv<br />
462/tcp datasurfsrvsec DataRampSrvSec<br />
463/tcp alpes alpes<br />
464/tcp kpasswd kpasswd<br />
465/tcp smtps smtp protocol over TLS/SSL (was ssmtp)<br />
466/tcp digital-vrc digital-vrc<br />
467/tcp mylex-mapd mylex-mapd<br />
468/tcp photuris proturis<br />
469/tcp rcp Radio Control Protocol<br />
470/tcp scx-proxy scx-proxy<br />
471/tcp mondex Mondex<br />
472/tcp ljk-login ljk-login<br />
473/tcp hybrid-pop hybrid-pop<br />
474/tcp tn-tl-w1 tn-tl-w1<br />
475/tcp tcpnethaspsrv tcpnethaspsrv<br />
476/tcp tn-tl-fd1 tn-tl-fd1<br />
477/tcp ss7ns ss7ns<br />
478/tcp spsc spsc<br />
479/tcp iafserver iafserver<br />
480/tcp iafdbase iafdbase<br />
481/tcp ph Ph service<br />
482/tcp bgs-nsi bgs-nsi<br />
483/tcp ulpnet ulpnet<br />
484/tcp integra-sme Integra Software Management Environment<br />
485/tcp powerburst Air Soft Power Burst<br />
486/tcp avian avian<br />
487/tcp saft saft Simple Asynchronous File Transfer<br />
488/tcp gss-http gss-http<br />
489/tcp nest-protocol nest-protocol<br />
490/tcp micom-pfs micom-pfs<br />
491/tcp go-login go-login<br />
492/tcp ticf-1 Transport Independent Convergence for FNA<br />
493/tcp ticf-2 Transport Independent Convergence for FNA<br />
494/tcp pov-ray POV-Ray<br />
495/tcp intecourier intecourier<br />
496/tcp pim-rp-disc PIM-RP-DISC<br />
497/tcp dantz dantz<br />
498/tcp siam siam<br />
499/tcp iso-ill ISO ILL Protocol<br />
500/tcp isakmp isakmp<br />
501/tcp stmf STMF<br />
502/tcp asa-appl-proto asa-appl-proto<br />
503/tcp intrinsa Intrinsa<br />
504/tcp citadel citadel<br />
505/tcp mailbox-lm mailbox-lm<br />
506/tcp ohimsrv ohimsrv<br />
507/tcp crs crs<br />
508/tcp xvttp xvttp<br />
509/tcp snare snare<br />
510/tcp fcp FirstClass Protocol<br />
511/tcp passgo PassGo<br />
512/tcp exec remote process execution;<br />
513/tcp login remote login a la telnet;<br />
514/tcp shell cmd<br />
515/tcp printer spooler<br />
516/tcp videotex videotex<br />
517/tcp talk like tenex link, but across<br />
518/tcp ntalk<br />
519/tcp utime unixtime<br />
520/tcp efs extended file name server<br />
521/tcp ripng ripng<br />
522/tcp ulp ULP<br />
523/tcp ibm-db2 IBM-DB2<br />
524/tcp ncp NCP<br />
525/tcp timed timeserver<br />
526/tcp tempo newdate<br />
527/tcp stx Stock IXChange<br />
528/tcp custix Customer IXChange<br />
529/tcp irc-serv IRC-SERV<br />
530/tcp courier rpc<br />
531/tcp conference chat<br />
532/tcp netnews readnews<br />
533/tcp netwall for emergency broadcasts<br />
534/tcp mm-admin MegaMedia Admin<br />
535/tcp iiop iiop<br />
536/tcp opalis-rdv opalis-rdv<br />
537/tcp nmsp Networked Media Streaming Protocol<br />
538/tcp gdomap gdomap<br />
539/tcp apertus-ldp Apertus Technologies Load Determination<br />
540/tcp uucp uucpd<br />
541/tcp uucp-rlogin uucp-rlogin<br />
542/tcp commerce commerce<br />
543/tcp klogin<br />
544/tcp kshell krcmd<br />
545/tcp appleqtcsrvr appleqtcsrvr<br />
546/tcp dhcpv6-client DHCPv6 Client<br />
547/tcp dhcpv6-server DHCPv6 Server<br />
548/tcp afpovertcp AFP over TCP<br />
549/tcp idfp IDFP<br />
550/tcp new-rwho new-who<br />
551/tcp cybercash cybercash<br />
552/tcp deviceshare deviceshare<br />
553/tcp pirp pirp<br />
554/tcp rtsp Real Time Stream Control Protocol<br />
555/tcp dsf<br />
556/tcp remotefs rfs server<br />
557/tcp openvms-sysipc openvms-sysipc<br />
558/tcp sdnskmp SDNSKMP<br />
559/tcp teedtap TEEDTAP<br />
560/tcp rmonitor rmonitord<br />
561/tcp monitor<br />
562/tcp chshell chcmd<br />
563/tcp nntps nntp protocol over TLS/SSL (was snntp)<br />
564/tcp 9pfs plan 9 file service<br />
565/tcp whoami whoami<br />
566/tcp streettalk streettalk<br />
567/tcp banyan-rpc banyan-rpc<br />
568/tcp ms-shuttle microsoft shuttle<br />
569/tcp ms-rome microsoft rome<br />
570/tcp meter demon<br />
571/tcp meter udemon<br />
572/tcp sonar sonar<br />
573/tcp banyan-vip banyan-vip<br />
574/tcp ftp-agent FTP Software Agent System<br />
575/tcp vemmi VEMMI<br />
576/tcp ipcd ipcd<br />
577/tcp vnas vnas<br />
578/tcp ipdd ipdd<br />
579/tcp decbsrv decbsrv<br />
581/tcp bdp Bundle Discovery Protocol<br />
588/tcp cal CAL<br />
589/tcp eyelink EyeLink<br />
590/tcp tns-cml TNS CML<br />
593/tcp http-rpc-epmap HTTP RPC Ep Map<br />
594/tcp tpip TPIP<br />
596/tcp smsd SMSD<br />
599/tcp acp Aeolon Core Protocol<br />
600/tcp ipcserver Sun IPC server<br />
606/tcp urm Cray Unified Resource Manager<br />
607/tcp nqs nqs<br />
608/tcp sift-uft Sender-Initiated/Unsolicited File Transfer<br />
609/tcp npmp-trap npmp-trap<br />
610/tcp npmp-local npmp-local<br />
611/tcp npmp-gui npmp-gui<br />
613/tcp hmmp-op HMMP Operation<br />
620/tcp sco-websrvrmgr SCO WebServer Manager<br />
621/tcp escp-ip ESCP<br />
625/tcp dec_dlm DEC DLM<br />
626/tcp asia ASIA<br />
628/tcp qmqp QMQP<br />
630/tcp rda RDA<br />
631/tcp ipp IPP (Internet Printing Protocol)<br />
632/tcp bmpp bmpp<br />
634/tcp ginad ginad<br />
635/tcp rlzdbase RLZ DBase<br />
636/tcp ldaps ldap protocol over TLS/SSL (was sldap)<br />
637/tcp lanserver lanserver<br />
639/tcp msdp MSDP<br />
666/tcp doom doom Id Software<br />
667/tcp disclose campaign contribution disclosures - SDR Technologies<br />
668/tcp mecomm MeComm<br />
669/tcp meregister MeRegister<br />
670/tcp vacdsm-sws VACDSM-SWS<br />
671/tcp vacdsm-app VACDSM-APP<br />
672/tcp vpps-qua VPPS-QUA<br />
673/tcp cimplex CIMPLEX<br />
674/tcp acap ACAP<br />
675/tcp dctp DCTP<br />
704/tcp elcsd errlog copy/server daemon<br />
705/tcp agentx AgentX<br />
709/tcp entrust-kmsh Entrust Key Management Service Handler<br />
710/tcp entrust-ash Entrust Administration Service Handler<br />
729/tcp netviewdm1 IBM NetView DM/6000 Server/Client<br />
730/tcp netviewdm2 IBM NetView DM/6000 send/tcp<br />
731/tcp netviewdm3 IBM NetView DM/6000 receive/tcp<br />
741/tcp netgw netGW<br />
742/tcp netrcs Network based Rev. Cont. Sys.<br />
744/tcp flexlm Flexible License Manager<br />
747/tcp fujitsu-dev Fujitsu Device Control<br />
748/tcp ris-cm Russell Info Sci Calendar Manager<br />
749/tcp kerberos-adm kerberos administration<br />
750/tcp rfile<br />
751/tcp pump<br />
752/tcp qrh<br />
753/tcp rrh<br />
754/tcp tell send<br />
758/tcp nlogin<br />
759/tcp con<br />
760/tcp ns<br />
761/tcp rxe<br />
762/tcp quotad<br />
763/tcp cycleserv<br />
764/tcp omserv<br />
765/tcp webster<br />
769/tcp vid<br />
770/tcp cadlock<br />
771/tcp rtip<br />
772/tcp cycleserv2<br />
773/tcp submit<br />
774/tcp rpasswd<br />
776/tcp wpages<br />
780/tcp wpgs<br />
786/tcp concert Concert<br />
787/tcp qsc QSC<br />
801/tcp device<br />
873/tcp rsync rsync<br />
886/tcp iclcnet-locate ICL coNETion locate server<br />
887/tcp iclcnet_svinfo ICL coNETion server info<br />
888/tcp accessbuilder AccessBuilder<br />
900/tcp omginitialrefs OMG Initial Refs<br />
911/tcp xact-backup xact-backup<br />
990/tcp ftps ftp protocol, control, over TLS/SSL<br />
991/tcp nas Netnews Administration System<br />
992/tcp telnets telnet protocol over TLS/SSL<br />
993/tcp imaps imap4 protocol over TLS/SSL<br />
994/tcp ircs irc protocol over TLS/SSL<br />
995/tcp pop3s pop3 protocol over TLS/SSL (was spop3)<br />
996/tcp vsinet vsinet<br />
997/tcp maitrd<br />
998/tcp busboy<br />
999/tcp garcon<br />
1000/tcp cadlock<br />
1010/tcp surf surf<br />
1023/tcp Reserved Reserved<br />
1030/tcp iad1 BBN IAD<br />
1031/tcp iad2 BBN IAD<br />
1032/tcp iad3 BBN IAD<br />
1047/tcp neod1 Sun‘s NEO Object Request Broker<br />
1048/tcp neod2 Sun‘s NEO Object Request Broker<br />
1058/tcp nim nim<br />
1059/tcp nimreg nimreg<br />
1067/tcp instl_boots Installation Bootstrap Proto. Serv.<br />
1068/tcp instl_bootc Installation Bootstrap Proto. Cli.<br />
1080/tcp socks Socks<br />
1083/tcp ansoft-lm-1 Anasoft License Manager<br />
1084/tcp ansoft-lm-2 Anasoft License Manager<br />
1123/tcp murray Murray<br />
1155/tcp nfa Network File Access<br />
1212/tcp lupa lupa<br />
1222/tcp nerv SNI R&amp;D network<br />
1239/tcp nmsd NMSD<br />
1248/tcp hermes<br />
1313/tcp bmc_patroldb BMC_PATROLDB<br />
1314/tcp pdps Photoscript Distributed Printing System<br />
1321/tcp pip PIP<br />
1345/tcp vpjp VPJP<br />
1346/tcp alta-ana-lm Alta Analytics License Manager<br />
1347/tcp bbn-mmc multi media conferencing<br />
1348/tcp bbn-mmx multi media conferencing<br />
1349/tcp sbook Registration Network Protocol<br />
1350/tcp editbench Registration Network Protocol<br />
1352/tcp lotusnote Lotus Note<br />
1353/tcp relief Relief Consulting<br />
1354/tcp rightbrain RightBrain Software<br />
1355/tcp intuitive-edge Intuitive Edge<br />
1356/tcp cuillamartin CuillaMartin Company<br />
1357/tcp pegboard Electronic PegBoard<br />
1358/tcp connlcli CONNLCLI<br />
1359/tcp ftsrv FTSRV<br />
1360/tcp mimer MIMER<br />
1361/tcp linx LinX<br />
1362/tcp timeflies TimeFlies<br />
1363/tcp ndm-requester Network DataMover Requester<br />
1364/tcp ndm-server Network DataMover Server<br />
1365/tcp adapt-sna Network Software Associates<br />
1366/tcp netware-csp Novell NetWare Comm Service Platform<br />
1367/tcp dcs DCS<br />
1368/tcp screencast ScreenCast<br />
1369/tcp gv-us GlobalView to Unix Shell<br />
1370/tcp us-gv Unix Shell to GlobalView<br />
1371/tcp fc-cli Fujitsu Config Protocol<br />
1372/tcp fc-ser Fujitsu Config Protocol<br />
1373/tcp chromagrafx Chromagrafx<br />
1374/tcp molly EPI Software Systems<br />
1375/tcp bytex Bytex<br />
1376/tcp ibm-pps IBM Person to Person Software<br />
1377/tcp cichlid Cichlid License Manager<br />
1378/tcp elan Elan License Manager<br />
1379/tcp dbreporter Integrity Solutions<br />
1380/tcp telesis-licman Telesis Network License Manager<br />
1381/tcp apple-licman Apple Network License Manager<br />
1382/tcp udt_os<br />
1383/tcp gwha GW Hannaway Network License Manager<br />
1384/tcp os-licman Objective Solutions License Manager<br />
1385/tcp atex_elmd Atex Publishing License Manager<br />
1386/tcp checksum CheckSum License Manager<br />
1387/tcp cadsi-lm Computer Aided Design Software Inc LM<br />
1388/tcp objective-dbc Objective Solutions DataBase Cache<br />
1389/tcp iclpv-dm document．nbspManager<br />
1390/tcp iclpv-sc Storage Controller<br />
1391/tcp iclpv-sas Storage Access Server<br />
1392/tcp iclpv-pm Print Manager<br />
1393/tcp iclpv-nls Network Log Server<br />
1394/tcp iclpv-nlc Network Log Client<br />
1395/tcp iclpv-wsm PC Workstation Manager software<br />
1396/tcp dvl-activemail DVL Active Mail<br />
1399/tcp cadkey-licman Cadkey License Manager<br />
1400/tcp cadkey-tablet Cadkey Tablet Daemon<br />
1402/tcp prm-sm-np Prospero Resource Manager<br />
1403/tcp prm-nm-np Prospero Resource Manager<br />
1404/tcp igi-lm Infinite Graphics License Manager<br />
1405/tcp ibm-res IBM Remote Execution Starter<br />
1406/tcp netlabs-lm NetLabs License Manager<br />
1407/tcp dbsa-lm DBSA License Manager<br />
1408/tcp sophia-lm Sophia License Manager<br />
1409/tcp here-lm Here License Manager<br />
1410/tcp hiq HiQ License Manager<br />
1411/tcp af AudioFile<br />
1412/tcp innosys InnoSys<br />
1413/tcp innosys-acl Innosys-ACL<br />
1414/tcp ibm-mqseries IBM MQSeries<br />
1415/tcp dbstar DBStar<br />
1416/tcp novell-lu6.2 Novell LU6.2<br />
1417/tcp timbuktu-srv1 Timbuktu Service 1 Port<br />
1418/tcp timbuktu-srv2 Timbuktu Service 2 Port<br />
1419/tcp timbuktu-srv3 Timbuktu Service 3 Port<br />
1420/tcp timbuktu-srv4 Timbuktu Service 4 Port<br />
1421/tcp gandalf-lm Gandalf License Manager<br />
1422/tcp autodesk-lm Autodesk License Manager<br />
1423/tcp essbase Essbase Arbor Software<br />
1424/tcp hybrid Hybrid Encryption Protocol<br />
1425/tcp zion-lm Zion Software License Manager<br />
1426/tcp sais Satellite-data Acquisition System 1<br />
1427/tcp mloadd mloadd monitoring tool<br />
1428/tcp informatik-lm Informatik License Manager<br />
1429/tcp nms Hypercom NMS<br />
1430/tcp tpdu Hypercom TPDU<br />
1431/tcp rgtp Reverse Gossip Transport<br />
1432/tcp blueberry-lm Blueberry Software License Manager<br />
1433/tcp ms-sql-s Microsoft-SQL-Server<br />
1434/tcp ms-sql-m Microsoft-SQL-Monitor<br />
1435/tcp ibm-cics IBM CICS<br />
1436/tcp saism Satellite-data Acquisition System 2<br />
1437/tcp tabula Tabula<br />
1438/tcp eicon-server Eicon Security Agent/Server<br />
1439/tcp eicon-x25 Eicon X25/SNA Gateway<br />
1440/tcp eicon-slp Eicon Service Location Protocol<br />
1441/tcp cadis-1 Cadis License Management<br />
1442/tcp cadis-2 Cadis License Management<br />
1443/tcp ies-lm Integrated Engineering Software<br />
1444/tcp marcam-lm Marcam License Management<br />
1445/tcp proxima-lm Proxima License Manager<br />
1446/tcp ora-lm Optical Research Associates License Manager<br />
1447/tcp apri-lm Applied Parallel Research LM<br />
1448/tcp oc-lm OpenConnect License Manager<br />
1449/tcp peport PEport<br />
1450/tcp dwf Tandem Distributed Workbench Facility<br />
1451/tcp infoman IBM Information Management<br />
1452/tcp gtegsc-lm GTE Government Systems License Man<br />
1453/tcp genie-lm Genie License Manager<br />
1454/tcp interhdl_elmd interHDL License Manager<br />
1455/tcp esl-lm ESL License Manager<br />
1456/tcp dca DCA<br />
1457/tcp valisys-lm Valisys License Manager<br />
1458/tcp nrcabq-lm Nichols Research Corp.<br />
1459/tcp proshare1 Proshare Notebook Application<br />
1460/tcp proshare2 Proshare Notebook Application<br />
1461/tcp ibm_wrless_lan IBM Wireless LAN<br />
1462/tcp world-lm World License Manager<br />
1463/tcp nucleus Nucleus<br />
1464/tcp msl_lmd MSL License Manager<br />
1465/tcp pipes Pipes Platform<br />
1466/tcp oceansoft-lm Ocean Software License Manager<br />
1467/tcp csdmbase CSDMBASE<br />
1468/tcp csdm CSDM<br />
1469/tcp aal-lm Active Analysis Limited License Manager<br />
1470/tcp uaiact Universal Analytics<br />
1471/tcp csdmbase csdmbase<br />
1472/tcp csdm csdm<br />
1473/tcp openmath OpenMath<br />
1474/tcp telefinder Telefinder<br />
1475/tcp taligent-lm Taligent License Manager<br />
1476/tcp clvm-cfg clvm-cfg<br />
1477/tcp ms-sna-server ms-sna-server<br />
1478/tcp ms-sna-base ms-sna-base<br />
1479/tcp dberegister dberegister<br />
1480/tcp pacerforum PacerForum<br />
1481/tcp airs AIRS<br />
1482/tcp miteksys-lm Miteksys License Manager<br />
1483/tcp afs AFS License Manager<br />
1484/tcp confluent Confluent License Manager<br />
1485/tcp lansource LANSource<br />
1486/tcp nms_topo_serv nms_topo_serv<br />
1487/tcp localinfosrvr LocalInfoSrvr<br />
1488/tcp docstor DocStor<br />
1489/tcp dmdocbroker dmdocbroker<br />
1490/tcp insitu-conf insitu-conf<br />
1491/tcp anynetgateway anynetgateway<br />
1492/tcp stone-design-1 stone-design-1<br />
1493/tcp netmap_lm netmap_lm<br />
1494/tcp ica ica<br />
1495/tcp cvc cvc<br />
1496/tcp liberty-lm liberty-lm<br />
1497/tcp rfx-lm rfx-lm<br />
1498/tcp sybase-sqlany Sybase SQL Any<br />
1499/tcp fhc Federico Heinz Consultora<br />
1500/tcp vlsi-lm VLSI License Manager<br />
1501/tcp saiscm Satellite-data Acquisition System 3<br />
1502/tcp shivadiscovery Shiva<br />
1503/tcp imtc-mcs Databeam<br />
1504/tcp evb-elm EVB Software Engineering License Manager<br />
1505/tcp funkproxy Funk Software, Inc.<br />
1506/tcp utcd Universal Time daemon (utcd)<br />
1507/tcp symplex symplex<br />
1508/tcp diagmond diagmond<br />
1509/tcp robcad-lm Robcad, Ltd. License Manager<br />
1510/tcp mvx-lm Midland Valley Exploration Ltd. Lic. Man.<br />
1511/tcp 3l-l1 3l-l1<br />
1512/tcp wins Microsoft‘s Windows Internet Name Service<br />
1513/tcp fujitsu-dtc Fujitsu Systems Business of America, Inc<br />
1514/tcp fujitsu-dtcns Fujitsu Systems Business of America, Inc<br />
1515/tcp ifor-protocol ifor-protocol<br />
1516/tcp vpad Virtual Places Audio data<br />
1517/tcp vpac Virtual Places Audio control<br />
1518/tcp vpvd Virtual Places Video data<br />
1519/tcp vpvc Virtual Places Video control<br />
1520/tcp atm-zip-office atm zip office<br />
1521/tcp ncube-lm nCube License Manager<br />
1522/tcp ricardo-lm Ricardo North America License Manager<br />
1523/tcp cichild-lm cichild<br />
1525/tcp orasrv oracle<br />
1525/tcp prospero-np Prospero Directory Service non-priv<br />
1526/tcp pdap-np Prospero Data Access Prot non-priv<br />
1527/tcp tlisrv oracle<br />
1528/tcp mciautoreg micautoreg<br />
1529/tcp coauthor oracle<br />
1530/tcp rap-service rap-service<br />
1531/tcp rap-listen rap-listen<br />
1532/tcp miroconnect miroconnect<br />
1533/tcp virtual-places Virtual Places Software<br />
1534/tcp micromuse-lm micromuse-lm<br />
1535/tcp ampr-info ampr-info<br />
1536/tcp ampr-inter ampr-inter<br />
1537/tcp sdsc-lm isi-lm<br />
1538/tcp 3ds-lm 3ds-lm<br />
1539/tcp intellistor-lm Intellistor License Manager<br />
1540/tcp rds rds<br />
1541/tcp rds2 rds2<br />
1542/tcp gridgen-elmd gridgen-elmd<br />
1543/tcp simba-cs simba-cs<br />
1544/tcp aspeclmd aspeclmd<br />
1545/tcp vistium-share vistium-share<br />
1546/tcp abbaccuray abbaccuray<br />
1547/tcp laplink laplink<br />
1548/tcp axon-lm Axon License Manager<br />
1549/tcp shivahose Shiva Hose<br />
1550/tcp 3m-image-lm Image Storage license manager 3M Company<br />
1551/tcp hecmtl-db HECMTL-DB<br />
1552/tcp pciarray pciarray<br />
1553/tcp sna-cs sna-cs<br />
1554/tcp caci-lm CACI Products Company License Manager<br />
1555/tcp livelan livelan<br />
1556/tcp ashwin AshWin CI Tecnologies<br />
1557/tcp arbortext-lm ArborText License Manager<br />
1558/tcp xingmpeg xingmpeg<br />
1559/tcp web2host web2host<br />
1560/tcp asci-val asci-val<br />
1561/tcp facilityview facilityview<br />
1562/tcp pconnectmgr pconnectmgr<br />
1563/tcp cadabra-lm Cadabra License Manager<br />
1564/tcp pay-per-view Pay-Per-View<br />
1565/tcp winddlb WinDD<br />
1566/tcp corelvideo CORELVIDEO<br />
1567/tcp jlicelmd jlicelmd<br />
1568/tcp tsspmap tsspmap<br />
1569/tcp ets ets<br />
1570/tcp orbixd orbixd<br />
1571/tcp rdb-dbs-disp Oracle Remote Data Base<br />
1572/tcp chip-lm Chipcom License Manager<br />
1573/tcp itscomm-ns itscomm-ns<br />
1574/tcp mvel-lm mvel-lm<br />
1575/tcp oraclenames oraclenames<br />
1576/tcp moldflow-lm moldflow-lm<br />
1577/tcp hypercube-lm hypercube-lm<br />
1578/tcp jacobus-lm Jacobus License Manager<br />
1579/tcp ioc-sea-lm ioc-sea-lm<br />
1580/tcp tn-tl-r1 tn-tl-r1<br />
1581/tcp mil-2045-47001 MIL-2045-47001<br />
1582/tcp msims MSIMS<br />
1583/tcp simbaexpress simbaexpress<br />
1584/tcp tn-tl-fd2 tn-tl-fd2<br />
1585/tcp intv intv<br />
1586/tcp ibm-abtact ibm-abtact<br />
1587/tcp pra_elmd pra_elmd<br />
1588/tcp triquest-lm triquest-lm<br />
1589/tcp vqp VQP<br />
1590/tcp gemini-lm gemini-lm<br />
1591/tcp ncpm-pm ncpm-pm<br />
1592/tcp commonspace commonspace<br />
1593/tcp mainsoft-lm mainsoft-lm<br />
1594/tcp sixtrak sixtrak<br />
1595/tcp radio radio<br />
1596/tcp radio-sm radio-sm<br />
1597/tcp orbplus-iiop orbplus-iiop<br />
1598/tcp picknfs picknfs<br />
1599/tcp simbaservices simbaservices<br />
1600/tcp issd<br />
1601/tcp aas aas<br />
1602/tcp inspect inspect<br />
1603/tcp picodbc pickodbc<br />
1604/tcp icabrowser icabrowser<br />
1605/tcp slp Salutation Manager (Salutation Protocol)<br />
1606/tcp slm-api Salutation Manager (SLM-API)<br />
1607/tcp stt stt<br />
1608/tcp smart-lm Smart Corp. License Manager<br />
1609/tcp isysg-lm isysg-lm<br />
1610/tcp taurus-wh taurus-wh<br />
1611/tcp ill Inter Library Loan<br />
1612/tcp netbill-trans NetBill Transaction Server<br />
1613/tcp netbill-keyrep NetBill Key Repository<br />
1614/tcp netbill-cred NetBill Credential Server<br />
1615/tcp netbill-auth NetBill Authorization Server<br />
1616/tcp netbill-prod NetBill Product Server<br />
1617/tcp nimrod-agent Nimrod Inter-Agent Communication<br />
1618/tcp skytelnet skytelnet<br />
1619/tcp xs-openstorage xs-openstorage<br />
1620/tcp faxportwinport faxportwinport<br />
1621/tcp softdataphone softdataphone<br />
1622/tcp ontime ontime<br />
1623/tcp jaleosnd jaleosnd<br />
1624/tcp udp-sr-port udp-sr-port<br />
1625/tcp svs-omagent svs-omagent<br />
1636/tcp cncp CableNet Control Protocol<br />
1637/tcp cnap CableNet Admin Protocol<br />
1638/tcp cnip CableNet Info Protocol<br />
1639/tcp cert-initiator cert-initiator<br />
1640/tcp cert-responder cert-responder<br />
1641/tcp invision InVision<br />
1642/tcp isis-am isis-am<br />
1643/tcp isis-ambc isis-ambc<br />
1645/tcp datametrics datametrics<br />
1646/tcp sa-msg-port sa-msg-port<br />
1647/tcp rsap rsap<br />
1648/tcp concurrent-lm concurrent-lm<br />
1649/tcp inspect inspect<br />
1650/tcp nkd nkd<br />
1651/tcp shiva_confsrvr shiva_confsrvr<br />
1652/tcp xnmp xnmp<br />
1653/tcp alphatech-lm alphatech-lm<br />
1654/tcp stargatealerts stargatealerts<br />
1655/tcp dec-mbadmin dec-mbadmin<br />
1656/tcp dec-mbadmin-h dec-mbadmin-h<br />
1657/tcp fujitsu-mmpdc fujitsu-mmpdc<br />
1658/tcp sixnetudr sixnetudr<br />
1659/tcp sg-lm Silicon Grail License Manager<br />
1660/tcp skip-mc-gikreq skip-mc-gikreq<br />
1661/tcp netview-aix-1 netview-aix-1<br />
1662/tcp netview-aix-2 netview-aix-2<br />
1663/tcp netview-aix-3 netview-aix-3<br />
1664/tcp netview-aix-4 netview-aix-4<br />
1665/tcp netview-aix-5 netview-aix-5<br />
1666/tcp netview-aix-6 netview-aix-6<br />
1667/tcp netview-aix-7 netview-aix-7<br />
1668/tcp netview-aix-8 netview-aix-8<br />
1669/tcp netview-aix-9 netview-aix-9<br />
1670/tcp netview-aix-10 netview-aix-10<br />
1671/tcp netview-aix-11 netview-aix-11<br />
1672/tcp netview-aix-12 netview-aix-12<br />
1673/tcp proshare-mc-1 Intel Proshare Multicast<br />
1674/tcp proshare-mc-2 Intel Proshare Multicast<br />
1675/tcp pdp Pacific Data Products<br />
1676/tcp netcomm1 netcomm1<br />
1677/tcp groupwise groupwise<br />
1678/tcp prolink prolink<br />
1679/tcp darcorp-lm darcorp-lm<br />
1681/tcp sd-elmd sd-elmd<br />
1682/tcp lanyon-lantern lanyon-lantern<br />
1683/tcp ncpm-hip ncpm-hip<br />
1684/tcp snaresecure SnareSecure<br />
1685/tcp n2nremote n2nremote<br />
1686/tcp cvmon cvmon<br />
1687/tcp nsjtp-ctrl nsjtp-ctrl<br />
1688/tcp nsjtp-data nsjtp-data<br />
1689/tcp firefox firefox<br />
1690/tcp ng-umds ng-umds<br />
1691/tcp empire-empuma empire-empuma<br />
1692/tcp sstsys-lm sstsys-lm<br />
1693/tcp rrirtr rrirtr<br />
1694/tcp rrimwm rrimwm<br />
1695/tcp rrilwm rrilwm<br />
1696/tcp rrifmm rrifmm<br />
1697/tcp rrisat rrisat<br />
1698/tcp rsvp-encap-1 RSVP-ENCAPSULATION-1<br />
1699/tcp rsvp-encap-2 RSVP-ENCAPSULATION-2<br />
1700/tcp mps-raft mps-raft<br />
1701/tcp l2f,l2tp l2f,l2tp<br />
1702/tcp deskshare deskshare<br />
1703/tcp hb-engine hb-engine<br />
1704/tcp bcs-broker bcs-broker<br />
1705/tcp slingshot slingshot<br />
1706/tcp jetform jetform<br />
1707/tcp vdmplay vdmplay<br />
1708/tcp gat-lmd gat-lmd<br />
1709/tcp centra centra<br />
1710/tcp impera impera<br />
1711/tcp pptconference pptconference<br />
1712/tcp registrar resource monitoring service<br />
1713/tcp conferencetalk ConferenceTalk<br />
1714/tcp sesi-lm sesi-lm<br />
1715/tcp houdini-lm houdini-lm<br />
1716/tcp xmsg xmsg<br />
1717/tcp fj-hdnet fj-hdnet<br />
1718/tcp h323gatedisc h323gatedisc<br />
1719/tcp h323gatestat h323gatestat<br />
1720/tcp h323hostcall h323hostcall<br />
1721/tcp caicci caicci<br />
1722/tcp hks-lm HKS License Manager<br />
1723/tcp pptp pptp<br />
1724/tcp csbphonemaster csbphonemaster<br />
1725/tcp iden-ralp iden-ralp<br />
1726/tcp iberiagames IBERIAGAMES<br />
1727/tcp winddx winddx<br />
1728/tcp telindus TELINDUS<br />
1729/tcp citynl CityNL License Management<br />
1730/tcp roketz roketz<br />
1731/tcp msiccp MSICCP<br />
1732/tcp proxim proxim<br />
1733/tcp siipat SIMS - SIIPAT Protocol for Alarm Transmission<br />
1734/tcp cambertx-lm Camber Corporation License Management<br />
1735/tcp privatechat PrivateChat<br />
1736/tcp street-stream street-stream<br />
1737/tcp ultimad ultimad<br />
1738/tcp gamegen1 GameGen1<br />
1739/tcp webaccess webaccess<br />
1740/tcp encore encore<br />
1741/tcp cisco-net-mgmt cisco-net-mgmt<br />
1742/tcp 3Com-nsd 3Com-nsd<br />
1743/tcp cinegrfx-lm Cinema Graphics License Manager<br />
1744/tcp ncpm-ft ncpm-ft<br />
1745/tcp remote-winsock remote-winsock<br />
1746/tcp ftrapid-1 ftrapid-1<br />
1747/tcp ftrapid-2 ftrapid-2<br />
1748/tcp oracle-em1 oracle-em1<br />
1749/tcp aspen-services aspen-services<br />
1750/tcp sslp Simple Socket Library‘s PortMaster<br />
1751/tcp swiftnet SwiftNet<br />
1752/tcp lofr-lm Leap of Faith Research License Manager<br />
1753/tcp translogic-lm Translogic License Manager<br />
1754/tcp oracle-em2 oracle-em2<br />
1755/tcp ms-streaming ms-streaming<br />
1756/tcp capfast-lmd capfast-lmd<br />
1757/tcp cnhrp cnhrp<br />
1758/tcp tftp-mcast tftp-mcast<br />
1759/tcp spss-lm SPSS License Manager<br />
1760/tcp www-ldap-gw www-ldap-gw<br />
1761/tcp cft-0 cft-0<br />
1762/tcp cft-1 cft-1<br />
1763/tcp cft-2 cft-2<br />
1764/tcp cft-3 cft-3<br />
1765/tcp cft-4 cft-4<br />
1766/tcp cft-5 cft-5<br />
1767/tcp cft-6 cft-6<br />
1768/tcp cft-7 cft-7</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/service-port/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>常用数列求和公式</title>
		<link>http://www.linuxsong.org/2010/09/sequence-formula/</link>
		<comments>http://www.linuxsong.org/2010/09/sequence-formula/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:34:26 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=163</guid>
		<description><![CDATA[一些常用的数列求和公式，编程的时候可能会用到，比如写一些算法的时候，需要的时候可以查一下。 <a href="http://www.linuxsong.org/2010/09/sequence-formula/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>下面是一些常用的数列求和公式，编程的时候可能会用到，比如写一些算法的时候，需要的时候可以查一下。</p>
<p>1. 1+2+3+......+n=n(n+1)/2<br />
2. 1^2+2^2+3^2+......+n^2=n(n+1)(2n+1)/6<br />
3. 1^3+2^3+3^3+......+n^3=( 1+2+3+......+n)^2=n^2*(n+1)^2/4<br />
4. 1*2+2*3+3*4+......+n(n+1)=n(n+1)(n+2)/3<br />
5. 1*2*3+2*3*4+3*4*5+......+n(n+1)(n+2)=n(n+1)(n+2)(n+3)/4</p>
<p>6. 1+3+6+10+15+......<br />
=1+(1+2)+(1+2+3)+(1+2+3+4)+......+(1+2+3+...+n)<br />
=[1*2+2*3+3*4+......+n(n+1)]/2<br />
=n(n+1)(n+2)/6</p>
<p>7. 1+2+4+7+11+......+ n<br />
=1+(1+1)+(1+1+2)+(1+1+2+3)+......+(1+1+2+3+...+n)<br />
=(n+1)*1+[1*2+2*3+3*4+......+n(n+1)]/2<br />
=(n+1)+n(n+1)(n+2)/6</p>
<p>8. 1/2+1/2*3+1/3*4+......+1/n(n+1)<br />
=1-1/(n+1)=n/(n+1)</p>
<p>9. 1/(1+2)+1/(1+2+3)+1/(1+2+3+4)+......+1/(1+2+3+...+n)<br />
= 2/2*3+2/3*4+2/4*5+......+2/n(n+1)=(n-1)/(n+1)<br />
10. 1/1*2+2/2*3+3/2*3*4+......+(n-1)/2*3*4*...*n<br />
=(2*3*4*...*n-1)/2*3*4*...*n</p>
<p>11. 1^2+3^2+5^2+..........(2n-1)^2=n(4n^2-1)/3<br />
12. 1^3+3^3+5^3+..........(2n-1)^3=n^2(2n^2-1)<br />
13. 1^4+2^4+3^4+..........+n^4=n(n+1)(2n+1)(3n^2+3n-1)/30<br />
14. 1^5+2^5+3^5+..........+n^5=n^2 (n+1)^2 (2n^2+2n-1) /12</p>
<p>15. 1+2+2^2+2^3+......+2^n=2^(n+1) – 1</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/sequence-formula/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>linux中全屏方式连续执行命令</title>
		<link>http://www.linuxsong.org/2010/09/shell-watch/</link>
		<comments>http://www.linuxsong.org/2010/09/shell-watch/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:28:42 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=160</guid>
		<description><![CDATA[在Linux 中有一个非常方便的命令 : watch，可以以全屏方式(无滚屏）在某个时间间隔连续执行一个命令。比如监视某个文件的变化情况，或者监视某个目录的大小等。 <a href="http://www.linuxsong.org/2010/09/shell-watch/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>在<a href="http://www.linuxsong.org/category/linux/">Linux </a>中有一个非常方便的命令 : watch，可以以全屏方式(无滚屏）在某个时间间隔连续执行一个命令。比如监视某个文件的变化情况，或者监视某个目录的大小等。<br />
命令参数如下</p>
<p>watch [-dhvt] [-n ] [--differences[=cumulative]] [--help] [--interval=] [--no-title] [--version]</p>
<p>其中比较常用的有：<br />
[-n ] 执行命令间隔的秒数<br />
[-d] 高亮显示变化的内容（与上次执行时的比较）<br />
[-d=cumulative] 高亮显示所有变化的内容<br />
下面举几个例子<br />
比如要查监视某个文件的变化情况，1秒更新一次：</p>
<p>$ watch -n 1 cat file</p>
<p>监视某个文件的大小变化情况，5秒更新一次：</p>
<p>$ watch -n 5 du -h file</p>
<p>以前在不知道这个命令时，总是按一下上箭头键再敲回车键:)<br />
这个命令的用处非常多，如果你以前还没有用过，那么赶紧在你的机器上试验一下吧:)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/shell-watch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C/C++字节对齐详解</title>
		<link>http://www.linuxsong.org/2010/09/c-byte-alignment/</link>
		<comments>http://www.linuxsong.org/2010/09/c-byte-alignment/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:25:32 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[c/c++]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=155</guid>
		<description><![CDATA[现代计算机中内存空间都是按照byte划分的，从理论上讲似乎对任何类型的变量的访问可以从任何地址开始，但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问，这就需要各种类型数据按照一定的规则在空间上排列，而不是顺序的一个接一个的排放，这就是对齐。 <a href="http://www.linuxsong.org/2010/09/c-byte-alignment/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>一.什么是字节对齐,为什么要对齐?</p>
<p>现代计算机中内存空间都是按照byte划分的，从理论上讲似乎对任何类型的变量的访问可以从任何地址开始，但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问，这就需要各种类型数据按照一定的规则在空间上排列，而不是顺序的一个接一个的排放，这就是对齐。</p>
<p>对齐的作用和原因：各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况，但是最常见的是如果不按照适合其平台要求对数据存放进行对齐，会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始，如果一个int型（假设为32位系统）如果存放在偶地址开始的地方，那么一个读周期就可以读出这32bit，而如果存放在奇地址开始的地方，就需要2个读周期，并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。</p>
<p>二.字节对齐对程序的影响:</p>
<p>先让我们看几个例子吧(32bit,x86环境,gcc编译器):<br />
设结构体如下定义：</p>
<pre>struct A
{
  int a;
  char b;
  short c;
};

struct B
{
  char b;
  int a;
  short c;
};</pre>
<p>现在已知32位机器上各种数据类型的长度如下:<br />
char:1(有符号无符号同)<br />
short:2(有符号无符号同)<br />
int:4(有符号无符号同)<br />
long:4(有符号无符号同)<br />
float:4 double:8<br />
那么上面两个结构大小如何呢?<br />
结果是:<br />
sizeof(strcut A)值为8<br />
sizeof(struct B)的值却是12</p>
<p><span id="more-155"></span>结构体A中包含了4字节长度的int一个，1字节长度的char一个和2字节长度的short型数据一个,B也一样;按理说A,B大小应该都是7字节。<br />
之所以出现上面的结果是因为编译器要对数据成员在空间上进行对齐。上面是按照编译器的默认设置进行对齐的结果,那么我们是不是可以改变编译器的这种默认对齐设置呢,当然可以.例如:</p>
<pre>#pragma pack (2) /*指定按2字节对齐*/
struct C
{
  char b;
  int a;
  short c;
};
#pragma pack ()   /*取消指定对齐，恢复缺省对齐*/</pre>
<p>sizeof(struct C)值是8。<br />
修改对齐值为1：</p>
<pre>#pragma pack (1) /*指定按1字节对齐*/
struct D
{
  char b;
  int a;
  short c;
};
#pragma pack () /*取消指定对齐，恢复缺省对齐*/</pre>
<p>sizeof(struct D)值为7。<br />
后面我们再讲解#pragma pack()的作用.</p>
<p>三.编译器是按照什么样的原则进行对齐的?</p>
<p>先让我们看四个重要的基本概念：<br />
1.数据类型自身的对齐值：<br />
对于char型数据，其自身对齐值为1，对于short型为2，对于int,float,double类型，其自身对齐值为4，单位字节。<br />
2.结构体或者类的自身对齐值：其成员中自身对齐值最大的那个值。<br />
3.指定对齐值：#pragma pack (value)时的指定对齐值value。<br />
4.数据成员、结构体和类的有效对齐值：自身对齐值和指定对齐值中小的那个值。<br />
有了这些值，我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值，最重要。有效对齐N，就是表示“对齐在N上”，也就是说该数据的&quot;存放起始地址%N=0&quot;.而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放，结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍，结合下面例子理解)。这样就不能理解上面的几个例子的值了。<br />
例子分析：<br />
分析例子B:</p>
<pre>struct B
{
  char b;
  int a;
  short c;
};</pre>
<p>假设B从地址空间0&#215;0000开始排放。该例子中没有定义指定对齐值，在笔者环境下，该值默认为4。第一个成员变量b的自身对齐值是1，比指定或者默认指定对齐值4小，所以其有效对齐值为1，所以其存放地址0&#215;0000符合0&#215;0000%1=0.第二个成员变量a，其自身对齐值为4，所以有效对齐值也为4，所以只能存放在起始地址为0&#215;0004到0&#215;0007这四个连续的字节空间中，复核0&#215;0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐值为 2，所以有效对齐值也是2，可以存放在0&#215;0008到0&#215;0009这两个字节空间中，符合0&#215;0008%2=0。所以从0&#215;0000到0&#215;0009存放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b）所以就是4，所以结构体的有效对齐值也是4。根据结构体圆整的要求， 0&#215;0009到0&#215;0000=10字节，（10＋2）％4＝0。所以0x0000A到0x000B也为结构体B所占用。故B从0&#215;0000到0x000B 共有12个字节,sizeof(struct B)=12;其实如果就这一个就来说它已将满足字节对齐了, 因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,是因为编译器为了实现结构数组的存取效率,试想如果我们定义了一个结构B的数组,那么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果我们不把结构的大小补充为4的整数倍,那么下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此我们要把结构补充成有效对齐大小的整数倍.其实诸如:对于char型数据，其自身对齐值为1，对于short型为2，对于int,float,double类型，其自身对齐值为4，这些已有类型的自身对齐值也是基于数组考虑的,只是因为这些类型的长度已知了,所以他们的自身对齐值也就已知了.<br />
同理,分析上面例子C：</p>
<pre>#pragma pack (2) /*指定按2字节对齐*/
struct C
{
  char b;
  int a;
  short c;
};
#pragma pack () /*取消指定对齐，恢复缺省对齐*/</pre>
<p>第一个变量b的自身对齐值为1，指定对齐值为2，所以，其有效对齐值为1，假设C从0&#215;0000开始，那么b存放在0&#215;0000，符合0&#215;0000%1= 0;第二个变量，自身对齐值为4，指定对齐值为2，所以有效对齐值为2，所以顺序存放在0&#215;0002、0&#215;0003、0&#215;0004、0&#215;0005四个连续字节中，符合0&#215;0002%2=0。第三个变量c的自身对齐值为2，所以有效对齐值为2，顺序存放<br />
在0&#215;0006、0&#215;0007中，符合 0&#215;0006%2=0。所以从0&#215;0000到0&#215;00007共八字节存放的是C的变量。又C的自身对齐值为4，所以C的有效对齐值为2。又8%2=0,C 只占用0&#215;0000到0&#215;0007的八个字节。所以sizeof(struct C)=8.</p>
<p>四.如何修改编译器的默认对齐值?</p>
<p>1.在VC IDE中，可以这样修改：[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改，默认是8字节。<br />
2.在编码时，可以这样动态修改：#pragma pack .注意:是pragma而不是progma.</p>
<p>五.针对字节对齐,我们在编程中如何考虑?</p>
<p>如果在编程的时候要考虑节约空间的话,那么我们只需要假定结构的首地址是0,然后各个变量按照上面的原则进行排列即可,基本的原则就是把结构中的变量按照类型大小从小到大声明,尽量减少中间的填补空间.还有一种就是为了以空间换取时间的效率,我们显示的进行填补空间进行对齐,比如:有一种使用空间换时间做法是显式的插入reserved成员：</p>
<pre>struct A{
  char a;
  char reserved[3];//使用空间换时间
  int b;
};</pre>
<p>reserved成员对我们的程序没有什么意义,它只是起到填补空间以达到字节对齐的目的,当然即使不加这个成员通常编译器也会给我们自动填补对齐,我们自己加上它只是起到显式的提醒作用.</p>
<p>六.字节对齐可能带来的隐患:</p>
<p>代码中关于对齐的隐患，很多是隐式的。比如在强制类型转换的时候。例如：<br />
unsigned int i = 0&#215;12345678;<br />
unsigned char *p=NULL;<br />
unsigned short *p1=NULL;</p>
<p>p=&amp;i;<br />
*p=0&#215;00;<br />
p1=(unsigned short *)(p+1);<br />
*p1=0&#215;0000;<br />
最后两句代码，从奇数边界去访问unsignedshort型变量，显然不符合对齐的规定。<br />
在x86上，类似的操作只会影响效率，但是在MIPS或者sparc上，可能就是一个error,因为它们要求必须字节对齐.<br />
七.如何查找与字节对齐方面的问题:</p>
<p>如果出现对齐或者赋值问题首先查看<br />
1. 编译器的big little端设置<br />
2. 看这种体系本身是否支持非对齐访问<br />
3. 如果支持看设置了对齐与否,如果没有则看访问时需要加某些特殊的修饰来标志其特殊访问操作。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/c-byte-alignment/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux关机与重启命令详解</title>
		<link>http://www.linuxsong.org/2010/09/linux-restart-shutdown/</link>
		<comments>http://www.linuxsong.org/2010/09/linux-restart-shutdown/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:23:00 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=153</guid>
		<description><![CDATA[Linux下的关机与重启的命令有多种，每种方式略有些不同，除非有特别紧急的情况发生，否则不要通过直接关闭电源来关机，这可能会导致数据丢失。 <a href="http://www.linuxsong.org/2010/09/linux-restart-shutdown/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.linuxsong.org/category/linux/">Linux</a>下的关机与重启的命令有多种，每种方式略有些不同，除非有特别紧急的情况发生，否则不要通过直接关闭电源来关机，这可能会导致数据丢失。</p>
<p>1. shutdown:妥善的停机方式</p>
<p>shutdown 是关机或重启系统最安全的方式。<br />
shutdown可以在指定时间关机（定时关机），也可以让shutdown 在开始关闭系统之前等待一段时间，在等待过程中，shutdown 以越来越短的时间间隔发送一些消息给已登录的用户，警告用户，系统将要关闭，可以让用户在系统关闭之前做好相应的准备工作，防止发生数据丢失。管理员也可以提供一个简短的说明，比如：更换设备，10：00恢复。</p>
<p>下面看一下shutdown的详细参数：<br />
shutdown [OPTION]... TIME [MESSAGE]</p>
<p><span id="more-153"></span>[-r] 重启计算器。<br />
[-k] 并不真正关机﹐只是送警告信号给每位登录者<br />
[-h] 关机后关闭电源。<br />
[-c] 取消目前正在执行的关机程序，可以给当前登录的用户一个提示信息<br />
[-F] 在重启系统时执行磁盘检查 （fsck）<br />
[-f] 在重启系统时不检查磁盘<br />
比如要在 10：00关闭系统，并给登录用户一条提示信息：<br />
$ shutdown -h 10:00 &quot;系统维护10:00关机，11:00恢复&quot;</p>
<p>比如要在15分钟后重启计算机：<br />
$ shutdown -r +15</p>
<p>2. halt 更简单的关机方式</p>
<p>halt命令执行关闭系统所需要的基本任。它可以被shutdown -h调用，也可以单独使用。halt记录关机的情况，终止百必须的进程，执行sync系统调用，等待文件系统写操作完成，然后停止内核。</p>
<p>halt -n 不执行sync调用。在fsck修复了根分区之后会用到这条命令。如果fsck没用使用-n选项，那么内核可能会用内存中组成上的超级块的老版本覆盖fsck的修改。</p>
<p>3. telinit 改变init的运行级别</p>
<p>使用telnit可以指引init进入指定的运行级别。如要让系统进入单用户模式：<br />
$ telinit 1</p>
<p>4. reboot 快速重启系统</p>
<p>reboot基本和halt一样，只不过它是让系统重新启动，而halt是让机器关机。reboot由shutdown -r来调用。与halt类似，它也支持-n参数。</p>
<p>5. poweroff 让Linux关闭电源</p>
<p>poweroff命令基本和halt一样，区别在于Linux关闭后，poweroffer可以向电源管理系统（如果有的话）发送一则请求来关闭系统主电源。主要用于远程关机。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linuxsong.org/2010/09/linux-restart-shutdown/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unix哲学</title>
		<link>http://www.linuxsong.org/2010/09/unix-philosophy/</link>
		<comments>http://www.linuxsong.org/2010/09/unix-philosophy/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 17:20:25 +0000</pubDate>
		<dc:creator>LinuxSong</dc:creator>
				<category><![CDATA[linux/unix]]></category>

		<guid isPermaLink="false">http://www.linuxsong.org/?p=151</guid>
		<description><![CDATA[Unix哲学起源于Ken Thompson早期关于如何设计一个服务接口简洁、小巧精干的操作系统的思考，随着Unix文化在学习如何尽可能发掘Thompson设计思想的过程中不断成长，同时一路上还从其它许多地方博采众长。 <a href="http://www.linuxsong.org/2010/09/unix-philosophy/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Unix哲学起源于Ken Thompson早期关于如何设计一个服务接口简洁、小巧精干的操作系统的思考，随着Unix文化在学习如何尽可能发掘Thompson设计思想的过程中不断成长，同时一路上还从其它许多地方博采众长。</p>
<p>Unix哲学说来不算是一种正规设计方法。它并不打算从计算机科学的理论高度来产生理论上完美的软件。那些毫无动力、松松垮垮而且薪水微薄的程序员们，能在短短期限内，如同神灵附体般造出稳定而新颖的软件——这只不过是经理人永远的梦呓罢了。</p>
<p>Unix哲学（同其它工程领域的民间传统一样）是自下而上的，而不是自上而下的。Unix哲学注重实效，立足于丰富的经验。你不会在正规方法学和标准中找到它，它更接近于隐性的半本能的知识，即Unix文化所传播的专业经验。它鼓励那种分清轻重缓急的感觉，以及怀疑一切的态度，并鼓励你以幽默达观的态度对待这些。</p>
<p>Unix管道的发明人、Unix传统的奠基人之一Doug McIlroy在[McIlroy78]中曾经说过：</p>
<p>（i）让每个程序就做好一件事。如果有新任务，就重新开始，不要往原程序中加入新功能而搞得复杂。</p>
<p>（ii）假定每个程序的输出都会成为另一个程序的输入，哪怕那个程序还是未知的。输出中不要有无关的信息干扰。避免使用严格的分栏格式和二进制格式输入。不要坚持使用交互式输入。</p>
<p>（ⅲ）尽可能早地将设计和编译的软件投入试用, 哪怕是操作系统也不例外，理想情况下, 应该是在几星期内。对拙劣的代码别犹豫，扔掉重写。</p>
<p>（iv）优先使用工具而不是拙劣的帮助来减轻编程任务的负担。工欲善其事，必先利其器。</p>
<p>后来他这样总结道（引自《Unix的四分之一世纪》（A Quarter Century of Unix [Salus]））：</p>
<p><span id="more-151"></span>Unix哲学是这样的：一个程序只做一件事，并做好。程序要能协作。程序要能处理文本流，因为这是最通用的接口。</p>
<p>Rob Pike, 最伟大的C语言大师之一, 在《Notes on C Programming》中从另一个稍微不同的角度表述了Unix的哲学[Pike]：</p>
<p>原则1：你无法断定程序会在什么地方耗费运行时间。瓶颈经常出现在想不到的地方，所以别急于胡乱找个地方改代码，除非你已经证实那儿就是瓶颈所在。</p>
<p>原则2：估量。在你没对代码进行估量，特别是没找到最耗时的那部分之前，别去优化速度。</p>
<p>原则3：花哨的算法在n很小时通常很慢，而n通常很小。花哨算法的常数复杂度很大。除非你确定n总是很大，否则不要用花哨算法（即使n很大，也优先考虑原则2）。</p>
<p>原则4：花哨的算法比简单算法更容易出bug、更难实现。尽量使用简单的算法配合简单的数据结构。</p>
<p>原则5：数据压倒一切。如果已经选择了正确的数据结构并且把一切都组织得井井有条，正确的算法也就不言自明。编程的核心是数据结构，而不是算法。</p>
<p>原则6：没有原则6。</p>
<p>Ken Thompson——Unix最初版本的设计者和实现者，禅宗偈语般地对Pike的原则4作了强调：</p>
<p>拿不准就穷举。</p>
<p>Unix哲学中更多的内容不是这些先哲们口头表述出来的，而是由他们所作的一切和Unix本身所作出的榜样体现出来的。从整体上来说，可以概括为以下几点：</p>
<p>1. 模块原则：使用简洁的接口拼合简单的部件。</p>
<p>2. 清晰原则：清晰胜于机巧。</p>
<p>3. 组合原则：设计时考虑拼接组合。</p>
<p>4. 分离原则：策略同机制分离，接口同引擎分离。</p>
<p>5. 简洁原则：设计要简洁，复杂度能低则低。</p>
<p>6. 吝啬原则：除非确无它法，不要编写庞大的程序。</p>
<p>7. 透明性原则：设计要可见，以便审查和调试。</p>
<p>8. 健壮原则：健壮源于透明与简洁。</p>
<p>9. 表示原则：把知识叠入数据以求逻辑质朴而健壮。</p>
<p>10. 通俗原则：接口设计避免标新立异。</p>
<p>11. 缄默原则：如果一个程序没什么好说的，就沉默。</p>
<p>12. 补救原则：出现异常时，马上退出并给出足够错误信息。</p>
<p>13. 经济原则：宁花机器一分，不花程序员一秒。</p>
<p>14. 生成原则：避免手工hack，尽量编写程序去生成程序。</p>
<p>15. 优化原则：雕琢前先要有原型，跑之前先学会走。</p>
<p>16. 多样原则：决不相信所谓“不二法门”的断言。</p>
<p>17. 扩展原则：设计着眼未来，未来总比预想来得快。</p>
<p>如果刚开始接触Unix，这些原则值得好好体味一番。谈软件工程的文章常常会推荐大部分的这些原则，但是大多数其它操作系统缺乏恰当的工具和传统将这些准则付诸实践，所以，多数的程序员还不能自始至终地贯彻这些原则。蹩脚的工具、糟糕的设计、过度的劳作和臃肿的代码对他们已经是家常便饭了；他们奇怪，Unix的玩家有什么好烦的呢。</p>
<p>1.6.1 模块原则：使用简洁的接口拼合简单的部件</p>
<p>正如Brian Kernighan曾经说过的：“计算机编程的本质就是控制复杂度”[Kernighan-Plauger]。排错占用了大部分的开发时间，弄出一个拿得出手的可用系统，通常与其说出自才华横溢的设计成果，还不如说是跌跌撞撞的结果。</p>
<p>汇编语言、编译语言、流程图、过程化编程、结构化编程、所谓的人工智能、第四代编程语言、面向对象、以及软件开发的方法论，不计其数的解决之道被抛售者吹得神乎其神。但实际上这些都用处不大，原因恰恰在于它们“成功”地将程序的复杂度提升到了人脑几乎不能处理的地步。就像Fred Brooks的一句名言[Brooks]：没有万能药。</p>
<p>要编制复杂软件而又不至于一败涂地的唯一方法就是降低其整体复杂度——用清晰的接口把若干简单的模块组合成一个复杂软件。如此一来，多数问题只会局限于某个局部，那么就还有希望对局部进行改进而不至牵动全身。</p>
<p>1.6.2 清晰原则: 清晰胜于机巧</p>
<p>维护如此重要而成本如此高昂；在写程序时，要想到你不是写给执行代码的计算机看的，而是给人——将来阅读维护源码的人，包括你自己——看的。</p>
<p>在Unix传统中，这个建议不仅意味着代码注释。良好的Unix实践同样信奉在选择</p>
<p>算法和实现时就应该考虑到将来的可扩展性。而为了取得程序一丁点的性能提升就大幅度增加技术的复杂性和晦涩性，这个买卖做不得——这不仅仅是因为复杂的代码容易滋生bug，也因为它会使日后的阅读和维护工作更加艰难。</p>
<p>相反，优雅而清晰的代码不仅不容易崩溃——而且更易于让后来的修改者立刻理解。这点非常重要，尤其是说不定若干年后回过头来修改这些代码的人可能恰恰就是你自己。</p>
<p>永远不要去吃力地解读一段晦涩的代码三次。第一次也许侥幸成功，但如果发现必须重新解读一遍——离第一次太久了，具体细节无从回想——那么你该注释代码了，这样第三次就相对不会那么痛苦了。</p>
<p>—Henry Spencer</p>
<p>1.6.3 组合原则：设计时考虑拼接组合</p>
<p>如果程序彼此之间不能有效通信，那么软件就难免会陷入复杂度的泥淖。</p>
<p>在输入输出方面，Unix传统极力提倡采用简单、文本化、面向流、设备无关的格式。在经典的Unix下，多数程序都尽可能采用简单过滤器的形式，即将一个输入的简单文本流处理为一个简单的文本流输出。</p>
<p>抛开世俗眼光，Unix程序员偏爱这种做法并不是因为他们仇视图形用户界面，而是因为如果程序不采用简单的文本输入输出流，它们就极难衔接。</p>
<p>Unix中，文本流之于工具，就如同在面向对象环境中的消息之于对象。文本流界面的简洁性加强了工具的封装性。而许多精致的进程间通讯方法，比如远程过程调用，都存在牵扯过多各程序间内部状态的倾向。</p>
<p>要想让程序具有组合性，就要使程序彼此独立。在文本流这一端的程序应该尽可能不要考虑文本流另一端的程序。将一端的程序替换为另一个截然不同的程序，而完全不惊扰另一端应该很容易做到。</p>
<p>GUI可以是个好东西。有时竭尽所能也不可避免复杂的二进制数据格式。但是，在做一个GUI前，最好还是应该想想可不可以把复杂的交互程序跟干粗活的算法程序分离开，每个部分单独成为一块，然后用一个简单的命令流或者是应用协议将其组合在一起。</p>
<p>在构思精巧的数据传输格式前，有必要实地考察一下，是否能利用简单的文本数据格式；以一点点格式解析的代价，换得可以使用通用工具来构造或解读数据流的好处是值得的。</p>
<p>当程序无法自然地使用序列化、协议形式的接口时，正确的Unix设计至少是，把尽可能多的编程元素组织为一套定义良好的API。这样，至少你可以通过链接调用应用程序，或者可以根据不同任务的需求粘合使用不同的接口。</p>
<p>（我们将在第7章详细讨论这些问题。）</p>
<p>1.6.4 分离原则: 策略同机制分离，接口同引擎分离</p>
<p>在Unix之失的讨论中，我们谈到过X系统的设计者在设计中的基本抉择是实行“机制，而不是策略”这种做法——使X成为一个通用图形引擎，而将用户界面风格留给工具包或者系统的其它层次来决定。这一点得以证明是正确的，因为策略和机制是按照不同的时间尺度变化的，策略的变化要远远快于机制。GUI工具包的观感时尚来去匆匆，而光栅操作和组合却是永恒的。</p>
<p>所以，把策略同机制揉成一团有两个负面影响：一来会使策略变得死板，难以适应用户需求的改变，二来也意味着任何策略的改变都极有可能动摇机制。</p>
<p>相反，将两者剥离，就有可能在探索新策略的时候不足以打破机制。另外，我们也可以更容易为机制写出较好的测试（因为策略太短命，不值得花太多精力在这上面）。</p>
<p>这条设计准则在GUI环境之外也被广泛应用。总而言之，这条准则告诉我们应该设法将接口和引擎剥离开来。</p>
<p>实现这种剥离的一个方法是，比如，将应用按照一个库来编写，这个库包含许多由内嵌脚本语言驱动的C服务程序，而至于整个应用的控制流程则用脚本来撰写而不是用C语言。这种模式的经典例子就是Emacs编辑器，它使用内嵌的脚本语言Lisp解释器来控制用C编写的编辑原语操作。我们会在第11章讨论这种设计风格。</p>
<p>另一个方法是将应用程序分成可以协作的前端和后端进程，通过套接字上层的专用应用协议进行通讯；我们会在第5章和第7章讨论这种设计。前端实现策略，后端实现</p>
<p>机制。比起仅用单个进程的整体实现方式来说，这种双端设计方式大大降低了整体复杂度，bug有望减少，从而降低程序的寿命周期成本。</p>
<p>1.6.5 简洁原则：设计要简洁，复杂度能低则低</p>
<p>来自多方面的压力常常会让程序变得复杂（由此代价更高，bug更多），其中一种压力就是来自技术上的虚荣心理。程序员们都很聪明，常常以能玩转复杂东西和耍弄抽象概念的能力为傲，这一点也无可厚非。但正因如此，他们常常会与同行们比试，看看谁能够鼓捣出最错综复杂的美妙事物。正如我们经常所见，他们的设计能力大大超出他们的实现和排错能力，结果便是代价高昂的废品。</p>
<p>“错综复杂的美妙事物”听来自相矛盾。Unix程序员相互比的是谁能够做到“简洁而漂亮”并以此为荣，这一点虽然只是隐含在这些规则之中，但还是很值得公开提出来强调一下。</p>
<p>—Doug McIlroy</p>
<p>更为常见的是(至少在商业软件领域里)，过度的复杂性往往来自于项目的要求，而这些要求常常基于当月的推销热点，而不是基于顾客的需求和软件实际能够提供的功能。许多优秀的设计被市场推销所需要的大堆大堆“特性清单”扼杀——实际上，这些特性功能几乎从未用过。然后，恶性循环开始了：比别人花哨的方法就是把自己变得更花哨。很快，庞大臃肿变成了业界标准，每个人都在使用臃肿不堪、bug极多的软件，连软件开发人员也不敢敝帚自珍。</p>
<p>无论以上哪种方式，最后每个人都是失败者。</p>
<p>要避免这些陷阱，唯一的方法就是鼓励另一种软件文化，以简洁为美，人人对庞大复杂的东西群起而攻之——这是一个非常看重简单解决方案的工程传统，总是设法将程序系统分解为几个能够协作的小部分，并本能地抵制任何用过多噱头来粉饰程序的企图。</p>
<p>这就有点Unix文化的意味了。</p>
<p>1.6.6 吝啬原则: 除非确无它法，不要编写庞大的程序</p>
<p>“大”有两重含义：体积大，复杂程度高。程序大了，维护起来就困难。由于人们对花费了大量精力才做出来的东西难以割舍，结果导致在庞大的程序中把投资浪费在注定要失败或者并非最佳的方案上。</p>
<p>（我们会在第13章就软件的最佳大小进行更多的详细讨论。）</p>
<p>1.6.7 透明性原则：设计要可见，以便审查和调试</p>
<p>因为调试通常会占用四分之三甚至更多的开发时间，所以一开始就多做点工作以减少日后调试的工作量会很划算。一个特别有效的减少调试工作量的方法就是设计时充分考虑透明性和显见性。</p>
<p>软件系统的透明性是指你一眼就能够看出软件是在做什么以及怎样做的。显见性指程序带有监视和显示内部状态的功能，这样程序不仅能够运行良好，而且还可以看得出它以何种方式运行。</p>
<p>设计时如果充分考虑到这些要求会给整个项目全过程都带来好处。至少，调试选项的设置应该尽量不要在事后，而应该在设计之初便考虑进去。这是考虑到程序不但应该能够展示其正确性，也应该能够把原开发者解决问题的思维模型告诉后来者。</p>
<p>程序如果要展示其正确性，应该使用足够简单的输入输出格式，这样才能保证很容易地检验有效输入和正确输出之间的关系是否正确。</p>
<p>出于充分考虑透明性和显见性的目的，还应该提倡接口简洁，以方便其它程序对其进行操作——尤其是测试监视工具和调试脚本。</p>
<p>1.6.8 健壮原则: 健壮源于透明与简洁</p>
<p>软件的健壮性指软件不仅能在正常情况下运行良好，而且在超出设计者设想的意外条件下也能够运行良好。</p>
<p>大多数软件禁不起磕碰，毛病很多，就是因为过于复杂，很难通盘考虑。如果不能够正确理解一个程序的逻辑，就不能确信其是否正确，也就不能在出错的时候修复它。</p>
<p>这也就带来了让程序健壮的方法，就是让程序的内部逻辑更易于理解。要做到这一点主要有两种方法：透明化和简洁化。</p>
<p>就健壮性而言，设计时要考虑到能承受极端大量的输入，这一点也很重要。这时牢记组合原则会很有益处；经不起其它一些程序产生的输入（例如，原始的Unix C编译器据说需要一些小小的升级才能处理好Yacc的输出）。当然，这其中涉及的一些形式对人类来说往往看起来没什么实际用处。比如，接受空的列表/字符串等等，即使在人们很少或者根本就不提供空字符串的地方也得如此，这可以避免在用机器生成输入时需要对这种情况进行特殊处理。</p>
<p>—Henry Spencer</p>
<p>在有异常输入的情况下，保证软件健壮性的一个相当重要的策略就是避免在代码中出现特例。bug通常隐藏在处理特例的代码以及处理不同特殊情况的交互操作部分的代码中。</p>
<p>上面我们曾说过，软件的透明性就是指一眼就能够看出来是怎么回事。如果“怎么回事”不算复杂，即人们不需要绞尽脑汁就能够推断出所有可能的情况，那么这个程序就是简洁的。程序越简洁，越透明，也就越健壮.</p>
<p>模块性（代码简朴，接口简洁）是组织程序以达到更简洁目的的一个方法。另外也有其它的方法可以得到简洁。接下来就是另一个。</p>
<p>1.6.9 表示原则: 把知识叠入数据以求逻辑质朴而健壮</p>
<p>即使最简单的程序逻辑让人类来验证也很困难，但是就算是很复杂的数据，对人类来说，还是相对容易地就能够推导和建模的。不信可以试试比较一下，是五十个节点的指针树，还是五十行代码的流程图更清楚明了；或者，比较一下究竟用一个数组初始化器来表示转换表，还是用switch语句更清楚明了呢？可以看出，不同的方式在透明性和清晰性方面具有非常显著的差别。参见Rob Pike的原则5。</p>
<p>数据要比编程逻辑更容易驾驭。所以接下来，如果要在复杂数据和复杂代码中选择一个，宁愿选择前者。更进一步：在设计中，你应该主动将代码的复杂度转移到数据之中去。</p>
<p>此种考量并非Unix社区的原创，但是许多Unix代码都显示受其影响。特别是C语言对指针使用控制的功能，促进了在内核以上各个编码层面上对动态修改引用结构。在</p>
<p>结构中用非常简单的指针操作就能够完成的任务，在其它语言中，往往不得不用更复杂的过程才能完成。</p>
<p>（我们将在第9章再讨论这些技术。）</p>
<p>1.6.10 通俗原则：接口设计避免标新立异</p>
<p>（也就是众所周知的“最少惊奇原则”。）</p>
<p>最易用的程序就是用户需要学习新东西最少的程序——或者，换句话说，最易用的程序就是最切合用户已有知识的程序。</p>
<p>因此，接口设计应该避免毫无来由的标新立异和自作聪明。如果你编制一个计算器程序，‘＋’应该永远表示加法。而设计接口的时候，尽量按照用户最可能熟悉的同样功能接口和相似应用程序来进行建模。</p>
<p>关注目标受众。他们也许是最终用户，也许是其他程序员，也许是系统管理员。对于这些不同的人群，最少惊奇的意义也不同。</p>
<p>关注传统惯例。Unix世界形成了一套系统的惯例，比如配置和运行控制文件的格式，命令行开关等等。这些惯例的存在有个极好的理由：缓和学习曲线。应该学会并使用这些惯例。</p>
<p>（我们将在第5章和第10章讨论这些传统惯例。）</p>
<p>最小立异原则的另一面是避免表象相似而实际却略有不同。这会极端危险，因为表象相似往往导致人们产生错误的假定。所以最好让不同事物有明显区别，而不要看起来几乎一模一样。</p>
<p>—Henry Spencer</p>
<p>1.6.11 缄默原则：如果一个程序没什么好说的，就保持沉默</p>
<p>Unix中最古老最持久的设计原则之一就是：若程序没有什么特别之处可讲，就保持沉默。行为良好的程序应该默默工作，决不唠唠叨叨，碍手碍脚。沉默是金。</p>
<p>“沉默是金”这个原则的起始是源于Unix诞生时还没有视频显示器。在1969年的缓慢的打印终端，每一行多余的输出都会严重消耗用户的宝贵时间。现在，这种情况已不复存在，一切从简的这个优良传统流传至今。</p>
<p>我认为简洁是Unix程序的核心风格。一旦程序的输出成为另一个程序的输入，就很容易把需要的数据挑出来。站在人的角度上来说――重要信息不应该混杂在冗长的程序内部行为信息中。如果显示的信息都是重要的，那就不用找了。</p>
<p>—Ken Arnold</p>
<p>设计良好的程序将用户的注意力视为有限的宝贵资源，只有在必要时才要求使用。</p>
<p>（我们将在第11章末尾进一步讨论缄默原则及其理由。）</p>
<p>1.6.12 补救原则: 出现异常时，马上退出并给出足量错误信息</p>
<p>软件在发生错误的时候也应该与在正常操作的情况下一样，有透明的逻辑。最理想的情况当然是软件能够适应和应付非正常操作；而如果补救措施明明没有成功，却悄无声息地埋下崩溃的隐患，直到很久以后才显现出来，这就是最坏的一种情况。</p>
<p>因此，软件要尽可能从容地应付各种错误输入和自身的运行错误。但是，如果做不到这一点，就让程序尽可能以一种容易诊断错误的方式终止。</p>
<p>同时也请注意Postel的规定[8]：“宽容地收，谨慎地发”。Postel谈的是网络服务程序，但是其含义可以广为适用。就算输入的数据很不规范，一个设计良好的程序也会尽量领会其中的意义，以尽量与别的程序协作；然后，要么响亮地倒塌，要么为工作链下一环的程序输出一个严谨干净正确的数据。</p>
<p>然而，也请注意这条警告：</p>
<p>最初HTML文档推荐“宽容地接受数据”，结果因为每一种浏览器都只接受规范中一个不同的超集，使我们一直倍感无奈。要宽容的应该是规范而不是它们的解释工具。</p>
<p>—Doug McIlroy</p>
<p>McIlroy 要求我们在设计时要考虑宽容性，而不是用过分纵容的实现来补救标准的不足。否则，正如他所指出的一样，一不留神你会死得很难看。</p>
<p>1.6.13 经济原则: 宁花机器一分，不花程序员一秒</p>
<p>在Unix早期的小型机时代，这一条观点还是相当激进的（那时机器要比现在慢得多也贵得多）。如今，随着技术的发展，开发公司和大多数用户（那些需要对核爆炸进行建模或处理三维电影动画的除外）都能够得到廉价的机器，所以这一准则的合理性就显然不用多说啦！</p>
<p>但不知何故，实践似乎还没完全跟上现实的步伐。如果我们在整个软件开发中很严格的遵循这条原则的话，大多数的应用场合都应该使用高一级的语言，如Perl、Tcl、Python、Java、Lisp，甚至<a href="http://www.linuxsong.org/category/shell/">shell</a>——这些语言可以将程序员从自行管理
