<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
 <channel>
  <title>panbird's blog</title>
  <link>http://panbird.blogbus.com</link>
  <description><![CDATA[妙文偶得，blog之，不亦乐乎；]]></description>
  <generator> by blogbus.com </generator>
  <lastBuildDate>Thu, 01 Jan 1970 07:00:00 +0700</lastBuildDate>
  <image>
									<url>http://public.blogbus.com/profile/5/4/2/1006245/avatar_1006245_96.jpg</url>
									<title>panbird's blog</title>
									<link>http://panbird.blogbus.com</link>
								</image>  <item>
   <title>程序员创业三关</title>
   <description><![CDATA[<p>当人们还在浩叹第一次网络泡沫破灭的时候，互联网已经悄悄迎来了它的第二个春天；从某种意义上看，甚至已经进入了夏天——热烈但不乏浮躁、兴奋但失之肤浅。某位投资人声称今年总共有三十亿美金资本进入中国，言下之意，大家都可以甩开膀子大干快上，登陆纳市不好说，搞笔钱进来花差花差多半是没问题的。</p><p>另一方面，程序员创业，在中国乃至国外，都不是什么新鲜事儿。我们是那么一群聪明、优秀的家伙，大脑发达，点子就像啤酒的泡沫，扑腾扑腾直往外冒，天生我才，有什么做不到的呢？遥想比尔盖茨当年，西装革履，谈笑间，多少豪杰灰飞烟灭……</p><p>于是我看到，无数公司成立了，眼看他雄心勃勃，眼看他一败涂地。成败固然不足以论英雄，然而英雄却不得不面对可能的成败。可惜的是，程序员朋友们在创业的时候，往往没有做好充分准备。据一些资料显示，百分之七十五的新创公司，会在两、三年内倒闭。笔者也曾经见过许多程序员创业失败的个案；成功或不成功，有很多因素制约；对于立志创业的程序员，至少应该突破三关。</p><p>第一是模式关。你的创业计划，也许起源于灵机一动。可惜的是，好点子并不能保证你创业成功。我相信多数程序员的点子，尚不至于低级到靠软色情、盗版、恶性SEO等等下作手段去骗取广告费的地步，但怎么从点子变成盈利模式，却是让很多创业者迷惑的事情。在一些业界聚会上，总听到类似“只要有流量，总有办法赚钱”之类的说法，在2000年持同样言论的创业者，多数已经成为失败的先烈，因为他们始终没明白，赚现钱的生意才是好生意。三大门户成功的要点，在于他们想出办法，把流量转化为盈利模式。缺乏有效的模式，流量只是成本。确定有效经营模式、组建有力创业团队，是首要任务。</p><p>第二是管理关。从程序员变成管理者，是艰难的过程。你得明白两件事：一、管理和写程序一样，是门科学；二、人和计算机不一样，人有感情、会出错。协调沟通能力，是程序员创业必备的素质。曾经眼见一些项目经理，和手下技术人员通过邮件争辩不休，甚至发展到在Blog上互相嘲讽，这样的管理，可谓彻底失败。另一个极端是，和手下称兄道弟、一团和气，工作被感情所左右，酒肉害了朋友。管理有那么难吗？我看未必。只做对公司有利的事，就是根本原则。在和你的手下打交道时，请三思：我这么做，对公司有好处吗？对事业有好处吗？如果答案是否定的，那你需要另一个解决方案。</p><p>第三是坚持关。一位多次创业不成功的朋友告诉我，他总结了一条“三年定律”，即任何事如果不能坚持三年，则一定失败。诚哉斯言！另一位朋友说，中国人相信机会，西方人相信方向和时间，虽有些偏激，却也不乏道理。许多程序员都属于思维活跃、点子特多的一类人，当有新鲜的想法出来时，他们倾向于放弃或冷落手上正在执行的计划。点子复点子，点子何其多，每天新点子，万事成蹉跎。西谚有云，双鸟在林不如一鸟在手；吃到嘴里的鸭子才是好鸭子，湖里那只鸭子看起来比较肥？也许吧，不过，吃了这只鸭子再去涉水抓那只，是不是更有把握呢？</p><p>文短意深，未尽之处不及一一道来。奉上忠言数句，与程序员朋友们共勉：你永远不是最聪明的人；手下比你强是好事；创业不怕起步晚，只怕起个不停。</p><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/1902017.html">《Squid 中文权威指南》第3章</a> 2006-02-09</div><div><a href="/logs/1750121.html">留言版留言自动折行问题</a> 2005-12-26</div><div><a href="/logs/1711786.html">常用注册表修改</a> 2005-12-16</div><div><a href="/logs/1561297.html">MBTI 测试报告</a> 2005-11-03</div><div><a href="/logs/1538946.html">Apache2 httpd.conf 中文版</a> 2005-10-26</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F2471201.html&title=%E7%A8%8B%E5%BA%8F%E5%91%98%E5%88%9B%E4%B8%9A%E4%B8%89%E5%85%B3">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://pindao.blogbus.com/shenghuo?utm_source=blogbus&utm_medium=rss&utm_campaign=shenghuo" target="_blank">生活频道——笑谈生活，坐看人生，这里有着小人物的健康生活。</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/2471201.html</link>
   <author>panbird</author>
   <pubDate>Sun, 14 May 2006 22:45:27 +0800</pubDate>
  </item>
  <item>
   <title>从LiveJournal后台发展看大规模网站性能优化方法</title>
   <description><![CDATA[<h2>一、LiveJournal发展历程</h2><a href="http://www.livejournal.com/">LiveJournal</a>是99年始于校园中的项目，几个人出于爱好做了这样一个应用，以实现以下功能： <ul><li>博客，论坛 </li><li>社会性网络，找到朋友 </li><li>聚合，把朋友的文章聚合在一起</li></ul>LiveJournal采用了大量的开源软件，甚至它本身也是一个开源软件。 <p>在上线后，LiveJournal实现了非常快速的增长：</p><ul><li>2004年4月份：280万注册用户。 </li><li>2005年4月份：680万注册用户。 </li><li>2005年8月份：790万注册用户。 </li><li>达到了每秒钟上千次的页面请求及处理。 </li><li>使用了大量MySQL服务器。 </li><li>使用了大量通用组件。</li></ul><h2>二、LiveJournal架构现状概况</h2><p><img height="445" alt="livejournal_backend.png" src="http://www.example.net.cn/archives/livejournal_backend.png" width="600" /><br /><br /></p><h2>三、从LiveJournal发展中学习</h2><p /><p>LiveJournal从1台服务器发展到100台服务器，这其中经历了无数的伤痛，但同时也摸索出了解决这些问题的方法，通过对LiveJournal的学习，可以让我们避免LJ曾经犯过的错误，并且从一开始就对系统进行良好的设计，以避免后期的痛苦。</p><p>下面我们一步一步看LJ发展的脚步。</p><div id="a000073more"><div id="more"><h2>1、一台服务器</h2><p>一台别人捐助的服务器，LJ最初就跑在上面，就像Google开始时候用的破服务器一样，值得我们尊敬。这个阶段，LJ的人以惊人的速度熟悉的Unix的操作管理，服务器性能出现过问题，不过还好，可以通过一些小修小改应付过去。在这个阶段里LJ把CGI升级到了FastCGI。</p><p>最终问题出现了，网站越来越慢，已经无法通过优过化来解决的地步，需要更多的服务器，这时LJ开始提供付费服务，可能是想通过这些钱来购买新的服务器，以解决当时的困境。<br />毫无疑问，当时LJ存在巨大的单点问题，所有的东西都在那台服务器的铁皮盒子里装着。</p><p><img height="187" alt="LJ-backend-7.png" src="http://www.example.net.cn/archives/LJ-backend-7.png" width="500" /></p><h2>2、两台服务器</h2><p>用付费服务赚来的钱LJ买了两台服务器：一台叫做Kenny的Dell 6U机器用于提供Web服务，一台叫做Cartman的Dell 6U服务器用于提供数据库服务。</p><p><img height="279" alt="LJ-backend-8.png" src="http://www.example.net.cn/archives/LJ-backend-8.png" width="218" /></p><p>LJ有了更大的磁盘，更多的计算资源。但同时网络结构还是非常简单，每台机器两块网卡，Cartman通过内网为Kenny提供MySQL数据库服务。<br /><br />暂时解决了负载的问题，新的问题又出现了：</p><ul><li>原来的一个单点变成了两个单点。 </li><li>没有冷备份或热备份。 </li><li>网站速度慢的问题又开始出现了，没办法，增长太快了。 </li><li>Web服务器上CPU达到上限，需要更多的Web服务器。</li></ul><h2>3、四台服务器</h2><p>又买了两台，Kyle和Stan，这次都是1U的，都用于提供Web服务。目前LJ一共有3台Web服务器和一台数据库服务器。这时需要在3台Web服务器上进行负载均横。</p><p><img height="241" alt="LJ-backend-9.png" src="http://www.example.net.cn/archives/LJ-backend-9.png" width="499" /></p><p>LJ把Kenny用于外部的网关，使用mod_backhand进行负载均横。</p><p>然后问题又出现了：</p><ul><li>单点故障。数据库和用于做网关的Web服务器都是单点，一旦任何一台机器出现问题将导致所有服务不可用。虽然用于做网关的Web服务器可以通过保持心跳同步迅速切换，但还是无法解决数据库的单点，LJ当时也没做这个。 </li><li>网站又变慢了，这次是因为IO和数据库的问题，问题是怎么往应用里面添加数据库呢？</li></ul><h2>4、五台服务器</h2><p>又买了一台数据库服务器。在两台数据库服务器上使用了数据库同步(Mysql支持的Master-Slave模式)，写操作全部针对主数据库（通过Binlog，主服务器上的写操作可以迅速同步到从服务器上），读操作在两个数据库上同时进行(也算是负载均横的一种吧)。</p><p><img height="265" alt="LJ-backend-10.png" src="http://www.example.net.cn/archives/LJ-backend-10.png" width="500" /></p><p>实现同步时要注意几个事项：</p><ul><li>读操作数据库选择算法处理，要选一个当前负载轻一点的数据库。 </li><li>在从数据库服务器上只能进行读操作 </li><li>准备好应对同步过程中的延迟，处理不好可能会导致数据库同步的中断。只需要对写操作进行判断即可，读操作不存在同步问题。</li></ul><h2>5、更多服务器</h2><p>有钱了，当然要多买些服务器。部署后快了没多久，又开始慢了。这次有更多的Web服务器，更多的数据库服务器，存在 IO与CPU争用。于是采用了BIG-IP作为负载均衡解决方案。</p><p><img height="483" alt="LJ-backend-11.png" src="http://www.example.net.cn/archives/LJ-backend-11.png" width="453" /></p><h2>6、现在我们在哪里：</h2><p><img height="357" alt="LJ-backend-1.png" src="http://www.example.net.cn/archives/LJ-backend-1.png" width="600" /></p><p>现在服务器基本上够了，但性能还是有问题，原因出在架构上。</p><p>数据库的架构是最大的问题。由于增加的数据库都是以Slave模式添加到应用内，这样唯一的好处就是将读操作分布到了多台机器，但这样带来的后果就是写操作被大量分发，每台机器都要执行，服务器越多，浪费就越大，随着写操作的增加，用于服务读操作的资源越来越少。</p><p><img height="195" alt="LJ-backend-2.png" src="http://www.example.net.cn/archives/LJ-backend-2.png" width="500" /></p><p>由一台分布到两台</p><p><img height="273" alt="LJ-backend-3.png" src="http://www.example.net.cn/archives/LJ-backend-3.png" width="500" /></p><p>最终效果</p><p>现在我们发现，我们并不需要把这些数据在如此多的服务器上都保留一份。服务器上已经做了RAID，数据库也进行了备份，这么多的备份完全是对资源的浪费，属于冗余极端过度。那为什么不把数据分布存储呢？</p><p>问题发现了，开始考虑如何解决。现在要做的就是把不同用户的数据分布到不同的服务器上进行存储，以实现数据的分布式存储，让每台机器只为相对固定的用户服务，以实现平行的架构和良好的可扩展性。</p><p>为了实现用户分组，我们需要为每一个用户分配一个组标记，用于标记此用户的数据存放在哪一组数据库服务器中。每组数据库由一个master及几个slave组成，并且slave的数量在2-3台，以实现系统资源的最合理分配，既保证数据读操作分布，又避免数据过度冗余以及同步操作对系统资源的过度消耗。</p><p><img height="324" alt="LJ-backend-4.png" src="http://www.example.net.cn/archives/LJ-backend-4.png" width="500" /></p><p>由一台（一组）中心服务器提供用户分组控制。所有用户的分组信息都存储在这台机器上，所有针对用户的操作需要先查询这台机器得到用户的组号，然后再到相应的数据库组中获取数据。</p><p>这样的用户架构与目前LJ的架构已经很相像了。</p><p>在具体的实现时需要注意几个问题：</p><ul><li>在数据库组内不要使用自增ID，以便于以后在数据库组之间迁移用户，以实现更合理的I/O，磁盘空间及负载分布。 </li><li>将userid，postid存储在全局服务器上，可以使用自增，数据库组中的相应值必须以全局服务器上的值为准。全局服务器上使用事务型数据库InnoDB。 </li><li>在数据库组之间迁移用户时要万分小心，当迁移时用户不能有写操作。</li></ul><h2>7、现在我们在哪里</h2><p><img height="365" alt="LJ-backend-5.png" src="http://www.example.net.cn/archives/LJ-backend-5.png" width="500" /></p><p>问题：</p><ul><li>一个全局主服务器，挂掉的话所有用户注册及写操作就挂掉。 </li><li>每个数据库组一个主服务器，挂掉的话这组用户的写操作就挂掉。 </li><li>数据库组从服务器挂掉的话会导致其它服务器负载过大。 </li><li>对于Master-Slave模式的单点问题，LJ采取了Master-Master模式来解决。所谓Master-Master实际上是人工实现的，并不是由MySQL直接提供的，实际上也就是两台机器同时是Master，也同时是Slave，互相同步。</li></ul><p>Master-Master实现时需要注意：</p><ul><li>一个Master出错后恢复同步，最好由服务器自动完成。 </li><li>数字分配，由于同时在两台机器上写，有些ID可能会冲突。</li></ul><p>解决方案：<br /></p><ul><li>奇偶数分配ID，一台机器上写奇数，一台机器上写偶数 </li><li>通过全局服务器进行分配(LJ采用的做法)。</li></ul><p /><p>Master-Master模式还有一种用法，这种方法与前一种相比，仍然保持两台机器的同步，但只有一台机器提供服务（读和写），在每天晚上的时候进行轮换，或者出现问题的时候进行切换。</p><h2>8、现在我们在哪里</h2><p><img height="349" alt="LJ-backend-6.png" src="http://www.example.net.cn/archives/LJ-backend-6.png" width="500" /></p><p>现在插播一条广告，MyISAM VS InnoDB。</p><p>使用InnoDB：</p><ul><li>支持事务 </li><li>需要做更多的配置，不过值得，可以更安全的存储数据，以及得到更快的速度。</li></ul><p>使用MyISAM：</p><ul><li>记录日志（LJ用它来记网络访问日志） </li><li>存储只读静态数据，足够快。 </li><li>并发性很差，无法同时读写数据（添加数据可以） </li><li>MySQL非正常关闭或死机时会导致索引错误，需要使用myisamchk修复，而且当访问量大时出现非常频繁。</li></ul><h2>9、缓存</h2><p>去年我写过<a href="http://www.example.net.cn/archives/2006/01/eoamemcachedoea.html">一篇文章介绍memcached</a>，它就是由LJ的团队开发的一款缓存工具，以key-value的方式将数据存储到分布的内存中。LJ缓存的数据：</p><ul><li>12台独立服务器（不是捐赚的） </li><li>28个实例 </li><li>30GB总容量 </li><li>90-93%的命中率（用过squid的人可能知道，squid内存加磁盘的命中率大概在70-80%）</li></ul><p>如何建立缓存策略？</p><p>想缓存所有的东西？那是不可能的，我们只需要缓存已经或者可能导致系统瓶颈的地方，最大程度的提交系统运行效率。通过对MySQL的日志的分析我们可以找到缓存的对象。</p><p>缓存的缺点？</p><ul><li>没有完美的事物，缓存也有缺点： </li><li>增大开发量，需要针对缓存处理编写特殊的代码。 </li><li>管理难度增加，需要更多人参与系统维护。 </li><li>当然大内存也需要钱。</li></ul><h2>10、Web访问负载均衡</h2><p>在数据包级别使用BIG-IP，但BIG-IP并不知道我们内部的处理机制，无法判断由哪台服务器对这些请求进行处理。反向代理并不能很好的起到作用，不是已经够快了，就是达不到我们想要的效果。</p><p>所以，LJ又开发了<a href="http://www.danga.com/perlbal/">Perlbal</a>。特点：</p><ul><li>快，小，可管理的http web 服务器/代理 </li><li>可以在内部进行转发 </li><li>使用Perl开发 </li><li>单线程，异步，基于事件，使用epoll , kqueue </li><li>支持Console管理与http远程管理，支持动态配置加载 </li><li>多种模式：web服务器，反向代理，插件 </li><li>支持插件：GIF/PNG互换？</li></ul><h2>11、MogileFS</h2><p>LJ使用开源的<a href="http://www.danga.com/mogilefs/">MogileFS</a>作为分布式文件存储系统。MogileFS使用非常简单，它的主要设计思想是：</p><ul><li>文件属于类（类是最小的复制单位） </li><li>跟踪文件存储位置 </li><li>在不同主机上存储 </li><li>使用MySQL集群统一存储分布信息 </li><li>大容易廉价磁盘</li></ul><p>到目前为止就这么多了，更多文档可以在<a href="http://www.danga.com/words/">http://www.danga.com/words/</a>找到。<a href="http://www.danga.com/">Danga.com</a>和<a href="http://www.livejournal.com/">LiveJournal.com</a>的同学们拿这个文档参加了两次MySQL Con，两次OS Con，以及众多的其它会议，无私的把他们的经验分享出来，值得我们学习。在web2.0时代快速开发得到大家越来越多的重视，但良好的设计仍是每一个应用的基础，希望web2.0们在成长为Top500网站的路上，不要因为架构阻碍了网站的发展。</p><p>参考资料：<a href="http://www.danga.com/words/2005_oscon/oscon-2005.pdf">http://www.danga.com/words/2005_oscon/oscon-2005.pdf</a></p></div></div><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2471201.html">程序员创业三关</a> 2006-05-14</div><div><a href="/logs/1902017.html">《Squid 中文权威指南》第3章</a> 2006-02-09</div><div><a href="/logs/1711786.html">常用注册表修改</a> 2005-12-16</div><div><a href="/logs/1538946.html">Apache2 httpd.conf 中文版</a> 2005-10-26</div><div><a href="/logs/1524526.html">日志文件分析工具—AWStats在IIS中的配置步骤</a> 2005-10-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F2081878.html&title=%E4%BB%8ELiveJournal%E5%90%8E%E5%8F%B0%E5%8F%91%E5%B1%95%E7%9C%8B%E5%A4%A7%E8%A7%84%E6%A8%A1%E7%BD%91%E7%AB%99%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E6%96%B9%E6%B3%95">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://pindao.blogbus.com/shenghuo?utm_source=blogbus&utm_medium=rss&utm_campaign=shenghuo" target="_blank">生活频道——笑谈生活，坐看人生，这里有着小人物的健康生活。</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/2081878.html</link>
   <author>panbird</author>
   <pubDate>Fri, 17 Mar 2006 16:18:40 +0800</pubDate>
  </item>
  <item>
   <title>Apache学习笔记</title>
   <description><![CDATA[<p>作者： 车东 Email: chedongATbigfoot.com/chedongATchedong.com</p><p>写于：2002/07 最后更新：<script language="JavaScript"></script> 06/26/2004 23:42:36</p><p>版权声明：可以任意转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明<br /><a href="http://www.chedong.com/tech/apache_install.html">http://www.chedong.com/tech/apache_install.html</a></p><p>关键词： apache install php resin mod_gzip mod_expire webalizer cronolog</p><p>内容摘要：</p><p>Apache是一个历史悠久并且功能十分强大的WEB服务器，但其丰富的功能对于一个新手来说往往不知道从何下手。我个人感觉Apache的设计充分体现了模块化设计的优势，通过在动态模块加载（DSO）模式下的安装，任何子应用模块都可以通过配置文件的简单修改进行插拔式的灵活配置。然后我们就可以从简单的静态html服务开始，一个模块一个模块的学习使用。从单纯的HTML静态服务(core)，到复杂的动态页面服务(core + php, core + resin, core + php + mod_gzip, core + resin + mod_expire)。<br /></p><p>本文主要从简化安装==&gt;性能调优==&gt;维护方便的角度，介绍了WEB服务的规划、HTTPD安装/应用模块配置、升级/维护等过程。让Apache和PHP，Resin等应用模块的独立升级，完全互不影响。</p><ol><li><a href="http://www.huihoo.org/apache/apache_install.html#scale">WEB应用容量规划</a>：根据硬件配置和WEB应用的特点进行WEB服务的规划及一些简单的估算公式； </li><li><a href="http://www.huihoo.org/apache/apache_install.html#install">Apache安装过程</a>：apache的通用的简化安装选项，方便以后的应用的模块化配置；<br />修改 HARD_SERVER_LIMIT：<br />vi /path/to/apache_src/src/include/httpd.h<br />#define HARD_SERVER_LIMIT 2560 &lt;===将原来的 HARD_SERVER_LIMIT 256 后面加个“0”<br />apache编译：<br />./configure --prefix=/home/apache --enable-shared=max --enable-module=most </li><li><a href="http://www.huihoo.org/apache/apache_install.html#module">可选应用模块/工具的安装</a>：php resin mod_gzip mod_expire及各个模块之间的配合；<br />mod_php安装：./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql<br />mod_resin安装：./configure --with-apxs=/home/apache/bin/apxs <br />mod_gzip安装：/home/apache/bin/apxs -i -a -c mod_gzip.c<br />工具：日志轮循工具cronolog安装：http://www.cronolog.org </li><li><a href="http://www.huihoo.org/apache/apache_install.html#maintain">升级/维护</a>：看看通用和模块化的安装过程如何简化了日常的升级/维护工作；<br />按照以上的方法：系统管理员和应用管理员的职责可以清楚的分开，互相独立。<br />系统安装：系统管理员的职责就是安装好一台DSO模式的Apache，然后COLON即可，<br />应用安装：由应用管理员负责具体应用所需要的模块，比如PHP Resin等，并设置httpd.conf中相关的配置。<br />系统升级：系统管理员：升级操作系统/升级Apache<br />应用升级：应用管理员：升级应用模块，PHP Resin等。 </li></ol><p><b><a name="scale">WEB应用的容量规划</a></b></p><p>Apache主要是一个内存消耗型的服务应用，我个人总结的经验公式：<br />apache_max_process_with_good_perfermance &lt; (total_hardware_memory / apache_memory_per_process ) * 2<br />apache_max_process = apache_max_process_with_good_perfermance * 1.5</p><p>为什么会有一个apache_max_process_with_good_perfermance和apache_max_process呢？原因是在低负载下系统可以使用更多的内存用于文件系统的缓存，从而进一步提高单个请求的响应速度。在高负载下，系统的单个请求响应速度会慢不少，而超过apache_max_process，系统会因为开始使用硬盘做虚拟内存交换空间而导致系统效率急剧下降。此外，同样的服务：2G内存的机器的apache_max_process一般只设置到1G内存的1.7倍，因为Apache本身会因为进程过多导致性能下降。</p><p>例子1：<br />一个apache + mod_php的服务器：一个apache进程一般需要4M内存<br />因此在一个1G内存的机器上：apache_max_process_with_good_perfermance &lt; (1g / 4m) * 2 = 500<br />apache_max_process ＝ 500 * 1.5 = 750<br />所以规划你的应用让服务尽量跑在500个进程以下以保持比较高的效率，并设置Apache的软上限在800个。</p><p>例子2：<br />一个apache + mod_resin的服务器： 一个apache进程一般需要2M内存<br />在一个2G内存的机器上： <br />apache_max_process_with_good_perfermance &lt; (2g / 2m ) * 2 = 2000<br />apache_max_process ＝ 2000 * 1.5 = 3000</p><p>以上估算都是按小文件服务估算的（一个请求一般大小在20k以下）。对于文件下载类型站点，可能还会受其他因素：比如带宽等的影响。</p><p><b><a name="install">Apache安装过程</a></b></p><p>服务器个数的硬上限HARD_SERVER_LIMIT的修改：<br />在Apache的源代码中缺省的最大进程数是256个，需要修改apache_1.3.xx/src/include/httpd.h<br />#ifndef HARD_SERVER_LIMIT<br />#ifdef WIN32<br />#define HARD_SERVER_LIMIT 1024<br />#elif defined(NETWARE)<br />#define HARD_SERVER_LIMIT 2048<br />#else<br />#define HARD_SERVER_LIMIT 2560 &lt;===将原来的HARD_SERVER_LIMIT 256 后面加个“0”<br />#endif<br />#endif</p><p>解释：<br />Apache缺省的最大用户数是256个：这个配置对于服务器内存还是256M左右的时代是一个非常好的缺省设置，但随着内存成本的急剧下降，现在大型站点的服务器内存配置一般比当时要高一个数量级不止。所以256个进程的硬限制对于一台1G内存的机器来说是太浪费了，而且Apache的软上限max_client是受限于HARD_SERVER_LIMIT的，因此如果WEB服务器内存大于256M，都应该调高Apache的HARD_SERVER_LIMIT。根据个人的经验：2560已经可以满足大部分小于2G内存的服务器的容量规划了（Apache的软上限的规划请看后面）。</p><p>Apache的编译：以下通用的编译选项能满足以后任意模块的安装<br />./configure --prefix=/another_driver/apache/ --enable-shared=max<i> </i>--enable-module=most<br />比如：<br />./configure --prefix=/home/apache/ --enable-shared=max<i> </i>--enable-module=most<br /></p><p>解释：<br />--prefix=/another_driver/apache/：建议将apache服务安装在另外一个驱动设备上的目的在于硬盘往往是一个系统使用寿命最低的设备，因此：将服务数据和系统完全分开，不仅能提高了数据的访问速度，更重要的，大大方便系统升级，应用备份和恢复过程。</p><p>--shared-module=max：使用动态加载方式载入子模块会带来5%的性能下降，但和带来的配置方便相比更本不算什么：比如模块升级方便，系统升级风险降低，安装过程标准化等</p><p>--enable-module=most：用most可以将一些不常用的module编译进来，比如后面讲到的mod_expire是就不在apache的缺省常用模块中</p><p>如果不想build so, 也可以这样:<br />./configure \<br />&quot;--with-layout=Apache&quot; \<br />&quot;--prefix=/path/to/apache&quot; \<br />&quot;--disable-module=access&quot; \<br />&quot;--disable-module=actions&quot; \<br />&quot;--disable-module=autoindex&quot; \<br />&quot;--disable-module=env&quot; \<br />&quot;--disable-module=imap&quot; \<br />&quot;--disable-module=negotiation&quot; \<br />&quot;--disable-module=setenvif&quot; \<br />&quot;--disable-module=status&quot; \<br />&quot;--disable-module=userdir&quot; \<br />&quot;--disable-module=cgi&quot; \<br />&quot;--disable-module=include&quot; \<br />&quot;--disable-module=auth&quot; \<br />&quot;--disable-module=asis&quot;</p><p>但结果会发现，这样编译对服务性能只能有微小的提高（5%左右），但却失去了以后系统升级和模块升级的灵活性，无论是模块还是Apache本身升级都必须把Apache和PHP的SOURCE加在一起重新编译。</p><p>apache的缺省配置文件一般比较大：可以使用去掉注释的方法精简一下：然后再进入具体的培植过程能让你更快的定制出你所需要的。<br />grep -v &quot;#&quot; httpd.conf.default &gt;httpd.conf</p><p>需要修改的通用项目有以下几个：</p><p>#服务端口，缺省是8080，建议将整个Apache配置调整好后再将服务端口改到正式服务的端口<br />Port 8080 =&gt; 80</p><p>#服务器名：缺省没有<br />ServerName name.example.com<br /><br />#最大服务进程数：根据服务容量预测设置<br />MaxClients 256 =&gt; 800</p><p>#缺省启动服务后的服务进程数：等服务比较平稳后，按平均负载下的httpd个数设置就可以<br />StartServers 5 =&gt; 200</p><p>不要修改：<br />以前有建议说修改：<br />MinSpareServers 5 =&gt; 100<br />MaxSpareServers 10 =&gt; 200</p><p>但从我的经验看来：缺省值已经是非常优化的了，而且让Apache自己调整子共享进程个数还是比较好的。</p><p>特别修改：<br />在solaris或一些比较容易出现内存泄露的应用上：<br />MaxRequestsPerChild 0 =&gt;3000</p><p><b><a name="module">应用模块和工具的安装</a>配置：</b></p><p>由于使用模块动态加载的模式，所以可以方便的通过简单的配置调整来把Apache定制成你需要的：最好把不常用模块全部清除（无论处于安全还是效率）。<br />比如：对于静态页面服务器：就什么其他子模块都不加载，对于PHP应用就加上PHP模块，对于JAVA应用就把Resin模块加载上。而且各种模块的插拔非常简单，这样调试过程中就可以简单的通过注释掉不需要的模块，而不用重新编译。</p><p>一般说来，可以不需要的模块包括：<br />#LoadModule env_module libexec/mod_env.so<br />#LoadModule negotiation_module libexec/mod_negotiation.so<br />#LoadModule status_module libexec/mod_status.so<br />#server side include已经过时了<br />#LoadModule includes_module libexec/mod_include.so<br />#不需要将没有缺省index文件的目录下所有文件列出<br />#LoadModule autoindex_module libexec/mod_autoindex.so<br />#尽量不使用CGI：一直是Apache安全问题最多的地方<br />#LoadModule cgi_module libexec/mod_cgi.so<br />#LoadModule asis_module libexec/mod_asis.so<br />#LoadModule imap_module libexec/mod_imap.so<br />#LoadModule action_module libexec/mod_actions.so<br />#不使用安全认证可以大大提高访问速度<br />#LoadModule access_module libexec/mod_access.so<br />#LoadModule auth_module libexec/mod_auth.so<br />#LoadModule setenvif_module libexec/mod_setenvif.so</p><p>最好保留的有：<br />#用于定制log格式<br />LoadModule config_log_module libexec/mod_log_config.so<br />#用于增加文件应用的关联<br />LoadModule mime_module libexec/mod_mime.so<br />#用于缺省index文件：index.php等<br />LoadModule dir_module libexec/mod_dir.so</p><p>可用可不用的有：<br />#比如：需要在~/username/下调试php可以将<br />LoadModule userdir_module libexec/mod_userdir.so<br />#比如：需要将以前的URL进行转向或者需要使用CGI script-alias<br />LoadModule alias_module libexec/mod_alias.so<br /></p><p>常用的模块：<br />最常用的可能就是php和JAVA应用服务器的前端，此外，从性能上讲利用mod_gzip可以减少40%左右的流量，减少机器用于传输的负载，而mod_expires可以减少10%左右的重复请求，让重复的用户对指定的页面请求结果都CACHE在本地，根本不向服务器发出请求。</p><p>建议将所有MODULE的配置都放到相应模块的配置内部：<ifmodule />some_module config </ifmodule /></p><p>PHP的安装：<br />/path/to/php_src/configure --with-apxs=/path/to/apache/bin/apxs --with-other-modules-you-need<br />需要修改的配置：<br />AddType application/x-httpd-php .php .php3 .any_file_in_php</p><p>resin的安装设置：<br />/path/to/resin/src/configure --with-apxs=/path/to/apache/bin/apxs <br /><br />具体的resin设置放在另外一个文件中：比如/home/resin/conf/resin.conf<br /><ifmodule /><br />CauchoConfigFile /path/to/apache/conf/resin.conf<br /></ifmodule /></p><p>mod_expires的安装配置：<br /><ifmodule /><br />    ExpiresActive on<br />    ExpiresByType image/gif &quot;access plus 1 month&quot;<br />    ExpiresByType text/css &quot;now plus 1 month&quot;<br />    ExpiresDefault &quot;now plus 1 day&quot;<br /></ifmodule /></p><p>注释：<br />所有的.gif文件1个月以后过期<br />所有的文件缺省1天以后过期<br /></p><p>mod_gzip的安装：<br />/path/to/apache/bin/apxs -i -a -c mod_gzip.c</p><p>配置：mod_gzip+mod_php<br />LoadModule gzip_module modules/mod_gzip.so</p><p>...<br />AddModule mod_gzip.c</p><p>...<br /><i><ifmodule /><br />mod_gzip_on Yes<br />mod_gzip_minimum_file_size 1000<br />mod_gzip_maximum_file_size 300000 <br />mod_gzip_item_include file \.htm$<br />mod_gzip_item_include file \.html$<br />mod_gzip_item_include file \.php$<br />mod_gzip_item_include file \.php3$<br />mod_gzip_item_include mime text/.*<br />mod_gzip_item_include mime httpd/unix-directory <br />#mod_gzip的临时工作目录<br />mod_gzip_temp_dir /tmp/mod_gzip<br />mod_gzip_dechunk Yes<br />mod_gzip_keep_workfiles No<br /></ifmodule /></i></p><p><i>mod_gzip和mod_php的配合：不要让mod_gzip和mod_php使用同一个临时目录，php_session存放目录可以通过php.ini设置到session.save_path = /tmp/php_sess<br /><br />mod_gzip和Resin配合：要让mod_gzip在mod_caucho后加载，否则mod_gzip不起作用<br />...othr modules<br />AddModule mod_so.c<br />AddModule mod_caucho.c<br />#notice: mod_gzip must load after mod_caucho<br />AddModule mod_gzip.c<br />AddModule mod_expires.c<br />...</i></p><p>配置：mod_gzip + resin<br /><i><ifmodule /><br />mod_gzip_on Yes<br />mod_gzip_dechunk yes<br />mod_gzip_keep_workfiles No<br />mod_gzip_minimum_file_size 3000<br />mod_gzip_maximum_file_size 300000 <br />mod_gzip_item_include file \.html$<br />mod_gzip_item_include mime text/.*<br />mod_gzip_item_include mime httpd/unix-directory<br />mod_gzip_item_include handler 'caucho-request'<br /></ifmodule /></i></p><p>日志的轮循：cronolog的安装和设置<br />cronolog可以非常整齐的将日志按天轮循存储<br />缺省编译安装到/usr/local/bin/下，只需要将配置改成：</p><p>CustomLog &quot;|/usr/local/sbin/cronolog /home/apache/logs/%w/access_log&quot; combined<br /></p>日志将按天截断并存放在以星期为目录名的目录下：比如：log/1是周一，log/5是周五, log/0是周日<br /><br />用gzip压缩每天的日志：<br />30 4 * * * /usr/bin/gzip -f /home/apache/logs/`date -d yesterday +%w`/access_log<br /><br />日志的定期删除：<br />30 5 * * */usr/bin/find /home/apache/logs/ -name access_log.gz -mtime +3 |xargs -r /bin/rm -f<br /><p><b><a name="maintain">升级维护</a>：</b></p><p>由于使用动态模块加载方式（DSO模式)安装Apache，Apache的HTTPD核心服务和应用模块以及应用模块之间都变的非常灵活，建议将所有独立模块的配置都放在<br /><ifmodule /><br />CONFIGURATIONS..<br /></ifmodule /><br />里，这样配置非常容易通过屏蔽某个模块来进行功能调整：比如：<br />#AddModule mod_gzip.c<br />就屏蔽了mod_gzip，而其他模块不首任何影响。</p><p>安装和维护过程：</p><ul><li>系统安装：系统管理员的职责就是安装系统和一个按照DSO模式安装的Apache，然后COLON。 </li><li>应用安装：由应用管理员负责具体应用所需要的模块并设置HTTPD。 </li><li>系统升级：系统管理员：升级系统/升级Apache </li><li>应用升级：应用管理员：升级应用模块：PHP CAUCHO等 </li><li>系统备份/恢复：如果Apache不在缺省的系统盘上，只需要将Apache目录备份就可以了，遇到系统分区的硬件问题直接使用预先准备好的系统COLON，再直接将Apache所在物理盘恢复就行了。 </li></ul><table border="1"><tbody><tr><td style="TEXT-ALIGN: right">系统管理员：Apache的最简化安装</td><td align="center" colspan="3">OS + Apache (httpd core only)</td></tr><tr><td style="TEXT-ALIGN: right">应用管理员：应用模块定制</td><td>纯静态页面服务<br />core<br /></td><td>PHP动态页面<br />core+so<br />+php<br /></td><td>JAVA应用<br />core+so<br />+caucho<br />+ssl</td></tr><tr><td style="TEXT-ALIGN: right">应用例子：</td><td>www.example.com<br />image.example.com<br /></td><td>bbs.example.com</td><td>mall.example.com</td></tr></tbody></table><p>例子：Apache和PHP模块的独立升级。</p><p>如果Apache是按照以下方式安装：<br />./configure --prefix=/home/apache --enable-shared=max --enable-module=most <br />PHP是按照以下方式安装：<br />./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql<br /><br />以后单独升级Apache的时候，仍然是：<br />./configure --prefix=/home/apache --enable-shared=max --enable-module=most <br />make<br />su<br />#/home/apache/bin/apachectl stop<br />#make install<br /><br />单独升级php时，仍然是：<br />./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql<br />make<br />su<br />#/home/apache/bin/apachectl stop<br />#make install<br /><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2471201.html">程序员创业三关</a> 2006-05-14</div><div><a href="/logs/1902017.html">《Squid 中文权威指南》第3章</a> 2006-02-09</div><div><a href="/logs/1826866.html">2005岁末BLOG 系统大评点</a> 2006-01-16</div><div><a href="/logs/1771287.html">Lucene倒排索引原理</a> 2005-12-31</div><div><a href="/logs/1733000.html">IBM快捷热键表　</a> 2005-12-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F2067682.html&title=Apache%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://tuijian.blogbus.com/" target="_blank">推荐：让我们寻找最优秀的Blogger！</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/2067682.html</link>
   <author>panbird</author>
   <pubDate>Wed, 15 Mar 2006 17:14:34 +0800</pubDate>
  </item>
  <item>
   <title>《Squid 中文权威指南》第3章</title>
   <description><![CDATA[<font size="2">第3章 编译和安装<br /><br />3.1 安装之前<br /><br />假如你使用unix 有一段时间，并且已编译过许多其他软件包，那么只需快速的扫描本章。编译安装squid 的过程与安装其他软件相似。<br /><br />为了编译squid，你需要一个ANSI C 编译器。不要被ANSI 字眼吓倒。假如你已经有一个编译器，它顺从ANSI 指令，那么也一样。GNU C 编译器（gcc）是很好的选择，它被广泛使用。大部分操作系统在其标准安装中附带了C 编译器，不过Solaris 和HP-UX 除外。假如你使用这样的操作系统，那可能没有安装编译器。<br /><br />理论上你应该在即将运行squid 的机器上编译squid。安装过程侦察你的操作系统以发现特定的参数，例如可用文件描述符的数量。然而，假如你的系统没有C 编译器存在，你也许会在其他机器上编译squid，然后把二进制代码copy 回来。如果操作系统不同，那么squid可能会遇到问题。假如操作系统有不同的内核配置，squid 会变得混乱。<br /><br />除了C 编译器，你还需要perl 和awk。awk 是所有unix 系统的标准程序，所以你不必担心它。perl 也是相当普及的，但它也许没有默认安装在你的系统上。你需要gzip 程序来解压源代码发布文件。<br /><br />对Solaris 用户，请确认/usr/ccs/bin 包含在你的PATH 环境变量里，即使你使用gcc编译器。为了编译squid，make 和ar 程序需要在这个目录找到。<br /><br />3.2 解开源代码包<br /><br />在下载完源代码后，你需要在某个目录解开它。具体哪个目录无关紧要。你能解开squid在你的家目录或任何其他地方，大概需要20M 的自由磁盘空间。我个人喜欢用/tmp。使用tar 命令来展开源代码目录：<br />% cd /tmp<br />% tar xzvf /some/where/squid-2.5.STABLE4-src.tar.gz<br /><br />一些tar 程序不支持z选项，该选项自动解压gzip 文件。如果这样，你需要运行如下命令：<br />% gzip -dc /some/where/squid-2.5.STABLE4-src.tar.gz | tar xvf -<br /><br />一旦源代码被展开，下一步通常是配置源代码树。然而，假如这是你第一次编译squid，你应确认特定的内核资源限制足够高。怎样发现，请继续。<br /><br />3.3 调整内核<br /><br />Squid 在高负载下，需要大量的内核资源。特别的，你需要给你的系统配置比正常情况更高的文件描述符和缓存。文件描述符的限制通常很恼人。你最好在开始编译squid 之前来增加这些限制的大小。<br /><br />因为这点，你可能为了避免重建内核的麻烦，而倾向于使用预编译的二进制版本。不幸的是，不管如何你必须重建一个新内核。squid 和内核通过数据结构来交换信息，数据结构的大小不能超过设置的文件描述符的限制。squid 在运行时检查这些设置，并且使用最安全的（最小的）值。这样，即使预编译的二进制版本有比你的内核更高的文件描述符，但还是以你系统内核的实际数值为主。<br /><br />为了改编一些参数，你需要重建新内核。这个过程在不同的操作系统之间不同。假如需要，请参阅Unix 系统管理员手册（Prentice Hall 出版）或者你的操作系统文档。假如你正使用Linux，可能不必重建内核。<br /><br />3.3.1 文件描述符<br /><br />文件描述符是一个简单的整数，用以标明每一个被进程所打开的文件和socket。第一个打开的文件是0，第二个是1，依此类推。Unix 操作系统通常给每个进程能打开的文件数量强加一个限制。更甚的是，unix 通常有一个系统级的限制。<br /><br />因为squid 的工作方式，文件描述符的限制可能会极大的影响性能。当squid 用完所有的文件描述符后，它不能接收用户新的连接。也就是说，用完文件描述符导致拒绝服务。直到一部分当前请求完成，相应的文件和socket 被关闭，squid 不能接收新请求。当squid发现文件描述符短缺时，它会发布警告。<br /><br />在运行./configure 之前，检查你的系统的文件描述符限制是否合适，能给你避免一些麻烦。大多数情况下，1024 个文件描述符足够了。非常忙的cache可能需要4096或更多。在配置文件描述符限制时，我推荐设置系统级限制的数量为每个进程限制的2 倍。<br /><br />通常在你的Unix shell 中能找到系统的文件描述符限制。所有的C shell 及其类似的shell有内建的limit 命令。更新的Bourne shell 及其类似的shell 有一条叫做ulimit 的命令。为了发现你的系统的文件描述符限制，试运行如下命令：<br />csh% limit descriptors unlimited<br />csh% limit descriptors<br />descriptors 4096<br /><br />或者<br /><br />sh$ ulimit -n unlimited<br />sh$ ulimit -n<br />4096<br /><br />在Freebsd 上，你能使用sysctl 命令：<br />% sysctl -a | grep maxfiles<br />kern.maxfiles: 8192<br />kern.maxfilesperproc: 4096<br /><br />如果你不能确认文件描述符限制，squid 的./configure 脚本能替你做到。当你运行./configure 时，请见3.4 章节，观察末尾这样的输出：<br />checking Maximum number of file descriptors we can open... 4096<br /><br />假如其他的limit,ulimit,或者./configure 报告这个值少于1024，你不得不在编译squid 之前，花费时间来增加这个限制值的大小。否则，squid 在高负载时执行性能将很低。<br /><br />增加文件描述符限制的方法因系统不同而不同。下面的章节提供一些方法帮助你开始。<br /><br />3.3.1.1 Freebsd,NetBSD,OpenBSD<br /><br />编辑你的内核配置文件，增加如下一行：<br />options MAXFILES=8192<br /><br />在OpenBSD 上，使用option 代替options。然后，configure，编译，和安装新内核。最后重启系统以使内核生效。<br /><br />3.3.1.2 Linux<br /><br />在Linux 上配置文件描述符有点复杂。在编译squid 之前，你必须编辑系统include 文件中的一个，然后执行一些shell 命令。请首先编辑/usr/include/bits/types.h 文件，改变__FD_SETSIZE 的值：<br />#define _ _FD_SETSIZE 8192<br /><br />下一步，使用这个命令增加内核文件描述符的限制：<br /># echo 8192 &gt;; /proc/sys/fs/file-max<br /><br />最后，增加进程文件描述符的限制，在你即将编译squid 的同一个shell 里执行：<br />sh# ulimit -Hn 8192<br /><br />该命令必须以root 运行，仅仅运行在bash shell。不必重启机器。<br /><br />使用这个技术，你必须在每一次系统启动后执行上述echo 和ulimit 命令，或者至少在squid 启动之前。假如你使用某个rc.d 脚本来启动squid，那是一个放置这些命令的好地方。<br /><br />3.3.1.3 Solaris<br /><br />增加该行到你的/etc/system 文件：<br />set rlim_fd_max = 4096<br /><br />然后，重启机器以使改动生效。<br /><br />3.3.2 Mbuf Clusters<br /><br />BSD 基础的网络代码使用一个叫做mbuf（参阅W.R.Stevens 的TCP/IP 描述卷2）的数据结构。Mbuf 典型的是小块内存（例如128 字节）。较大的网络包的数据存储在mbuf clusters里。内核可能给系统可用的mbuf clusters 的总数量强加一个最高限制。你能使用netstat 命令来发现这个限制：<br />% netstat -m<br />196/6368/32768 mbufs in use (current/peak/max):<br />146 mbufs allocated to data<br />50 mbufs allocated to packet headers<br />103/6182/8192 mbuf clusters in use (current/peak/max)<br />13956 Kbytes allocated to network (56% of mb_map in use)<br />0 requests for memory denied<br />0 requests for memory delayed<br />0 calls to protocol drain routines<br /><br />在这个例子里，有8192 个mbuf clusters 可用，但是永远不会同时用到6182 个。当系统用尽mbuf clusters 时，I/O 机制例如read()和write()返回“无缓存空间可用”的错误信息。<br /><br />NetBSD 和OpenBSD 使用netstat -m 不会显示mbuf 的输出。代替的，它们在syslog 里报告：&quot;WARNING: mclpool limit reached&quot; 。<br /><br />为了增加mbuf clusters 的数量，你必须在内核配置文件里增加一个选项：<br />options NMBCLUSTERS=16384<br />Squid 中文权威指南 3<br /><br />3.3.3 临时端口范围<br /><br />临时端口是TCP/IP 栈分配给出去连接的本地端口。换句话说，当squid 发起一条连接到另一台服务器，内核给本地socket 分配一个端口号。这些本地端口号有特定的范围限制。<br /><br />例如，在FreeBSD 上，默认的临时端口范围是1024-5000。<br /><br />临时端口号的短缺对非常忙的代理服务器（例如每秒数百个连接）来说，会较大的影响性能。这是因为一些TCP 连接在它们被关闭时进入TIME_WAIT 状态。当连接进入TIME_WATI 状态时，临时端口号不能被重用。<br /><br />你能使用netstat 命令来显示有多少个连接进入这个状态：<br /><br />% netstat -n | grep TIME_WAIT<br />Proto Recv-Q Send-Q Local Address Foreign Address (state)<br />tcp4 0 0 192.43.244.42.19583 212.67.202.80.80 TIME_WAIT<br />tcp4 0 0 192.43.244.42.19597 202.158.66.190.80 TIME_WAIT<br />tcp4 0 0 192.43.244.42.19600 207.99.19.230.80 TIME_WAIT<br />tcp4 0 0 192.43.244.42.19601 216.131.72.121.80 TIME_WAIT<br />tcp4 0 0 192.43.244.42.19602 209.61.183.115.80 TIME_WAIT<br />tcp4 0 0 192.43.244.42.3128 128.109.131.47.25666 TIME_WAIT<br />tcp4 0 0 192.43.244.42.3128 128.109.131.47.25795 TIME_WAIT<br />tcp4 0 0 192.43.244.42.3128 128.182.72.190.1488 TIME_WAIT<br />tcp4 0 0 192.43.244.42.3128 128.182.72.190.2194 TIME_WAIT<br /><br />注意这个例子中既有客户端连接又有服务器端的连接。客户端连接有3128作为临时端口号，服务器端连接有80作为远程主机的端口号。临时端口号出现在本地地址栏里。在该例子里，它们是19000 秒。<br /><br />如果你没有看到数千个临时端口在TIME_WAIT状态，那也许不必增加这个端口范围。<br /><br />在Freebsd 上，用如下命令增加临时端口范围：<br /># sysctl -w net.inet.ip.portrange.last=30000<br /><br />在OpenBSD 上，命令类似，但sysctl 变量有不同的名字：<br /># sysctl -w net.inet.ip.portlast=49151<br /><br />在NetBSD 上，事情稍有不同。默认的值是49152-65535.为了增加这个范围，需改变最低限制：<br /># sysctl -w net.inet.ip.anonportmin=10000<br /><br />在Linux 上，简单的写一对数字到下列指定文件：<br /># echo &quot;1024 40000&quot; &gt;; /proc/sys/net/ipv4/ip_local_port_range<br /><br />不要忘记将这些命令加到你的系统启动脚本中，以使机器每一次重启后都生效。<br /><br />3.4 Configure 脚本<br /><br />象许多其他Unix 软件一样，squid在开始编译之前使用./configure脚本来了解操作系统信息。./configure脚本由流行的GNU autoconf程序产生。当script运行时，它用不同的方法来侦察系统，以发现关于库，函数，类型，参数，和有没有功能被提供等。./configure所做的第一件事情是去找一个C 编译器。假如C编译器没有找到，或者编译一个简单的测试程序失败，./configure脚本不能继续。<br /><br />./configure 脚本有大量的选项。最重要的是安装prefix。在运行./configure 之前，你需要决定squid 被安装在哪里。prefix选项指定squid日志，二进制文件，和配置文件的默认位置。你可以在安装之后改变这些文件的位置，但假如你现在决定，事情更容易。<br /><br />默认的安装位置是/usr/local/squid.squid将文件放在prefix 指定目录下面的7 个子目录：<br /><br />% ls -l /usr/local/squid<br />total 5<br />drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 bin<br />drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 etc<br />drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 libexec<br />drwxr-x--- 3 wessels wheel 512 Apr 28 20:43 man<br />drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 sbin<br />drwxr-x--- 4 wessels wheel 512 Apr 28 20:42 share<br />drwxr-x--- 4 wessels wheel 512 Apr 28 20:43 var<br /><br />Squid 使用bin,etc,libexec,man,sbin,和share 目录存放一些相对较小的文件（或其他目录），这些文件不经常改变。但var目录的文件别有洞天。这里你可以发现squid 的日志文件，它增长得非常大（数十或数百兆）。var 也是实际磁盘cache 的默认位置。你也许想将var 目录放在磁盘空间足够的位置，这样做较容易的方法是使用--localstatedir 选项：<br />% ./configure --localstatedir=/bigdisk/var<br /><br />当配置squid 时，你不必对这些路径名称担心太多。你以后可以在squid.conf文件里改变这些路径名。<br /><br />3.4.1 configure 选项<br /><br />./configure 脚本有大量的不同选项，它们以-开始。当你敲入./configure --help 时，能看到选项的完整列表。一些选项对所有configure 脚本是通用的，还有一些是squid 专有的。下面是你可能用得到的标准选项：<br />--perfix =PREFIX<br /><br />如前面描述的一样，这里设置安装目录。安装目录是所有可执行文件，日志，和配置文件的默认目录。在整本书中，$prefix 指你选择的安装目录。<br /><br />--localstatedir =DIR<br />该选项允许你改变var 目录的安装位置。默认是$prefix/var，但也许你想改变它，以使squid 的磁盘缓存和日志文件被存储在别的地方。<br /><br />--sysconfdir =DIR<br />该选项允许你改变etc 目录的位置。默认的是$prefix/etc。假如你想使用/usr 作为安装位置，你也许该配置--sysconfdir为/etc.<br /><br />以下是squid 的专有./configure选项：<br /><br />--enable-dlmalloc[=LIB]<br />在一些系统上，内建的内存分配机制（malloc）在使用squid 时表现不尽人意。使用--enable-dlmalloc 选项将squid 源代码包中的dlmalloc 包编译和链接进来。假如你的系统中已安装dlmalloc，你能使用=LIB 参数指定库的路径。请见http://g.oswego.edu/dl/html/malloc.html更多关于dlmalloc 的信息。<br /><br />--enable-gnuregex<br />在访问控制列表和其他配置指令里，squid 使用正则表达式作为匹配机制。GNU 的正则表达式库包含在squid 的源代码包里；它可以在没有内建正则表达式的操作系统中使用。./configure脚本侦察你系统中的正则表达式库，假如必要，它可以激活使用GNU正则表达式。如果因为某些理由，你想强制使用GNU正则表达式，你可以将这个选项加到./configure命令后。<br /><br />--enable-carp<br />Cache数组路由协议（CARP）用来转发丢失的cache到父cache的数组或cluster。在10.9章有更多关于CARP的细节。<br /><br />--enable-async-io[=N_THREADS]<br />同步I/O 是squid 技术之一，用以提升存储性能。aufs 模块使用大量的线程来执行磁盘I/O 操作。该代码仅仅工作在linux 和solaris 系统中。=N_THREADS 参数改变squid 使用的线程数量。aufs 和同步I/O 在8.4 章中被讨论。<br />请注意--enable-async-io 是打开其他三个./configure 选项的快捷方式，它等同于：<br />--with-aufs-threads=N_THREADS<br />--with-pthreads<br />--enable-storeio=ufs,aufs<br />--with-pthreads<br /><br />该选项导致编译过程链接到你系统中的P 线程库。aufs 存储模块是squid 中唯一需要使用线程的部分。通常来说，如果你使用--enable-saync-io 选项，那么不必再单独指定该选项，因为它被自动激活了。<br /><br />--enable-storeio=LIST<br />Squid 支持大量的不同存储模块。通过使用该选项，你告诉squid 编译时使用哪个模块。在squid-2.5 中，支持ufs,aufs,diskd,和null 模块。通过查询src/fs 中的目录，你能得到一个模<br />块列表。<br />LIST 是一个以逗号分隔的模块列表，例如：<br />% ./configure --enable-storeio=afus,diskd,ufs<br /><br />ufs 模块是默认的，看起来问题最少。不幸的是，它性能有限。其他模块可能在某些操作系统中不必编译。关于squid 存储模块的完整描述，请见第8章。<br />--with-aufs-threads=N_THREADS<br /><br />指定aufs 存储机制使用的线程数量（见8.4章）。squid 默认根据缓存目录的数量，自动计算需要使用多少线程。<br /><br />--enable-heap-replacement<br />该选项不再使用，但被保留用于向后兼容性。你该使用--enable-removal-policies 来代替。<br /><br />--enable-removal-policies=LIST<br />排除策略是squid 需要腾出空间给新的cache目标时，用以排除旧目标的机制。squid-2.5支持3个排除策略：最少近期使用(LRU),贪婪对偶大小(GDS),最少经常使用(LFU)。<br /><br />然而，因为一些理由，./configure 选项使指定的替代策略和需要执行它们的基本数据结构之间的差别模糊化。LRU是默认的，它以双链表数据结构执行。GDS和LFU使用堆栈的数据结构。<br /><br />为了使用GDS 或LFU 策略，你指定：<br />% ./configure --enable-removal-policies=heap<br /><br />然后你在squid 的配置文件里选择使用GDS或LFU。假如你想重新使用LRU,那么指定：<br />% ./configure --enable-removal-policies=heap,lru<br />更多的关于替换策略的细节请见7.5 章。<br /><br />--enable-icmp<br />如在10.5 章中描述的一样，squid 能利用ICMP消息来确定回环时间尺寸，非常象ping程序。你能使用该选项来激活这些功能。<br /><br />--enable-delay-pools<br />延时池是squid 用于传输形状或带宽限制的技术。该池由大量的客户端IP 地址组成。当来自这些客户端的请求处于cache 丢失状态，他们的响应可能被人工延迟。关于延时池的更多细节请见附录C。<br /><br />--enable-useragent-log<br />该选项激活来自客户请求的HTTP 用户代理头的日志。更多细节请见13.5 章。<br /><br />--enable-referer-log<br />该选项激活来自客户请求的HTTP referer 日志。更多细节请见13.4 章。<br /><br />--disable-wccp<br />Web cache 协调协议(WCCP)是CISCO 的专有协议，用于阻止或分发HTTP 请求到一个或多个caches。WCCP默认被激活，假如你愿意，可以使用该选项来禁止该功能。<br /><br />--enable-snmp<br />简单网络管理协议(SNMP)是监视网络设备和服务器的流行方法。该选项导致编译过程去编译所有的SNMP相关的代码，包括一个裁切版本的CMU SNMP库。<br /><br />--enable-cachemgr -hostname[=hostname]<br />cachemgr 是一个CGI程序，你能使用它来管理查询squid。默认cachemgr的hostname值是空的，但你能使用该选项来指定一个默认值。例如：<br />% ./configure --enable-cachemgr-hostname=mycache.myorg.net<br /><br />--enable-arp-acl<br />squid 在一些操作系统中支持ARP,或者以太地址访问控制列表。该代码使用非标准的函数接口，来执行ARP访问控制列表，所以它默认被禁止。假如你在linux或solaris上使用squid，你可能用的上这个功能。<br /><br />--enable-htcp<br />HTCP 是超文本缓存协议--类似于ICP的内部缓存协议。更多细节请见10.8 章。<br /><br />--enable-ssl<br />使用该选项赋予squid 终止SSL/TLS 连接的能力。注意这仅仅工作在web加速器中用以加速请求。更多细节请见15.2.2 章节。<br /><br />--with-openssl[=DIR]<br />假如必要，你使用该选项来告诉squid到哪里找到OpenSSL库或头文件。假如它们不在默认位置，在该选项后指定它们的父路径。例如：<br />% ./configure --enable-ssl --with-ssl=/opt/foo/openssl<br />在这个例子中，你的编译器将在/opt/foo/openssl/include目录中找头文件， 在/opt/foo/openssl/lib 中找库文件。<br /><br />--enable-cache-digests<br />Cache 消化是ICP 的另一个替代，但有着截然不同的特性。请见10.7 章。<br /><br />--enable-err-languages=&quot;lang1 lang2 ...&quot;<br />squid支持定制错误消息，错误消息可以用多种语言报告。该选项指定复制到安装目录($prefix/share/errors)的语言。假如你不使用该选项，所有可用语言被安装。想知道何种语言可用，请见源代码包里errors目录下的目录列表。如下显示如何激活多种语言：<br />% ./configure --enable-err-languages=&quot;Dutch German French&quot; ...<br /><br />--enable-default-err-language=lang<br />该选项设置error_directory 指令的默认值。例如，假如你想使用荷兰语，你能这样指定：<br />% ./configure --enable-default-err-language=Dutch<br />你也能在squid.conf 里指定error_directory 指令，在附录A 中有描述。假如你忽略该选项，英语是默认错误语言。<br /><br />--with-coss-membuf-size=N<br />循环目录存储系统（coss）是squid 的试验性存储机制。该选项设置coss 缓存目录的内存缓冲大小。注意为了使用coss，你必须在--enable-storeio 选项里指定存储类型。<br />该参数以字节形式赋值，默认是1048576 字节或1M。你能指定2M 缓冲如下：<br />% ./configure --with-coss-membuf-size=2097152<br /><br />--enable-poll<br />unix 提供两个相似的函数用以在I/O 事件里扫描开放文件描述符：select() 和poll()。./configure 脚本通常能非常好的计算出何时使用poll()来代替select().假如你想强制使用poll()，那么指定该选项。<br />--desable-poll<br />类似的，如果不使用poll()，那么指定该选项。<br /><br />--disable-http-violations<br />squid 默认可以被配置成违背HTTP协议规范。你能使用该选项来删除违背HTTP协议的代码。<br /><br />--enable-ipf-transparent<br />在第9章中，我将描述如何配置squid来拦截缓存。一些操作系统使用IP Filter包来协助拦截缓存。在这些环境下你应该使用该./configure 选项。如果你使用了该选项，但是编译器提示src/client_side.c文件出错，那是因为IP Filter包没有或没有正确的安装在你的系统中。<br /><br />--enable-pf-transparent<br />你可能需要指定该选项，使用PF包过滤器在操作系统中拦截HTTP。PF是OpenBSD的标准包过滤器，也可能被发布到其他系统中。假如你使用该选项，但是编译器提示src/client_side.c 文件出错，那是因为PF 没有实际安装到你的系统中。<br /><br />--enable-linux-netfilter<br />Netfilter 是linux 2.4 系列内核的包过滤器名字。假如你想在linux2.4或以后的版本中使用HTTP拦截功能，那么激活该选项。<br /><br />--disable-ident-lookups<br />ident是一个简单的协议，允许服务器利用客户端的特殊TCP连接来发现用户名。假如你使用该选项，编译器将把执行这些查询的代码排除出去。即使你在编译时保留了这些代码，除非你在squid.conf文件里指定，squid不会执行ident查询。<br /><br />--disable-internal-dns<br />squid 源代码包含两个不同的DNS 解决方案，叫做“内部的”和“外部的”。内部查询是默认的，但某些人可能要使用外部技术。该选项禁止内部功能，转向使用旧的方式。<br />内部查询使用squid自己的DNS协议执行工具。也就是说，squid产生未完成的DNS查询并且将它们发送到一个解析器。假如超时，它重新发送请求，你能指定任意数量的解析器。该工具的有利处之一是，squid获得准确无误的DNS响应的TTLs。<br />外部查询利用C库的gethostbyname()和gethostbyaddr()函数。squid使用一个外部进程池来制造并行查询。使用外部DNS 解析的主要弊端是你需要更多的辅助进程，增加squid的负载。另一个麻烦是C 库函数不在响应里传输TTLs，这样squid使用postive_dns_ttl 指令提供的一个常量值。<br /><br />--enable-truncate<br />truncate()系统调用是unlink()的替代品。unlink()完全删除cache 文件，truncate()将文件大小设为零。这样做释放了分配给该文件的磁盘空间，但留下适当的目录接口。该选项存在的理由是，某些人相信（或希望）truncate()比unlink()性能表现更好。然而，压力测试显示两者有很少的或根本没有区别。<br /><br />--disable-hostname-checks<br />默认的，squid要求URL主机名在一定程度上遵守古老的RFC 1034 规范：<br />标签必须遵循下列ARPANET 主机名规则。它们必须以字母开始，以字母或数字结尾，仅仅包含字母，数字和下划线。<br />这里字母意味着ASCII字符，从A到Z。既然国际域名日益流行，你可能希望使用该选项来移除限制。<br /><br />--enable-underscores<br />该选项控制squid针对主机名里下划线的行为。通用的标准是主机名里不包含下划线字符，尽管有些人不赞成这点。squid默认会对URL主机名里带下划线的请求产生一条错误消息。你能使用该选项，让squid信任它们，把它们当作合法的。然而，你的DNS解析器也许强迫使用非下划线请求，并且对带下划线的主机名解析失败。<br /><br />--enable-auth[=LIST]<br />该选项控制在squid的二进制文件里支持哪种验证机制。你能选择下列机制的任意组合：<br />basic,digest,ntlm。假如你忽略该选项，squid 仅仅支持basic 验证。假如你使用不带参数的--enable-auth选项，编译进程将增加对所有验证机制的支持。你可以使用以逗号分隔的验证机制列表：<br />% ./configure --enable-auth=digest,ntlm<br />我在第六章和第十二章里会谈得更多。<br /><br />--enable-auth-helpers=LIST<br />这个旧选项现在已舍弃了， 但为了保持向后兼容性仍保留着。你可以使用--enable-basic-auth-helperes=LIST 来代替。<br /><br />--enable-basic-auth-helpers=LIST<br />使用该选项，你能将helpers/basic_auth 目录的一个或多个HTTP Basic验证辅助程序编译进来。请见12.2章找到它们的名字和描述。<br /><br />--enable-ntlm-auth-helpers=LIST<br />使用该选项，你能将helpers/ntlm_auth 目录的一个或多个HTTP NTLM验证辅助程序编译进来。请见12.4章找到它们的名字和描述。<br /><br />--enable-digest-auth-modules=LIST<br />使用该选项，你能将helpers/digest_auth 目录的一个或多个HTTP Digest验证辅助程序编译进来。请见12.3章找到它们的名字和描述。<br /><br />--enable-external-acl-helpers=LIST<br />使用该选项，你能编译一个或多个扩展ACL辅助程序，这些在12.5章中讨论。例如：<br />% ./configure --enable-external-acl-helpers=ip_user,ldap_group<br /><br />--disable-unlinkd<br />unlinkd 是另一个squid的外部辅助进程。它的基本工作是对cache文件执行unlink()或truncate()系统调用。通过在外部进程里执行文件删除工作，能给squid带来明显的性能提升。使用该选项来禁止外部unlink进程功能。<br /><br />--enable-stacktrace<br />某些系统支持在程序崩溃时，自动产生数据追踪。当你激活该功能后，如果squid崩溃，数据追踪信息被写到cache.log文件。这些信息对开发和程序bug调试有用。<br /><br />--enable-x-accelerator-vary<br />该高级功能可能在squid被配置成加速器时使用。它建议squid在响应请求时，从后台原始服务器中寻找X-Accelerator-Vary头。请见15.5章。<br /><br />3.4.2 运行configure<br /><br />现在我们准备运行./configure 脚本。进入源代码的顶级目录敲入./configure，后面跟上前面提到过的任意选项，例如：<br />% cd squid-2.5.STABLE4<br />% ./configure --enable-icmp --enable-htcp<br /><br />./configure 的工作就是侦察你的操作系统，以发现什么东西可用，什么不可用。它首先做的事情之一就是确认你的C编译器可用。假如./configure检测到你的C编译器有问题，脚本会退出，返回如下错误：<br />configure: error: installation or configuration problem: C compiler<br />cannot create executables.<br /><br />很可能你从不会看到这个消息。假如看到了，那意味着你的系统中没有C 编译器存在，或者编译器没有正确安装。请见config.log文件找到解决问题的建议。假如你的系统中有多个C编译器，你可以在运行./configure 之前设置CC环境变量，来告诉./configure使用哪个：<br />% setenv CC /usr/local/bin/gcc<br />% ./configure ...<br /><br />在./configure 检查完该编译器后，它查找头文件，库文件和函数的长列表。通常你不必担心该部分。在某些实际情况中，./configure会终止以引起你的注意，某些事情可能有问题，例如没有足够的文件描述符。假如你指定不完整的或不合理的命令行选项，它也会终止。假如有错误发生，请检查config.log 输出。./configure 的最终任务是创造Makefiles和其他文件，这些文件基于squid从你系统中了解到的知识。到此为止，你准备做编译工作。<br /><br />3.5 编译<br /><br />一旦./configure 完成了它的工作，你简单的敲入make 开始编译源代码：<br />%make<br /><br />正常来说，该过程很顺利，你可以见到大量的滚动行。<br />你也许见到一些编译器警告。大多数情况下，可以安全的忽略这些。假如这些警告非常多，并且一些看起来非常严重，请将它们报告给开发者，在第16.5 章中有描述。<br />假如编译过程没有错误，你可以转移到下一节，描述如何安装你刚才编译的程序。<br />为了验证编译是否成功，你可以再次运行make。你将看到如下输出：<br />% make<br />Making all in lib...<br />Making all in scripts...<br />Making all in src...<br />Making all in fs...<br />Making all in repl...<br />'squid' is up to date.<br />'client' is up to date.<br />'unlinkd' is up to date.<br />'cachemgr.cgi' is up to date.<br />Making all in icons...<br />Making all in errors...<br />Making all in auth_modules...<br /><br />因为许多理由，编译步骤也许会失败，包括：<br /><br />源代码bugs<br /><br />通常squid源代码是完整的调试过的。然而，你也许会遇到某些bugs或问题从而阻止你编译。这种问题在新的开发版本中更容易出现，请将它们报告给开发者。<br /><br /><br />编译器安装问题<br /><br />不正确安装的C编译器不能够编译squid或其他软件包。通常编译器随着操作系统预安装，所以你不必担心它。然而，假如你在操作系统安装完后，试图升级编译器，那么可能会犯错误。绝对不要把已经安装好的编译器从一台机器拷贝到另一台，除非你绝对清楚你在做什么。我觉得在每台机上独立的安装编译器总是最好的。<br /><br />请确认你的编译器的头文件总是与库文件同步。头文件通常在/usr/include目录，而库文件在/usr/lib目录。Linux的流行RPM系统允许它去升级其中之一，但并非另一个。假如库文件基于不同的头文件，squid不能编译。<br /><br />假如你想在开源BSD 变种之一中升级编译器，请确认在/usr/src目录中运行make world，这好过从/usr/src/lib 或/usr/src/include 中运行。<br /><br /><br />如下是一些通用的编译器问题和错误消息：<br /><br />Solaris: make[1]: *** [libmiscutil.a] Error 255<br />这意味着./configure 不能发现ar程序。请确认/usr/ccs/bin位于你的PATH环境变量里。假如你没有安装Sun 的编译器， 那么需要GNU 的工具。(http://www.gnu.org/directory/binutils.html).<br /><br />Linux: storage size of 'rl' isn't known<br />这是因为头文件和库文件不匹配所致，象前面描述的一样。请确认同时升级两者。<br /><br />Digital Unix: Don't know how to make EXTRA_libmiscutil_a_SOURCES. Stop.<br />Digital Unix的make 程序不能兼容automake 包产生的Makefile文件。例如，lib/Makefile.in包含如下行：<br />noinst_LIBRARIES = \<br />@LIBDLMALLOC@ \<br />libmiscutil.a \<br />libntlmauth.a \<br />@LIBREGEX@<br />在替换后，当lib/Makefile 被创建时，它看起来如下：<br />noinst_LIBRARIES = \<br />\<br />libmiscutil.a \<br />libntlmauth.a \<br />&lt;TAB&gt;;<br />象上面显示的一样，最后一行包括一个不可见的TAB字符，它阻止了make。通过安装和使用GNU make，或者手工编辑lib/Makefile 如下，来解决这个问题：<br />noinst_LIBRARIES = \<br />\<br />libmiscutil.a \<br />libntlmauth.a<br /><br /><br />假如你在编译squid时遇到问题，请先检查FAQ。你也许该在Squid的web站点上搜索（使用主页里的搜索栏）。最后，假如你仍有问题，请发邮件到squid-users@squid-cache.org列表。<br /><br />3.6 安装<br /><br />在编译完后，你需要把程序安装到指定的目录。可能需要超级用户权限来把它们放置到安装目录。所以，请先切换到root：<br />%su<br />password:<br />#make install<br /><br />假如你通过使用--enable-icmp 选项，激活了squid 的ICMP衡量功能，那么必须安装pinger程序。pinger 程序必须以超级用户权限安装，因为仅仅允许root 来发送和接受ICMP 消息。<br /><br />下列命令以相应的许可来安装pinger 程序：<br />#make install-pinger<br /><br />在安装完后，你将在squid 的安装目录里（默认是/usr/local/squid）见到下列目录和文件：<br /><br />sbin<br />sbin 目录的程序正常只能被root 启动<br /><br />sbin/squid<br />Squid 的主程序<br /><br />bin<br />bin 目录包含对所有用户可用的程序<br /><br />bin/RunCache<br />RunCache是一个shell脚本，你能用它来启动squid。假如squid死掉，该脚本自动重启它，除非它检测到经常的重启。RunCache是一个时间遗留的产物，那时Squid还不是后台服务进程。在最近的版本里，RunCache很少用到，因为Squid自动重启它自身，当你不使用-N选项时。<br /><br />bin/RunAccel<br />RunAccel 与RunCache 几乎一致，唯一的不同是它增加了一个命令行参数，告诉squid在哪里侦听HTTP 请求。<br /><br />bin/squidclient<br />squidclient 是个简单的HTTP 客户端程序，你能用它来测试squid。它也有一些特殊功能，用以对运行的squid 进程发起管理请求。<br /><br />libexec<br />libexec 目录传统的包含了辅助程序。有一些命令你不能正常的启动。然而，这些程序通常被其他程序启动。<br /><br />libexec/unlinkd<br />unlinkd是一个辅助程序，它从cache目录里删除文件。如你后面看到的一样，文件删除是个性能瓶颈。通过在外部进程里执行删除操作，Squid提升了一些执行性能。<br /><br />libexec/cachemgr.cgi<br />cachemgr.cgi是Squid管理功能的CGI接口。为了使用它，你需要拷贝该程序到你的WEB服务器的cgi-bin目录。在14.2章中有更多描述。<br /><br />libexec/diskd(optional)<br />假如你指定了--enable-storeio=diskd，你才能看到它。<br /><br />libexec/pinger(optional)<br />假如你指定了--enable-icmp，你才能看到它。<br /><br />etc<br />etc 目录包含squid 的配置文件。<br /><br />etc/squid.conf<br />这是squid的主要配置文件。初始的该文件包含了大量的注释，用以解释每一个选项做什么。在你理解了这些配置指令后，建议你删除这些注释，让配置文件更小和更容易阅读。注意假如该文件存在，安装过程不会覆盖该文件。<br /><br />etc/squid.conf.default<br />这是从源代码目录中拷贝过来的默认配置文件。在升级了squid安装后，你也许发现有一份当前默认配置文件的拷贝是有用的。可能会增加新的配置指令，一些存在的旧指令可能有所改变。<br /><br />etc/mime.conf<br />mime.conf文件告诉squid 对从FTP和Gopher服务器获取的数据使用何种MIME类型。该文件是一个关联文件名扩展到MIME类型的表。正常而言，你不必编辑该文件。然而，你可能需要增加特殊文件类型的接口，它们在你的组织内使用。<br /><br />etc/mime.conf.default<br />这是从源代码目录里拷贝过来的默认mime.conf文件。<br /><br />share<br />share目录通常包括squid的只读数据文件。<br /><br />share/mib.txt<br />这是squid的SNMP管理信息基础（MIB）文件。squid自身不使用该文件，然而，你的SNMP客户端软件（例如snmpget和多路由走向图(MRTG)）需要该文件，用以理解来自squid的SNMP对象可用。<br /><br />share/icons<br />share/icons目录包含大量的小图标文件，squid用在FTP和Gopher目录列举里。正常而言，你不必担心这些文件，但如果需要，你可以改变它们。<br /><br />share/errors<br />share/errors目录包含了squid显示给用户看的错误消息模板。这些文件在你安装squid时，从源代码目录拷贝而来。如果需要你可以编辑它们。然而，在每次运行make install时，安装过程总会覆盖它们。所以假如你想定制错误消息，建议你把它们放在不同的目录。<br /><br />var<br />var目录包含了不是很重要的和经常变化的文件。这些文件你不必正常的备份它们。<br /><br />var/logs<br />var/logs目录是squid 不同日志文件的默认位置。当你第一次安装squid 时，它是空的。一旦squid开始运行，你能在这里看到名字为access.log,cache.log和store.log这样的文件。<br /><br />var/cache<br />假如你不在squid.conf文件里指定，这是默认的缓存目录(cache_dir)。第七章有关于缓存目录的所有细节。<br /><br />3.7 打补丁<br /><br />在你运行squid一段时间后，你可能发现需要打源代码补丁，用以修正bug或者增加试验性的功能。在squid-cache.org站点上，对重要的bug修正会发布补丁。假如你不想等到下一个官方发布版本，你能下载补丁，并且打到你的源代码中。然后你需要重新编译squid。<br /><br />为了打补丁-或者有时候叫差别文件-你需要一个叫做&quot;patch&quot;的程序。你的操作系统必须有该程序。如果没有，你可以从GNU工具集里下载(http://www.gnu.org/directory/patch.html).<br /><br />注意假如你在使用匿名CVS（见2.4 节），你不必担心补丁文件。当你升级源代码树时，CVS系统自动升级了补丁。<br /><br />为了打补丁，你必须把补丁文件存放在系统中某处。然后进入到squid的源代码目录，运行如下命令：<br /><br />% cd squid-2.5.STABLE4<br />% patch &lt; /tmp/patch_file<br /><br />默认的，在patch程序运行时，它告诉你它正在做什么。通常输出滚动非常快，除非有问题。你能安全的忽略它输出的offset NNN lines警告。假如你不想见到所有这些输出，使用-s选项选择安静模式。<br /><br />当补丁更新了源代码后，它创造了原始文件的拷贝。例如，假如你对src/http.c 打一个补丁，备份文件名就是src/http.c.orig。这样，假如你在打了补丁后想撤销这个操作，简单的重命名所有的.orig 文件到它们以前的格式。为了成功的使用该技术，建议你在打补丁之前删除所有的.orig 文件。<br /><br />假如patch 程序遇到问题，它停止运行并且给出建议。通常问题如下：<br /><br />在错误的目录运行patch程序——解决的方法是，进入到正确的目录，或者使用patch的-p选项。<br /><br />补丁已打过——patch会告诉你是否已打过补丁文件。在这样的情况下，它会问你是否撤销这个文件的补丁。<br /><br />patch 程序不能理解你赋给它的文件——补丁文件通常有三个风格：正常的，context的和unified的。旧版本的patch 程序可能不理解后两者的差异输出。从GNU的FTP站点获取最近的版本能解决该问题。<br /><br />损坏的补丁文件——假如你在下载和存储补丁文件时不小心，它有可能被损坏。有时候人们以email消息发送补丁文件，在新的窗口里，它们被简单的剪切和粘贴。<br /><br />在这样的系统中，剪切和粘贴能将Tab字符改变为空格，或者不正确的捆绑长行。这些改变混乱了patch。-l选项也许有用，但最好是正确的拷贝和存储补丁文件。<br /><br />某些时候patch不能应用部分或所有的差别文件——在这样的情况下，你能见到类似于Hunk 3 of 4 failed的消息。失败的部分被存储在命名为.rej的文件里。例如，假如在处理src/http.c时失败，patch 程序将该差别文件片断存为src/http.c.rej。在这样的情况下，你也许能手工修正这些问题，但它通常不值得这么做。假如你有大量的&quot;failed hunks&quot;或者.rej文件，建议你去下载最近源代码版本的完整新拷贝。<br /><br />在你打完补丁后，你必须重新编译squid。make的先进功能之一就是它仅仅编译改变了的文件。但有时候make不能理解错综复杂的依赖关系，它没有完整的重编译所需文件。为了安全起见，通常建议你去重编译所有文件。最好的方法是在开始编译之前清除源代码树：<br /><br />%make clean<br />%make<br /><br />3.8 重运行configure<br /><br />有时候你可能发现有必要重新运行./configure。例如，假如你调整了内核参数，你必须再次运行./configure以使它能发现新设置。当你阅读本书时，你也发现你必须使用./configure选项来激活所需的功能。<br /><br />以相同的选项重运行./configure，使用如下命令：<br />%config.status --recheck<br /><br />另一个技术是`touch config.status`文件，它更新了该文件的时间戳。这导致make在编译源代码之前，重新运行./configure脚本：<br />% touch config.status<br />% make<br /><br />如果增加或删除./configure选项，你必须重新敲入完整的命令行。假如你记不住以前的选项，请查看config.status文件的顶部。例如：<br />% head config.status<br />#! /bin/sh<br /># Generated automatically by configure.<br /># Run this file to recreate the current configuration.<br />Squid 中文权威指南 16<br /># This directory was configured as follows,<br /># on host foo.life-gone-hazy.com:<br />#<br /># ./configure --enable-storeio=ufs,diskd --enable-carp \<br /># --enable-auth-modules=NCSA<br /># Compiler output produced by configure, useful for debugging<br /># configure, is in ./config.log if it exists.<br /><br />在运行./configure之后，你必须再次编译和安装squid。安全起见，建议先运行make clean：<br />%make clean<br />%make<br /><br />请回想一下，./configure会缓存它在你系统中发现的东西。在这样的形式下，你可能想清除这些缓存，从头开始编译过程。假如喜欢，你可以简单的删除config.cache 文件。然后，下一次./configure运行时，它不会使用以前的数值。你也能恢复squid源代码树到它的configure之前的状态，使用如下命令：<br />%make distclean<br /><br />这将删除所有的目标文件和其他被./configure和make程序产生的文件。</font> <br /><br /><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2471201.html">程序员创业三关</a> 2006-05-14</div><div><a href="/logs/1826866.html">2005岁末BLOG 系统大评点</a> 2006-01-16</div><div><a href="/logs/1733000.html">IBM快捷热键表　</a> 2005-12-21</div><div><a href="/logs/1561297.html">MBTI 测试报告</a> 2005-11-03</div><div><a href="/logs/1524534.html">Apache 服务器 Log 分析应用实例</a> 2005-10-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F1902017.html&title=%E3%80%8ASquid+%E4%B8%AD%E6%96%87%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97%E3%80%8B%E7%AC%AC3%E7%AB%A0">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://icity.cn" target="_blank">《城客》：第一本中文互动杂志！</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/1902017.html</link>
   <author>panbird</author>
   <pubDate>Thu, 09 Feb 2006 10:55:10 +0800</pubDate>
  </item>
  <item>
   <title>2005岁末BLOG 系统大评点</title>
   <description><![CDATA[L-Blog: <a href="http://www.loveyuki.com/" target="_blank">http://www.loveyuki.com</a><br>
由Loveyuki自主开发的基于 ASP+Access 的小型单用户BLOG，目前似乎已经停止更新了，但是用户群相当大，而且是国内相当多的BLOG系统的鼻祖。<br>
<br>
oblog: <a href="http://www.oioj.net/" target="_blank">http://www.oioj.net</a><br>
<br>
多用户Blog,目前占据ASP多用户BLOG的大部分市场，2.X商业版已经实行免费，很值得继续关注与期待的国内作品。<br>
<br>
<br>
SLblog：<a href="http://slblog.com/" target="_blank">http://SLblog.com</a><br>
<br>
多用户Blog，刚发展起来的，更新很快，感觉像是oblog和missblog的结合体，同时首创了Blog系统无限级分类和用户栏目的无限级分类，多功能在现编辑器。但界面不是很美观，好在模板和程序分离，方便修改。<br>
<br>
<br>
Misslog: <a href="http://www.misslog.com/blog" target="_blank">http://www.misslog.com/blog</a><br>
<br>
多用户blog,每个blog可以有多个用户参与创作与维护，团队功能很强大！<br>
<br>
<br>
LBS: <a href="http://www.voidland.com/blog" target="_blank">http://www.voidland.com/blog</a><br>
<br>
LBS早期基于L-Blog架构，自从LBS2推出以后，大部分属于自己的创作，模板很多，用户群也逐渐庞大。<br>
<br>
<br>
Z-Blog: <a href="http://www.rainbowsoft.org/zblog/" target="_blank">http://www.rainbowsoft.org/zblog/</a><br>
<br>
今年发展相当快的Blog系统，官方提供了想当丰富的支持，也创造了比较好的交流环境，这是他的一大亮点。<br>
<br>
<br>
<a href="http://www.pjhome.net/" target="_blank">PJBlog</a>: <a href="http://www.pjhome.net/" target="_blank">http://www.pjhome.net/</a><br>
<br>
基于ASP的单用户BLOG系统，由于其插件异常丰富，可扩展的功能很多，比较适合喜欢功能饱满的朋友。<br>
<br>
<br>
Alpar's Blog: <a href="http://blog.fz0132.com/" target="_blank">http://blog.fz0132.com</a><br>
<br>
基于L-Blog架构，但是作了相当大程度的修改，全面兼容LBS^2 的Style，目前版本模板采用DIV+CSS，很值得期待后续发展。<br>
<br>
<br>
nblog: <a href="http://blog.nowans.com/" target="_blank">http://blog.nowans.com/</a><br>
<br>
一个基于Access的个人Blog程序，全生成静态页面，刚开始起步。<br>
<br>
<br>
blogx： <a href="http://www.blanksoft.com/blogx/" target="_blank">http://www.blanksoft.com/blogx/</a><br>
<br>
<br>
d2kblog: <a href="http://www.d2ksoft.com/" target="_blank">http://www.d2ksoft.com/</a><br>
<br>
国外一个BLOG系统，支持多国语言页面内容和页面样式分离。<br>
<br>
<br>
KeeBlogSystem: <a href="http://keesky.com/blog/" target="_blank">http://keesky.com/blog/</a><br>
<br>
XUL后台管理，很有特点的一个BLOG系统。<!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2081878.html">从LiveJournal后台发展看大规模网站性能优化方法</a> 2006-03-17</div><div><a href="/logs/1733000.html">IBM快捷热键表　</a> 2005-12-21</div><div><a href="/logs/1561297.html">MBTI 测试报告</a> 2005-11-03</div><div><a href="/logs/1538171.html">AJAX基础教程</a> 2005-10-26</div><div><a href="/logs/1524526.html">日志文件分析工具—AWStats在IIS中的配置步骤</a> 2005-10-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F1826866.html&title=2005%E5%B2%81%E6%9C%ABBLOG+%E7%B3%BB%E7%BB%9F%E5%A4%A7%E8%AF%84%E7%82%B9">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://pindao.blogbus.com/shenghuo?utm_source=blogbus&utm_medium=rss&utm_campaign=shenghuo" target="_blank">生活频道——笑谈生活，坐看人生，这里有着小人物的健康生活。</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/1826866.html</link>
   <author>panbird</author>
   <pubDate>Mon, 16 Jan 2006 11:38:24 +0800</pubDate>
  </item>
  <item>
   <title>Lucene倒排索引原理</title>
   <description><![CDATA[<!--StartFragment --> Lucene是一个高性能的java全文检索工具包，它使用的是倒排文件索引结构。该结构及相应的生成算法如下：<br /><br />0）设有两篇文章1和2<br />文章1的内容为：Tom lives in Guangzhou,I live in Guangzhou too.<br />文章2的内容为：He once lived in Shanghai.<br /><br />1)由于lucene是基于关键词索引和查询的，首先我们要取得这两篇文章的关键词，通常我们需要如下处理措施<br />a.我们现在有的是文章内容，即一个字符串，我们先要找出字符串中的所有单词，即分词。英文单词由于用空格分隔，比较好处理。中文单词间是连在一起的需要特殊的分词处理。<br />b.文章中的”in”, “once” “too”等词没有什么实际意义，中文中的“的”“是”等字通常也无具体含义，这些不代表概念的词可以过滤掉<br />c.用户通常希望查“He”时能把含“he”，“HE”的文章也找出来，所以所有单词需要统一大小写。<br />d.用户通常希望查“live”时能把含“lives”，“lived”的文章也找出来，所以需要把“lives”，“lived”还原成“live”<br />e.文章中的标点符号通常不表示某种概念，也可以过滤掉<br />在lucene中以上措施由Analyzer类完成<br /><br />经过上面处理后<br />    文章1的所有关键词为：[tom] [live] [guangzhou] [i] [live] [guangzhou]<br />    文章2的所有关键词为：[he] [live] [shanghai]<br /><br />2) 有了关键词后，我们就可以建立倒排索引了。上面的对应关系是：“文章号”对“文章中所有关键词”。倒排索引把这个关系倒过来，变成：“关键词”对“拥有该关键词的所有文章号”。文章1，2经过倒排后变成<br />关键词   文章号<br />guangzhou  1<br />he         2<br />i           1<br />live       1,2<br />shanghai   2<br />tom         1<br /><br />通常仅知道关键词在哪些文章中出现还不够，我们还需要知道关键词在文章中出现次数和出现的位置，通常有两种位置：a)字符位置，即记录该词是文章中第几个字符（优点是关键词亮显时定位快）；b)关键词位置，即记录该词是文章中第几个关键词（优点是节约索引空间、词组（phase）查询快），lucene中记录的就是这种位置。<br /><br />加上“出现频率”和“出现位置”信息后，我们的索引结构变为：<br />关键词   文章号[出现频率]   出现位置<br />guangzhou 1[2]               3，6<br />he       2[1]               1<br />i         1[1]               4<br />live      1[2],2[1]           2，5，2<br />shanghai  2[1]               3<br />tom      1[1]               1<br /><br />以live 这行为例我们说明一下该结构：live在文章1中出现了2次，文章2中出现了一次，它的出现位置为“2,5,2”这表示什么呢？我们需要结合文章号和出现频率来分析，文章1中出现了2次，那么“2,5”就表示live在文章1中出现的两个位置，文章2中出现了一次，剩下的“2”就表示live是文章2中第 2个关键字。<br />    <br />以上就是lucene索引结构中最核心的部分。我们注意到关键字是按字符顺序排列的（lucene没有使用B树结构），因此lucene可以用二元搜索算法快速定位关键词。<br />    <br />实现时 lucene将上面三列分别作为词典文件（Term Dictionary）、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不仅保存有每个关键词，还保留了指向频率文件和位置文件的指针，通过指针可以找到该关键字的频率信息和位置信息。<br /><br />    Lucene中使用了field的概念，用于表达信息所在位置（如标题中，文章中，url中），在建索引中，该field信息也记录在词典文件中，每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)。<br /><br />     为了减小索引文件的大小，Lucene对索引还使用了压缩技术。首先，对词典文件中的关键词进行了压缩，关键词压缩为&lt;前缀长度，后缀&gt;，例如：当前词为“阿拉伯语”，上一个词为“阿拉伯”，那么“阿拉伯语”压缩为&lt;3，语&gt;。其次大量用到的是对数字的压缩，数字只保存与上一个值的差值（这样可以减小数字的长度，进而减少保存该数字需要的字节数）。例如当前文章号是16389（不压缩要用3个字节保存），上一文章号是16382，压缩后保存7（只用一个字节）。<br />    <br />    下面我们可以通过对该索引的查询来解释一下为什么要建立索引。<br />假设要查询单词 “live”，lucene先对词典二元查找、找到该词，通过指向频率文件的指针读出所有文章号，然后返回结果。词典通常非常小，因而，整个过程的时间是毫秒级的。<br />而用普通的顺序匹配算法，不建索引，而是对所有文章的内容进行字符串匹配，这个过程将会相当缓慢，当文章数目很大时，时间往往是无法忍受的。 <!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2067682.html">Apache学习笔记</a> 2006-03-15</div><div><a href="/logs/1750121.html">留言版留言自动折行问题</a> 2005-12-26</div><div><a href="/logs/1564360.html">在unix上让apache支持asp</a> 2005-11-04</div><div><a href="/logs/1537310.html">人生的八个经典问题</a> 2005-10-26</div><div><a href="/logs/1524526.html">日志文件分析工具—AWStats在IIS中的配置步骤</a> 2005-10-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F1771287.html&title=Lucene%E5%80%92%E6%8E%92%E7%B4%A2%E5%BC%95%E5%8E%9F%E7%90%86">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://pindao.blogbus.com/fengshang?utm_source=blogbus&utm_medium=rss&utm_campaign=fengshang" target="_blank">风尚频道——国内顶尖的时尚族群汇聚于此，未必是流行，但一定要有品位。</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/1771287.html</link>
   <author>panbird</author>
   <pubDate>Sat, 31 Dec 2005 11:47:16 +0800</pubDate>
  </item>
  <item>
   <title>prototype.js开发笔记</title>
   <description><![CDATA[<div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="CLEAR: both"><a name="d0e6"></a>1. Prototype是什么?</h2></div></div><div></div></div><p>或许你还没有用过它， <a href="http://prototype.conio.net/" target="_top">prototype.js</a> 是一个由<a href="http://www.conio.net/" target="_top">Sam Stephenson</a>写的JavaScript包。这个构思奇妙编写良好的一段<span class="bold"><b>兼容标准</b></span>的一段代码将承担创造胖客户端， 高交互性WEB应用程序的重担。轻松加入Web 2.0特性。</p><p>如果你最近体验了这个程序包，你很可能会发现文档并不是它的强项之一。像所有在我之前的开发者一样，我只能一头扎进prototype.js的源代码中并且试验其中的每一个部分。 我想当我学习他的时候记写笔记然后分享给其他人将会很不错。</p><p>我也一起提供了这个包的对象，类，方法和扩展的 <a title="4. prototype.js参考" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#reference">非官方参考</a> 。</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="CLEAR: both"><a name="d0e27"></a>2. 通用性方法</h2></div></div><div></div></div><p>这个程序包里面包含了许多预定义的对象和通用性方法。编写这些方法的明显的目的就是为了减少你大量的重复编码和惯用法。</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e32"></a>2.1. 使用 <tt class="literal">$()</tt>方法</h3></div></div><div></div></div><p><tt class="literal">$()</tt> 方法是在DOM中使用过于频繁的 <tt class="literal">document.getElementById()</tt> 方法的一个便利的简写，就像这个DOM方法一样，这个方法返回参数传入的id的那个元素。</p><p>比起DOM中的方法，这个更胜一筹。你可以传入多个id作为参数然后 <tt class="literal">$()</tt> 返回一个带有所有要求的元素的一个 <tt class="literal">Array</tt> 对象。下面的例子会向你描述这些。</p><pre class="programlisting">&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt; Test Page &lt;/TITLE&gt;
&lt;script src=&quot;prototype-1.3.1.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
    function test1()
    {
        var d = $('myDiv');
        alert(d.innerHTML);
    }

    function test2()
    {
        var divs = $('myDiv','myOtherDiv');
        for(i=0; i&lt;divs.length; i++)
        {
            alert(divs[i].innerHTML);
        }
    }
&lt;/script&gt;
&lt;/HEAD&gt;

&lt;BODY&gt;
    &lt;div id=&quot;myDiv&quot;&gt;
        &lt;p&gt;This is a paragraph&lt;/p&gt;
    &lt;/div&gt;
    &lt;div id=&quot;myOtherDiv&quot;&gt;
        &lt;p&gt;This is another paragraph&lt;/p&gt;
    &lt;/div&gt;

    &lt;input type=&quot;button&quot; value=Test1 onclick=&quot;test1();&quot;&gt;&lt;br&gt;
    &lt;input type=&quot;button&quot; value=Test2 onclick=&quot;test2();&quot;&gt;&lt;br&gt;

&lt;/BODY&gt;
&lt;/HTML&gt;</pre><p>这个方法的另一个好处就是你可以传入id字符串或者元素对象自己，这使得在创建可以传入任何形式参数的方法的时候， 它变得非常有用。</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e57"></a>2.2. 使用<tt class="literal">$F()</tt>方法</h3></div></div><div></div></div><p><tt class="literal">$F()</tt>方法是另一个非常受欢迎的简写。它可以返回任何输入表单控件的值，如文本框或下拉框。 这个方法可以传入元素的id或者元素自己。</p><pre class="programlisting">&lt;script&gt;
    function test3()
    {
        alert(  <span class="bold"><b>$F('userName')</b></span>  );
    }
&lt;/script&gt;

&lt;input type=&quot;text&quot; id=&quot;userName&quot; value=&quot;Joe Doe&quot;&gt;&lt;br&gt; 
&lt;input type=&quot;button&quot; value=Test3 onclick=&quot;test3();&quot;&gt;&lt;br&gt;</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e72"></a>2.3. 使用<tt class="literal">Try.these()</tt>方法</h3></div></div><div></div></div><p><tt class="literal">Try.these()</tt> 方法使得实现当你想调用不同的方法直到其中的一个成功正常的这种需求变得非常容易， 他把一系列的方法作为参数并且按顺序的一个一个的执行这些方法直到其中的一个成功执行，返回成功执行的那个方法的返回值。</p><p>在下面的例子中， <tt class="literal">xmlNode.text</tt>在一些浏览器中好用，但是<tt class="literal">xmlNode.textContent</tt>在另一些浏览器中正常工作。 使用<tt class="literal">Try.these()</tt>方法我们可以得到正常工作的那个方法的返回值。</p><pre class="programlisting">&lt;script&gt;
function getXmlNodeValue(xmlNode){
    return Try.these(
        function() {return xmlNode.text;},
        function() {return xmlNode.textContent;)
        );
}
&lt;/script&gt;</pre></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="CLEAR: both"><a name="d0e95"></a>3. <tt class="literal">Ajax</tt> 对象</h2></div></div><div></div></div><p>上面提到的共通方法非常好，但是面对它吧，它们不是最高级的那类东西。它们是吗？你很可能自己编写了这些甚至在你的脚本里面有类似功能的方法。但是这些方法只是冰山一角。</p><p>我很肯定你对prototype.js感兴趣的原因很可能是由于它的AJAX能力。所以让我们解释当你需要完成AJAX逻辑的时候，这个包如何让它更容易。</p><p><tt class="literal">Ajax</tt> 对象是一个预定义对象，由这个包创建，为了封装和简化编写<a href="http://en.wikipedia.org/wiki/Ajax_(programming)" target="_top">AJAX</a> 功能涉及的狡猾的代码。 这个对象包含一系列的封装AJAX逻辑的类。我们来看看它们的一些。</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e111"></a>3.1. 使用 <tt class="literal">Ajax.Request</tt>类</h3></div></div><div></div></div><p>如果你不使用任何的帮助程序包，你很可能编写了整个大量的代码来创建<tt class="literal">XMLHttpRequest</tt>对象并且异步的跟踪它的进程， 然后解析出响应 然后处理它。当你不需要支持多于一种类型的浏览器时你会感到非常的幸运。</p><p>为了支持 AJAX 功能。这个包定义了 <tt class="literal">Ajax.Request </tt>类。</p><p>假如你有一个应用程序可以通过url <span class="emphasis"><em>http://yoursever/app/get_sales?empID=1234&amp;year=1998</em></span>与服务器通信。它返回下面这样的XML 响应。</p><pre class="programlisting">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;ajax-response&gt;
    &lt;response type=&quot;object&quot; id=&quot;productDetails&quot;&gt;
        &lt;monthly-sales&gt;
            &lt;employee-sales&gt;
                &lt;employee-id&gt;1234&lt;/employee-id&gt;
                &lt;year-month&gt;1998-01&lt;/year-month&gt;
                &lt;sales&gt;$8,115.36&lt;/sales&gt;
            &lt;/employee-sales&gt;
            &lt;employee-sales&gt;
                &lt;employee-id&gt;1234&lt;/employee-id&gt;
                &lt;year-month&gt;1998-02&lt;/year-month&gt;
                &lt;sales&gt;$11,147.51&lt;/sales&gt;
            &lt;/employee-sales&gt;
        &lt;/monthly-sales&gt;
    &lt;/response&gt;
&lt;/ajax-response&gt;</pre><p>用 <tt class="literal">Ajax.Request</tt>对象和服务器通信并且得到这段XML是非常简单的。下面的例子演示了它是如何完成的。</p><pre class="programlisting">&lt;script&gt;
    function searchSales()
    {
        var empID = $F('lstEmployees');
        var y = $F('lstYears');
        var url = 'http://yoursever/app/get_sales';
        var pars = 'empID=' + empID + '&amp;year=' + y;<span class="bold"><b>
       var myAjax = new Ajax.Request(
                    url,
                    {method: 'get', parameters: pars, onComplete: showResponse}
                    );</b></span>

    }

    function showResponse(originalRequest)
    {
        //put returned XML in the textarea
        $('result').value = originalRequest.responseText;
    }
&lt;/script&gt;

&lt;select id=&quot;lstEmployees&quot; size=&quot;10&quot; onchange=&quot;searchSales()&quot;&gt;
    &lt;option value=&quot;5&quot;&gt;Buchanan, Steven&lt;/option&gt;
    &lt;option value=&quot;8&quot;&gt;Callahan, Laura&lt;/option&gt;
    &lt;option value=&quot;1&quot;&gt;Davolio, Nancy&lt;/option&gt;
&lt;/select&gt;
&lt;select id=&quot;lstYears&quot; size=&quot;3&quot; onchange=&quot;searchSales()&quot;&gt;
    &lt;option selected=&quot;selected&quot; value=&quot;1996&quot;&gt;1996&lt;/option&gt;
    &lt;option value=&quot;1997&quot;&gt;1997&lt;/option&gt;
    &lt;option value=&quot;1998&quot;&gt;1998&lt;/option&gt;
&lt;/select&gt;
&lt;br&gt;&lt;textarea id=result cols=60 rows=10 &gt;&lt;/textarea&gt;</pre><p>你看到传入 <tt class="literal">Ajax.Request</tt>构造方法的第二个对象了吗？ 参数<tt class="literal">{method: 'get', parameters: pars, onComplete: showResponse}</tt> 表示一个匿名对象的真实写法。他表示你传入的这个对象有一个名为 <tt class="literal">method</tt> 值为 <tt class="literal">'get'的属性，</tt>另一个属性名为 <tt class="literal">parameters</tt> 包含HTTP请求的查询字符串，和一个<tt class="literal">onComplete</tt> 属性/方法包含函数<tt class="literal">showResponse</tt>。</p><p>还有一些其它的属性可以在这个对象里面定义和设置，如 <tt class="literal">asynchronous</tt>，可以为<tt class="literal">true</tt> 或 <tt class="literal">false</tt> 来决定AJAX对服务器的调用是否是异步的（默认值是 <tt class="literal">true</tt>）。</p><p>这个参数定义AJAX调用的选项。在我们的例子中，在第一个参数通过HTTP GET命令请求那个url，传入了变量 <tt class="literal">pars</tt>包含的查询字符串， <tt class="literal">Ajax.Request </tt>对象在它完成接收响应的时候将调用<tt class="literal">showResponse</tt> 方法。</p><p>也许你知道， <tt class="literal">XMLHttpRequest</tt>在HTTP请求期间将报告进度情况。这个进度被描述为四个不同阶段：<span class="emphasis"><em>Loading</em></span>, <span class="emphasis"><em>Loaded</em></span>, <span class="emphasis"><em>Interactive</em></span>, 或 <span class="emphasis"><em>Complete</em></span>。你可以使 <tt class="literal">Ajax.Request</tt> 对象在任何阶段调用自定义方法 ，<span class="emphasis"><em>Complete</em></span> 是最常用的一个。想调用自定义的方法只需要简单的在请求的选项参数中的名为 <tt class="literal">onXXXXX</tt> 属性/方法中提供自定义的方法对象。 就像我们例子中的 <tt class="literal">onComplete</tt> 。你传入的方法将会被用一个参数调用，这个参数是 <tt class="literal">XMLHttpRequest</tt> 对象自己。你将会用这个对象去得到返回的数据并且或许检查包含有在这次调用中的HTTP结果代码的 <tt class="literal">status</tt> 属性。</p><p>还有另外两个有用的选项用来处理结果。我们可以在<tt class="literal">onSuccess</tt> 选项处传入一个方法，当AJAX无误的执行完后调用， 相反的，也可以在<tt class="literal">onFailure</tt>选项处传入一个方法，当服务器端出现错误时调用。正如<tt class="literal">onXXXXX</tt> 选项传入的方法一样，这两个在被调用的时候也传入一个带有AJAX请求的<tt class="literal">XMLHttpRequest对象。</tt></p><p>我们的例子没有用任何有趣的方式处理这个 XML响应， 我们只是把这段XML放进了一个文本域里面。对这个响应的一个典型的应用很可能就是找到其中的想要的信息，然后更新页面中的某些元素， 或者甚至可能做某些XSLT转换而在页面中产生一些HTML。</p><p>更完全的解释，请参照 <a title="4.14. Ajax.Request 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_request_reference">Ajax.Request 参考</a> 和 <a title="4.15. options 参数对象" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#options_reference">Ajax选项参考</a>。</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e251"></a>3.2. 使用 <tt class="literal">Ajax.Updater</tt> 类</h3></div></div><div></div></div><p>如果你的服务器的另一端返回的信息已经是HTML了，那么使用这个程序包中 <tt class="literal">Ajax.Updater</tt> 类将使你的生活变得更加得容易。用它你只需提供哪一个元素需要被AJAX请求返回的HTML填充就可以了，例子比我写说明的更清楚。</p><pre class="programlisting">&lt;script&gt;
    function getHTML()
    {
        var url = 'http://yourserver/app/getSomeHTML';
        var pars = 'someParameter=ABC';

         <span class="bold"><b>var myAjax = new Ajax.Updater('placeholder', url, {method: 'get', parameters: pars});</b></span>

    }
&lt;/script&gt;

&lt;input type=button value=GetHtml onclick=&quot;getHTML()&quot;&gt;
&lt;div id=&quot;placeholder&quot;&gt;&lt;/div&gt;</pre><p>你可以看到，这段代码比前面的例子更加简洁，不包括 <tt class="literal">onComplete</tt> 方法，但是在构造方法中传入了一个元素id。 我们来稍稍修改一下代码来描述如何在客户端处理服务器段错误成为可能。</p><p>我们将加入更多的选项， 指定处理错误的一个方法。这个是用 <tt class="literal">onFailure</tt> 选项来完成的。</p><p>我们也指定了一个 <tt class="literal">placeholder</tt> 只有在成功请求之后才会被填充。为了完成这个目的我们修改了第一个参数从一个简单的元素id到一个带有两个属性的对象， <tt class="literal">success</tt> (一切OK的时候被用到) 和 <tt class="literal">failure</tt> (有地方出问题的时候被用到) 在下面的例子中没有用到<tt class="literal">failure</tt>属性，而仅仅在 <tt class="literal">onFailure</tt> 处使用了 <tt class="literal">reportError</tt> 方法。</p><pre class="programlisting">&lt;script&gt;
    function getHTML()
    {
        var url = 'http://yourserver/app/getSomeHTML';
        var pars = 'someParameter=ABC';<span class="bold"><b>
        var myAjax = new Ajax.Updater(
                    {success: 'placeholder'},
                    url,
                    {method: 'get', parameters: pars, onFailure: reportError});</b></span>

    }

    function reportError(request)
    {
        alert('Sorry. There was an error.');
    }
&lt;/script&gt;

&lt;input type=button value=GetHtml onclick=&quot;getHTML()&quot;&gt;
&lt;div id=&quot;placeholder&quot;&gt;&lt;/div&gt;
</pre><p>如果你的服务器逻辑是返回JavaScript 代码而不是单纯的 HTML 标记， <tt class="literal">Ajax.Updater</tt>对象可以执行那段JavaScript代码。为了使这个对象对待响应为JavaScript，你只需在最后参数的对象构造方法中简单加入<tt class="literal">evalScripts: true</tt>属性。</p><p>更完全的解释，请参照 <a title="4.16. Ajax.Updater 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_updater_reference">Ajax.Updater 参考</a> 和 <a title="4.15. options 参数对象" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#options_reference">Ajax选项参考</a> 。</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="CLEAR: both"><a name="reference"></a>4. prototype.js参考</h2></div></div><div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e322"></a>4.1. JavaScript 类的扩展</h3></div></div><div></div></div><p>prototype.js 包中加入功能的一种途径就是扩展已有的JavaScript 类。</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e327"></a>4.2. 对 <tt class="literal">Object</tt> 类的扩展</h3></div></div><div></div></div><div class="table"><a name="d0e333"></a><p class="title"><b>Table 1. <tt class="literal">Object</tt> 类的扩展</b></p><table summary="Object 类的扩展" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">extend(destination, source)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">destination</tt>: 任何对象, <tt class="literal">source</tt>: 任何对象</td><td>用从 <tt class="literal">source</tt> 到 <tt class="literal">destination</tt>复制所有属性和方法的方式 来提供一种继承机制。</td></tr><tr><td><tt class="literal">extend(object)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">任何对象</tt></td><td>用从传入的 <tt class="literal">object</tt> 中复制所有属性和方法的方式 来提供一种继承机制。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e391"></a>4.3. 对 <tt class="literal">Number</tt> 类的扩展</h3></div></div><div></div></div><div class="table"><a name="d0e398"></a><p class="title"><b>Table 2. <tt class="literal">Number</tt> 类的扩展</b></p><table summary="Number 类的扩展" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">toColorPart()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>返回数字的十六进制描述， 当在HTML中转换为RGB颜色组件到HTML中使用的颜色。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e431"></a>4.4. 对 <tt class="literal">Function</tt> 类的扩展</h3></div></div><div></div></div><div class="table"><a name="d0e438"></a><p class="title"><b>Table 3. 对 <tt class="literal">Function</tt> 类的扩展</b></p><table summary="对 Function 类的扩展" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">bind(object)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">object</tt>: 拥有这个方法的对象</td><td>返回预先绑定在拥有该函数(=方法)的对象上的函数实例， 返回的方法将和原来的方法具有相同的参数。</td></tr><tr><td><tt class="literal">bindAsEventListener(object)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">object</tt>: 拥有这个方法的对象</td><td>返回预先绑定在拥有该函数(=方法)的对象上的函数实例， 返回的方法将把当前的事件对象作为它的参数。</td></tr></tbody></table></div><p>让我们看看这些扩展的具体例子。</p><pre class="programlisting">&lt;input type=checkbox id=myChk value=1&gt; Test?
&lt;script&gt;
    //declaring the class
    var CheckboxWatcher = Class.create();

    //defining the rest of the class implmentation
    CheckboxWatcher.prototype = {

       initialize: function(chkBox, message) {
            this.chkBox = $(chkBox);
            this.message = message;
            //assigning our method to the event
            <span class="bold"><b>this.chkBox.onclick = this.showMessage.bindAsEventListener(this);</b></span>
       },

       showMessage: function(evt) {
          alert(this.message + ' (' + evt.type + ')');
       }
    };


    var watcher = new CheckboxWatcher('myChk', 'Changed');
&lt;/script&gt;</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e492"></a>4.5. 对 <tt class="literal">String</tt> 类的扩展</h3></div></div><div></div></div><div class="table"><a name="d0e499"></a><p class="title"><b>Table 4. <tt class="literal">String</tt> 类的扩展</b></p><table summary="String 类的扩展" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">stripTags()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>返回一个把所有的HTML或XML标记都移除的字符串。</td></tr><tr><td><tt class="literal">escapeHTML()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>返回一个把所有的HTML标记回避掉的字符串。</td></tr><tr><td><tt class="literal">unescapeHTML()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>和 <tt class="literal">escapeHTML()</tt>相反。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e559"></a>4.6. 对 <tt class="literal">document</tt> DOM 对象的扩展</h3></div></div><div></div></div><div class="table"><a name="d0e566"></a><p class="title"><b>Table 5. <tt class="literal">document</tt> DOM 对象的扩展</b></p><table summary="document DOM 对象的扩展" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">getElementsByClassName(className)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">className</tt>: 关联在元素上的CSS类名</td><td>返回给定的具有相同的CSS类名的所有元素。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e600"></a>4.7. 对 <tt class="literal">Event</tt> 对象的扩展</h3></div></div><div></div></div><div class="table"><a name="d0e607"></a><p class="title"><b>Table 6. <tt class="literal">Event</tt> 对象的扩展</b></p><table summary="Event 对象的扩展" border="1"><colgroup><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">KEY_BACKSPACE</tt></td><td><tt class="literal">Number</tt></td><td>8: 常量，退格(Backspace)键的代码。</td></tr><tr><td><tt class="literal">KEY_TAB</tt></td><td><tt class="literal">Number</tt></td><td>9: 常量，Tab键的代码。</td></tr><tr><td><tt class="literal">KEY_RETURN</tt></td><td><tt class="literal">Number</tt></td><td>13: 常量，回车键的代码。</td></tr><tr><td><tt class="literal">KEY_ESC</tt></td><td><tt class="literal">Number</tt></td><td>27: 常量， Esc键的代码。</td></tr><tr><td><tt class="literal">KEY_LEFT</tt></td><td><tt class="literal">Number</tt></td><td>37: 常量，左箭头键的代码。</td></tr><tr><td><tt class="literal">KEY_UP</tt></td><td><tt class="literal">Number</tt></td><td>38: 常量，上箭头键的代码。</td></tr><tr><td><tt class="literal">KEY_RIGHT</tt></td><td><tt class="literal">Number</tt></td><td>39: 常量，右箭头键的代码。</td></tr><tr><td><tt class="literal">KEY_DOWN</tt></td><td><tt class="literal">Number</tt></td><td>40: 常量，下箭头键的代码。</td></tr><tr><td><tt class="literal">KEY_DELETE</tt></td><td><tt class="literal">Number</tt></td><td>46: 常量，删除(Delete)键的代码。</td></tr><tr><td><tt class="literal">observers:</tt></td><td><tt class="literal">Array</tt></td><td><span class="emphasis"><em>缓存的观察者的列表，这个对象内部具体实现的一部分。</em></span></td></tr></tbody></table></div><div class="table"><a name="d0e717"></a><p class="title"><b>Table 7. <tt class="literal">Event</tt> 对象的扩展</b></p><table summary="Event 对象的扩展" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">element(event)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">event</tt>: 事件对象</td><td>返回引发这个事件的元素。</td></tr><tr><td><tt class="literal">isLeftClick(event)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">event</tt>: 事件对象</td><td>如果鼠标左键单击返回true。</td></tr><tr><td><tt class="literal">pointerX(event)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">event</tt>: 事件对象</td><td>返回在页面上x坐标。</td></tr><tr><td><tt class="literal">pointerY(event)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">event</tt>: 事件对象</td><td>返回在页面上y坐标。</td></tr><tr><td><tt class="literal">stop(event)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">event</tt>: 事件对象</td><td>用这个方法来中止事件的默认行为来使事件的传播停止。</td></tr><tr><td><tt class="literal">findElement(event, tagName)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">event</tt>: 事件对象, <tt class="literal">tagName</tt>: 指定标记的名字</td><td>向 DOM 树的上位查找，找到第一个给定标记名称的元素， 从这个元素开始触发事件。</td></tr><tr><td><tt class="literal">observe(element, name, observer, useCapture)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">element</tt>: 对象或者对象id, <tt class="literal">name</tt>: 事件名 (如 'click', 'load', etc), <tt class="literal">observer</tt>: 处理这个事件的方法, <tt class="literal">useCapture</tt>: 如果true, 在捕捉到事件的阶段处理事件 那么如果 false在<span class="emphasis"><em>bubbling</em></span> 阶段处理。</td><td>加入一个处理事件的方法。</td></tr><tr><td><tt class="literal">stopObserving(element, name, observer, useCapture)</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">element</tt>: 对象或者对象id, <tt class="literal">name</tt>: 事件名 (如 'click', 'load', etc), <tt class="literal">observer</tt>: 处理这个事件的方法, <tt class="literal">useCapture</tt>: 如果true, 在捕捉到事件的阶段处理事件 那么如果 false在<span class="emphasis"><em>bubbling</em></span> 阶段处理。</td><td>删除一个处理实践的方法。</td></tr><tr><td><tt class="literal">_observeAndCache( element, name, observer, useCapture)</tt></td><td><tt class="literal">static</tt></td><td> </td><td>私有方法，不用管它。</td></tr><tr><td><tt class="literal">unloadCache()</tt></td><td><tt class="literal">static</tt></td><td><tt class="literal">(none)</tt></td><td>私有方法，不用管它。清除内存中的多有观察着缓存。</td></tr></tbody></table></div><p>让我们看看怎样用这个对象加入处理 <tt class="literal">window</tt> 对象的<tt class="literal">load</tt>事件的处理方法。</p><pre class="programlisting">&lt;script&gt;
    <span class="bold"><b>Event.observe(window, 'load', showMessage, false);</b></span>

    function showMessage() {
      alert('Page loaded.');
    }
&lt;/script&gt;</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e903"></a>4.8. 在 prototype.js中定义的新对象和类</h3></div></div><div></div></div><p>另一个这个程序包帮助你的地方就是提供许多既支持面向对象设计理念又有共通功能的许多对象。</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e908"></a>4.9. <tt class="literal">PeriodicalExecuter</tt> 对象</h3></div></div><div></div></div><p>这个对象提供一定间隔时间上重复调用一个方法的逻辑。</p><div class="table"><a name="d0e916"></a><p class="title"><b>Table 8. <tt class="literal">PeriodicalExecuter</tt> 对象</b></p><table summary="PeriodicalExecuter 对象" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](callback, interval)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">callback</tt>: 没有参数的方法, <tt class="literal">interval</tt>: 秒数</td><td>创建这个对象的实例将会重复调用给定的方法。</td></tr></tbody></table></div><div class="table"><a name="d0e953"></a><p class="title"><b>Table 9. <tt class="literal">PeriodicalExecuter</tt> 对象</b></p><table summary="PeriodicalExecuter 对象" border="1"><colgroup><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">callback</tt></td><td><tt class="literal">Function()</tt></td><td>被调用的方法，该方法不会被传入参数。</td></tr><tr><td><tt class="literal">frequency</tt></td><td><tt class="literal">Number</tt></td><td>以秒为单位的间隔。</td></tr><tr><td><tt class="literal">currentlyExecuting</tt></td><td><tt class="literal">Boolean</tt></td><td>表示这个方法是否正在执行。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e998"></a>4.10. <tt class="literal">Prototype</tt> 对象</h3></div></div><div></div></div><p><tt class="literal">Prototype</tt> 没有太重要的作用，只是声明了该程序包的版本 。</p><div class="table"><a name="d0e1008"></a><p class="title"><b>Table 10. The Prototype object</b></p><table summary="The Prototype object" border="1"><colgroup><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">Version</tt></td><td><tt class="literal">String</tt></td><td>包的版本。</td></tr><tr><td><tt class="literal">emptyFunction</tt></td><td><tt class="literal">Function()</tt></td><td>空方法对象。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1042"></a>4.11. <tt class="literal">Class</tt> 对象</h3></div></div><div></div></div><p>在这个程序包中 <tt class="literal">Class</tt> 对象在声明其他的类时候被用到 。用这个对象声明类使得新类支持 <tt class="literal">initialize()</tt> 方法，他起构造方法的作用。</p><p>看下面的例子</p><pre class="programlisting">//declaring the class
<span class="bold"><b>var MySampleClass = Class.create();</b></span>
//defining the rest of the class implmentation
MySampleClass.prototype = {

   initialize: function(message) {
        this.message = message;
   },

   showMessage: function(ajaxResponse) {
      alert(this.message);
   }
};

//now, let's instantiate and use one object
var myTalker = new MySampleClass('hi there.');
myTalker.showMessage(); //displays alert</pre><div class="table"><a name="d0e1063"></a><p class="title"><b>Table 11. <tt class="literal">Class</tt> 对象</b></p><table summary="Class 对象" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">create(*)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(any)</tt></td><td>定义新类的构造方法。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1096"></a>4.12. <tt class="literal">Ajax</tt> 对象</h3></div></div><div></div></div><p>这个对象被用作其他提供AJAX功能的类的根对象。</p><div class="table"><a name="d0e1104"></a><p class="title"><b>Table 12. <tt class="literal">Ajax</tt> 对象</b></p><table summary="Ajax 对象" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">getTransport()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>返回新的<tt class="literal">XMLHttpRequest</tt> 对象。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ajax_base"></a>4.13. <tt class="literal">Ajax.Base</tt> 类</h3></div></div><div></div></div><p>这个类是其他在Ajax对象中定义的类的基类。</p><div class="table"><a name="d0e1148"></a><p class="title"><b>Table 13. Ajax.Base 类</b></p><table summary="Ajax.Base 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">setOptions(options)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">options</tt>: <a title="4.15. options 参数对象" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#options_reference">AJAX 选项</a></td><td>设定AJAX操作想要的选项。</td></tr><tr><td><tt class="literal">responseIsSuccess()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>返回 <tt class="literal">true</tt> 如果AJAX操作成功,否则为 <tt class="literal">false</tt> 。</td></tr><tr><td><tt class="literal">responseIsFailure()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>与 <tt class="literal">responseIsSuccess()</tt> 相反。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ajax_request_reference"></a>4.14. <tt class="literal">Ajax.Request</tt> 类</h3></div></div><div></div></div><p>继承自 <a title="4.13. Ajax.Base 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_base"><tt class="literal">Ajax.Base</tt></a></p><p>封装 AJAX 操作</p><div class="table"><a name="d0e1228"></a><p class="title"><b>Table 14. <tt class="literal">Ajax.Request</tt> 类</b></p><table summary="Ajax.Request 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">类别</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">Events</tt></td><td><tt class="literal">Array</tt></td><td><tt class="literal">static</tt></td><td>在AJAX操作中所有可能报告的事件/状态的列表。这个列表包括: <tt class="literal">'Uninitialized', 'Loading', 'Loaded', 'Interactive', </tt>和 <tt class="literal">'Complete'</tt>。</td></tr><tr><td><tt class="literal">transport</tt></td><td><tt class="literal">XMLHttpRequest</tt></td><td><tt class="literal">instance</tt></td><td>携带AJAX操作的 <tt class="literal">XMLHttpRequest</tt> 对象。</td></tr></tbody></table></div><div class="table"><a name="d0e1282"></a><p class="title"><b>Table 15. <tt class="literal">Ajax.Request</tt> 类</b></p><table summary="Ajax.Request 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](url, options)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">url</tt>: 请求的url, <tt class="literal">options</tt>: AJAX 选项</td><td>创建这个对象的一个实例，它将在给定的选项下请求url。 <span class="bold"><b>重要：</b></span>如果选择的url受到浏览器的安全设置，他会一点作用也不起。 很多情况下，浏览器不会请求与当前页面不同主机(域名)的url。 你最好只使用本地url来避免限制用户配置他们的浏览器(谢谢Clay)</td></tr><tr><td><tt class="literal">request(url)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">url</tt>: AJAX 请求的url</td><td>这个方法通常不会被外部调用。已经在构造方法中调用了。</td></tr><tr><td><tt class="literal">setRequestHeaders()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>这个方法通常不会被外部调用。 被这个对象自己调用来配置在HTTP请求要发送的HTTP报头。</td></tr><tr><td><tt class="literal">onStateChange()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>这个方法通常不会被外部调用。 当AJAX请求状态改变的时候被这个对象自己调用。</td></tr><tr><td><tt class="literal">respondToReadyState(readyState)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">readyState</tt>: 状态数字 (1 到 4)</td><td>这个方法通常不会被外部调用。 当AJAX请求状态改变的时候被这个对象自己调用。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="options_reference"></a>4.15. <tt class="literal">options</tt> 参数对象</h3></div></div><div></div></div><p>AJAX操作中一个重要的部分就是 <tt class="literal">options</tt> 参数。 本质上没有options类。任何对象都可以被传入，只要带有需要的属性。通常会只为了AJAX调用创建匿名类。</p><div class="table"><a name="d0e1383"></a><p class="title"><b>Table 16. <tt class="literal">options</tt> 参数对象</b></p><table summary="options 参数对象" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">Default</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">method</tt></td><td><tt class="literal">Array</tt></td><td><tt class="literal">'post'</tt></td><td>HTTP 请求方式。</td></tr><tr><td><tt class="literal">parameters</tt></td><td><tt class="literal">String</tt></td><td><tt class="literal">''</tt></td><td>在HTTP请求中传入的url格式的值列表。</td></tr><tr><td><tt class="literal">asynchronous</tt></td><td><tt class="literal">Boolean</tt></td><td><tt class="literal">true</tt></td><td>指定是否做异步 AJAX 请求。</td></tr><tr><td><tt class="literal">postBody</tt></td><td><tt class="literal">String</tt></td><td><tt class="literal">undefined</tt></td><td>在HTTP POST的情况下，传入请求体中的内容。</td></tr><tr><td><tt class="literal">requestHeaders</tt></td><td><tt class="literal">Array</tt></td><td><tt class="literal">undefined</tt></td><td>和请求一起被传入的HTTP头部列表， 这个列表必须含有偶数个项目， 任何奇数项目是自定义的头部的名称， 接下来的偶数项目使这个头部项目的字符串值。 例子:<tt class="literal">['my-header1', 'this is the value', 'my-other-header', 'another value']</tt></td></tr><tr><td><tt class="literal">onXXXXXXXX</tt></td><td><tt class="literal">Function(XMLHttpRequest)</tt></td><td><tt class="literal">undefined</tt></td><td>在AJAX请求中，当相应的事件/状态形成的时候调用的自定义方法。 例如 <tt class="literal">var myOpts = {onComplete: showResponse, onLoaded: registerLoaded};</tt>. 这个方法将被传入一个参数， 这个参数是携带AJAX操作的 <tt class="literal">XMLHttpRequest</tt>对象。</td></tr><tr><td><tt class="literal">onSuccess</tt></td><td><tt class="literal">Function(XMLHttpRequest)</tt></td><td><tt class="literal">undefined</tt></td><td>当AJAX请求成功完成的时候调用的自定义方法。 这个方法将被传入一个参数， 这个参数是携带AJAX操作的 <tt class="literal">XMLHttpRequest</tt>对象。</td></tr><tr><td><tt class="literal">onFailure</tt></td><td><tt class="literal">Function(XMLHttpRequest)</tt></td><td><tt class="literal">undefined</tt></td><td>当AJAX请求完成但出现错误的时候调用的自定义方法。 这个方法将被传入一个参数， 这个参数是携带AJAX操作的 <tt class="literal">XMLHttpRequest</tt>对象。</td></tr><tr><td><tt class="literal">insertion</tt></td><td><tt class="literal">Function(Object, String)</tt></td><td><tt class="literal">null</tt></td><td>为了把返回的文本注入到一个元素中而执行的方法。 这个方法将被传入两个参数，要被更新的对象并且只应用于 <tt class="literal"><a title="4.16. Ajax.Updater 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_updater_reference">Ajax.Updater</a></tt>的响应文本 。</td></tr><tr><td><tt class="literal">evalScripts</tt></td><td><tt class="literal">Boolean</tt></td><td><tt class="literal">undefined, false</tt></td><td>决定当响应到达的时候是否执行其中的脚本块，只在 <a title="4.16. Ajax.Updater 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_updater_reference"><tt class="literal">Ajax.Updater</tt></a> 对象中应用。</td></tr><tr><td><tt class="literal">decay</tt></td><td><tt class="literal">Number</tt></td><td><tt class="literal">undefined, 1</tt></td><td>决定当最后一次响应和前一次响应相同时在 <a title="4.17. Ajax.PeriodicalUpdater 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_periodical_updater"><tt class="literal">Ajax.PeriodicalUpdater</tt></a> 对象中的减漫访问的次数， 例如，如果设为2，后来的刷新和之前的结果一样， 这个对象将等待2个设定的时间间隔进行下一次刷新， 如果又一次一样， 那么将等待4次，等等。 不设定这个只，或者设置为1，将避免访问频率变慢。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ajax_updater_reference"></a>4.16. <tt class="literal">Ajax.Updater</tt> 类</h3></div></div><div></div></div><p>继承自 <tt class="literal"><a title="4.14. Ajax.Request 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_request_reference">Ajax.Request</a></tt></p><p>当请求的url返回一段HTML而你想把它直接放置到页面中一个特定的元素的时候被用到。 如果url的返回<tt class="literal">&lt;script&gt;</tt> 的块并且想在接收到时就执行它的时候也可以使用该对象。含有脚本的时候使用 <tt class="literal">evalScripts</tt> 选项。</p><div class="table"><a name="d0e1581"></a><p class="title"><b>Table 17. <tt class="literal">Ajax.Updater</tt> 类</b></p><table summary="Ajax.Updater 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">类别</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">ScriptFragment</tt></td><td><tt class="literal">String</tt></td><td><tt class="literal">static</tt></td><td>可以判断是否为脚本的正则表达式。</td></tr><tr><td><tt class="literal">containers</tt></td><td><tt class="literal">Object</tt></td><td><tt class="literal">instance</tt></td><td>这个对象包含两个属性:AJAX请求成功执行的时候用到 <tt class="literal">containers.success</tt> , 否则的话用到 <tt class="literal">containers.failure</tt> 。</td></tr></tbody></table></div><div class="table"><a name="d0e1632"></a><p class="title"><b>Table 18. <tt class="literal">Ajax.Updater</tt> 类</b></p><table summary="Ajax.Updater 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](container, url, options)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">container</tt>:可以是元素的id, 也可以是元素自己, 或者可以是带有2个属性的对象 - <span class="bold"><b>object.success</b></span> AJAX请求成功的时候用到的元素(或者id) 否则用到<span class="bold"><b>object.failure</b></span> 中设定的元素(或id) <tt class="literal">,url</tt>: 请求的url, <tt class="literal">options</tt>: <a title="4.15. options 参数对象" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#options_reference">AJAX 选项</a></td><td>创建一个用给定的选项请求给定的url的一个实例。</td></tr><tr><td><tt class="literal">updateContent()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>这个方法通常不会被外部调用。 当响应到达的时候，被这个对象自己调用。 它会用HTML更新适当的元素或者调用在 <tt class="literal">insertion</tt> 选项中传入的方法-这个方法将被传入两个参数， 被更新的元素和响应文本。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ajax_periodical_updater"></a>4.17. <tt class="literal">Ajax.PeriodicalUpdater</tt> 类</h3></div></div><div></div></div><p>继承自 <a title="4.13. Ajax.Base 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_base"><tt class="literal">Ajax.Base</tt></a></p><p>这个类重复生成并使用 <tt class="literal">Ajax.Updater </tt>对象来刷新页面中的一个元素。或者执行 Ajax.Updater 可以执行的其它任务。更多信息参照 <a title="4.16. Ajax.Updater 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_updater_reference">Ajax.Updater 参考</a> 。</p><div class="table"><a name="d0e1714"></a><p class="title"><b>Table 19. <tt class="literal">Ajax.PeriodicalUpdater</tt> 类</b></p><table summary="Ajax.PeriodicalUpdater 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">类别</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">container</tt></td><td><tt class="literal">Object</tt></td><td><tt class="literal">instance</tt></td><td>这个值将直接传入<tt class="literal">Ajax.Updater</tt>的构造方法。</td></tr><tr><td><tt class="literal">url</tt></td><td><tt class="literal">String</tt></td><td><tt class="literal">instance</tt></td><td>这个值将直接传入<tt class="literal">Ajax.Updater</tt>的构造方法。</td></tr><tr><td><tt class="literal">frequency</tt></td><td><tt class="literal">Number</tt></td><td><tt class="literal">instance</tt></td><td>两次刷新之间的间隔 (不是频率) ，以秒为单位。 默认2秒。 This 当调用 <tt class="literal">Ajax.Updater</tt> 对象的时候，这个数将和当前的 <tt class="literal">decay</tt> 相乘。</td></tr><tr><td><tt class="literal">decay</tt></td><td><tt class="literal">Number</tt></td><td><tt class="literal">instance</tt></td><td>重负执行任务的时候保持的衰败水平。</td></tr><tr><td><tt class="literal">updater</tt></td><td><tt class="literal"><a title="4.16. Ajax.Updater 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#ajax_updater_reference">Ajax.Updater</a></tt></td><td><tt class="literal">instance</tt></td><td>最后一次使用的 <tt class="literal">Ajax.Updater </tt>对象</td></tr><tr><td><tt class="literal">timer</tt></td><td><tt class="literal">Object</tt></td><td><tt class="literal">instance</tt></td><td>通知对象该下一次更新时用到的JavaScript 计时器。</td></tr></tbody></table></div><div class="table"><a name="d0e1823"></a><p class="title"><b>Table 20. <tt class="literal">Ajax.PeriodicalUpdater</tt> 类</b></p><table summary="Ajax.PeriodicalUpdater 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](container, url, options)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">container</tt>:可以是元素的id, 也可以是元素自己, 或者可以是带有2个属性的对象 - <span class="bold"><b>object.success</b></span> AJAX请求成功的时候用到的元素(或者id) 否则用到<span class="bold"><b>object.failure</b></span> 中设定的元素(或id) <tt class="literal">,url</tt>: 请求的url, <tt class="literal">options</tt>: <a title="4.15. options 参数对象" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#options_reference">AJAX 选项</a></td><td>创建一个用给定的选项请求给定的url的一个实例。</td></tr><tr><td><tt class="literal">start()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>这个方法通常不会被外部调用。 对象为了开始周期性执行任务的时候调用的方法。</td></tr><tr><td><tt class="literal">stop()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>这个方法通常不会被外部调用。 对象为了停止周期性执行任务的时候调用的方法。</td></tr><tr><td><tt class="literal">updateComplete()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>这个方法通常不会被外部调用。 被当前的 <tt class="literal">Ajax.Updater </tt>使用，当一次请求结束的时候，它被用作计划下一次请求。</td></tr><tr><td><tt class="literal">onTimerEvent()</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">(none)</tt></td><td>这个方法通常不会被外部调用。当到下一次更新时被内部调用。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1922"></a>4.18. <tt class="literal">Element</tt> 对象</h3></div></div><div></div></div><p>这个对象提供在操作DOM中元素时使用的功能性方法。</p><div class="table"><a name="d0e1930"></a><p class="title"><b>Table 21. <tt class="literal">Element</tt> 对象</b></p><table summary="Element 对象" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">toggle(elem1 [, elem2 [, elem3 [...]]])</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">elemN</tt>: 元素对象或id</td><td>切换每一个传入元素的可视性。</td></tr><tr><td><tt class="literal">hide(elem1 [, elem2 [, elem3 [...]]])</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">elemN</tt>: 元素对象或id</td><td>用设定它的 <tt class="literal">style.display</tt> 为 <tt class="literal">'none'</tt>来隐藏每个传入的元素。</td></tr><tr><td><tt class="literal">show(elem1 [, elem2 [, Slem3 [...]]])</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">elemN</tt>: 元素对象或id</td><td>用设定它的 <tt class="literal">style.display </tt>为 <tt class="literal">''</tt>来显示每个传入的元素。</td></tr><tr><td><tt class="literal">remove(element)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">element</tt>: 元素对象或id</td><td>从document对象中删除指定的元素。</td></tr><tr><td><tt class="literal">getHeight(element)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">element</tt>: 元素对象或id</td><td>返回元素的 <tt class="literal">offsetHeight</tt> 。</td></tr><tr><td><tt class="literal">addClassName( element, className)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">className</tt>: CSS类名</td><td>向元素的类名中加入给定的类名。</td></tr><tr><td><tt class="literal">hasClassName( element, className)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">className</tt>: CSS类名</td><td>返回 <tt class="literal">true</tt> 如果元素的类名中含有给定的类名</td></tr><tr><td><tt class="literal">removeClassName( element, className)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">className</tt>: CSS类名</td><td>从元素的类名中删除给定的类名。</td></tr><tr><td><tt class="literal">cleanWhitespace( element )</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">element</tt>: 元素对象或id</td><td>删除该元素的所有只含有空格的子节点。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2095"></a>4.19. <tt class="literal">Abstract</tt> 对象</h3></div></div><div></div></div><p>这个对象是这个程序包中其他类的根。它没有任何属性和方法。在这个对象中定义的类可以被视为传统的抽象类。</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="abstract_insertion"></a>4.20. <tt class="literal">Abstract.Insertion</tt> 类</h3></div></div><div></div></div><p>这个类被用作其他提供动态内容插入功能的类的基类，它像一个抽象类一样被使用。</p><div class="table"><a name="d0e2110"></a><p class="title"><b>Table 22. <tt class="literal">Abstract.Insertion</tt> 类</b></p><table summary="Abstract.Insertion 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](element, content)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">content</tt>: 被插入的HTML</td><td>创建一个可以帮助插入动态内容的对象。</td></tr></tbody></table></div><div class="table"><a name="d0e2147"></a><p class="title"><b>Table 23. <tt class="literal">Abstract.Insertion</tt> 类</b></p><table summary="Abstract.Insertion 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">属性</th><th align="center">类型</th><th align="center">类别</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">adjacency</tt></td><td><tt class="literal">String</tt></td><td><tt class="literal">static, parameter</tt></td><td>这个参数指定相对于给定元素，内容将被放置的位置。 可能的值是: <tt class="literal">'beforeBegin'</tt>, <tt class="literal">'afterBegin'</tt>, <tt class="literal">'beforeEnd'</tt>, 和 <tt class="literal">'afterEnd'</tt>.</td></tr><tr><td><tt class="literal">element</tt></td><td><tt class="literal">Object</tt></td><td><tt class="literal">instance</tt></td><td>与插入物做参照元素对象。</td></tr><tr><td><tt class="literal">content</tt></td><td><tt class="literal">String</tt></td><td><tt class="literal">instance</tt></td><td>被插入的 HTML 。</td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2216"></a>4.21. <tt class="literal">Insertion</tt> 对象</h3></div></div><div></div></div><p>这个对象是其他类似功能的根。它没有任何属性和方法。在这个对象中定义的类仍然可以被视为传统的抽象类。</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2223"></a>4.22. <tt class="literal">Insertion.Before</tt> 类</h3></div></div><div></div></div><p>继承自 <tt class="literal"><a title="4.20. Abstract.Insertion 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#abstract_insertion">Abstract.Insertion</a></tt></p><p>在给定元素开始标记的前面插入HTML。</p><div class="table"><a name="d0e2236"></a><p class="title"><b>Table 24. <tt class="literal">Insertion.Before</tt> 类</b></p><table summary="Insertion.Before 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](element, content)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">content</tt>: 被插入的HTML</td><td>继承自 <tt class="literal">Abstract.Insertion</tt>. 创建一个可以帮助插入动态内容的对象。</td></tr></tbody></table></div><p>下面的代码</p><pre class="programlisting">&lt;br&gt;Hello, &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;Wiggum. How's it going?&lt;/span&gt;

&lt;script&gt; <span class="bold"><b>new Insertion.Before('person', 'Chief ');</b></span> &lt;/script&gt;</pre><p>将把 HTML 变为</p><pre class="programlisting">&lt;br&gt;Hello, <span class="bold"><b>Chief</b></span> &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;Wiggum. How's it going?&lt;/span&gt;</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2289"></a>4.23. <tt class="literal">Insertion.Top</tt> 类</h3></div></div><div></div></div><p>继承自 <tt class="literal"><a title="4.20. Abstract.Insertion 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#abstract_insertion">Abstract.Insertion</a></tt></p><p>在给定元素第一个子节点位置插入 HTML。内容将位于元素的开始标记的紧后面。</p><div class="table"><a name="d0e2302"></a><p class="title"><b>Table 25. <tt class="literal">Insertion.Top</tt> 类</b></p><table summary="Insertion.Top 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](element, content)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">content</tt>: 被插入的HTML</td><td>继承自 <tt class="literal">Abstract.Insertion</tt>. 创建一个可以帮助插入动态内容的对象。</td></tr></tbody></table></div><p>下面的代码</p><pre class="programlisting">&lt;br&gt;Hello, &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;Wiggum. How's it going?&lt;/span&gt;

&lt;script&gt; <span class="bold"><b>new Insertion.Top('person', 'Mr. ');</b></span> &lt;/script&gt;</pre><p>将把 HTML 变为</p><pre class="programlisting">&lt;br&gt;Hello, &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;<span class="bold"><b>Mr.</b></span> Wiggum. How's it going?&lt;/span&gt;</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2355"></a>4.24. <tt class="literal">Insertion.Bottom</tt> 类</h3></div></div><div></div></div><p>继承自 <tt class="literal"><a title="4.20. Abstract.Insertion 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#abstract_insertion">Abstract.Insertion</a></tt></p><p>在给定元素最后一个子节点位置插入 HTML。内容将位于元素的结束标记的紧前面。</p><div class="table"><a name="d0e2368"></a><p class="title"><b>Table 26. <tt class="literal">Insertion.Bottom</tt> 类</b></p><table summary="Insertion.Bottom 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](element, content)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">content</tt>: 被插入的HTML</td><td>继承自 <tt class="literal">Abstract.Insertion</tt>. 创建一个可以帮助插入动态内容的对象。</td></tr></tbody></table></div><p>下面的代码</p><pre class="programlisting">&lt;br&gt;Hello, &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;Wiggum. How's it going?&lt;/span&gt;

&lt;script&gt; <span class="bold"><b>new Insertion.Bottom('person', &quot; What's up?&quot;);</b></span> &lt;/script&gt;</pre><p>将把 HTML 变为</p><pre class="programlisting">&lt;br&gt;Hello, &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;Wiggum. How's it going? <span class="bold"><b>What's up?</b></span>&lt;/span&gt;</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2421"></a>4.25. <tt class="literal">Insertion.After</tt> 类</h3></div></div><div></div></div><p>继承自 <tt class="literal"><a title="4.20. Abstract.Insertion 类" href="https://compdoc2cn.dev.java.net/prototype/html/prototype.js.cn.html#abstract_insertion">Abstract.Insertion</a></tt></p><p>在给定元素结束标记的后面插入HTML。</p><div class="table"><a name="d0e2434"></a><p class="title"><b>Table 27. <tt class="literal">Insertion.After</tt> 类</b></p><table summary="Insertion.After 类" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">[ctor](element, content)</tt></td><td><tt class="literal">constructor</tt></td><td><tt class="literal">element</tt>: 元素对象或id, <tt class="literal">content</tt>: 被插入的HTML</td><td>继承自 <tt class="literal">Abstract.Insertion</tt>. 创建一个可以帮助插入动态内容的对象。</td></tr></tbody></table></div><p>下面的代码</p><pre class="programlisting">&lt;br&gt;Hello, &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;Wiggum. How's it going?&lt;/span&gt;

&lt;script&gt; <span class="bold"><b>new Insertion.After('person', ' Are you there?');</b></span> &lt;/script&gt;</pre><p>将把 HTML 变为</p><pre class="programlisting">&lt;br&gt;Hello, &lt;span id=&quot;person&quot; style=&quot;color:red;&quot;&gt;Wiggum. How's it going?&lt;/span&gt; <span class="bold"><b>Are you there?</b></span></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2486"></a>4.26. <tt class="literal">Field</tt> 对象</h3></div></div><div></div></div><p>这个对象提供操作表单中的输入项目的功能性方法。</p><div class="table"><a name="d0e2494"></a><p class="title"><b>Table 28. <tt class="literal">Field</tt> 对象</b></p><table summary="Field 对象" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th align="center">方法</th><th align="center">类别</th><th align="center">参数</th><th align="center">描述</th></tr></thead><tbody><tr><td><tt class="literal">clear(field1 [, field2 [, field3 [...]]])</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">fieldN</tt>: 元素对象或id</td><td>清除传入表单中项目元素的值。</td></tr><tr><td><tt class="literal">present(field1 [, field2 [, field3 [...]]])</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">fieldN</tt>: 元素对象或id</td><td>只有在所有的表单项目都不为空时返回 <tt class="literal">true</tt> 。</td></tr><tr><td><tt class="literal">focus(field)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">fieldN</tt>: 元素对象或id</td><td>移动焦点到给定的表单项目。</td></tr><tr><td><tt class="literal">select(field)</tt></td><td><tt class="literal">instance</tt></td><td><tt class="literal">fieldN</tt>: 元素对象或id</td><td>选择支持项目值选择的表单<!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2067682.html">Apache学习笔记</a> 2006-03-15</div><div><a href="/logs/1750121.html">留言版留言自动折行问题</a> 2005-12-26</div><div><a href="/logs/1711786.html">常用注册表修改</a> 2005-12-16</div><div><a href="/logs/1564360.html">在unix上让apache支持asp</a> 2005-11-04</div><div><a href="/logs/1538957.html">Apache James用户信息的数据库存储和密码问题</a> 2005-10-26</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F1762340.html&title=prototype.js%E5%BC%80%E5%8F%91%E7%AC%94%E8%AE%B0">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://icity.cn" target="_blank">《城客》：第一本中文互动杂志！</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/1762340.html</link>
   <author>panbird</author>
   <pubDate>Thu, 29 Dec 2005 09:38:52 +0800</pubDate>
  </item>
  <item>
   <title>留言版留言自动折行问题</title>
   <description><![CDATA[<P>很多留言类似111111111111。。。。。。。</P>
<P>加上style=" table-layout:fixed;word-break：break-all" 可以解决折行问题</P><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2081878.html">从LiveJournal后台发展看大规模网站性能优化方法</a> 2006-03-17</div><div><a href="/logs/2067682.html">Apache学习笔记</a> 2006-03-15</div><div><a href="/logs/1771287.html">Lucene倒排索引原理</a> 2005-12-31</div><div><a href="/logs/1762340.html">prototype.js开发笔记</a> 2005-12-29</div><div><a href="/logs/1564360.html">在unix上让apache支持asp</a> 2005-11-04</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F1750121.html&title=%E7%95%99%E8%A8%80%E7%89%88%E7%95%99%E8%A8%80%E8%87%AA%E5%8A%A8%E6%8A%98%E8%A1%8C%E9%97%AE%E9%A2%98">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://pindao.blogbus.com/shenghuo?utm_source=blogbus&utm_medium=rss&utm_campaign=shenghuo" target="_blank">生活频道——笑谈生活，坐看人生，这里有着小人物的健康生活。</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/1750121.html</link>
   <author>panbird</author>
   <pubDate>Mon, 26 Dec 2005 11:46:47 +0800</pubDate>
  </item>
  <item>
   <title>IBM快捷热键表　</title>
   <description><![CDATA[IBM快捷热键表　<p><br />　　Fn+F3：关闭屏幕，StandBy模式（待机），显示器、硬盘、音频被关闭，移动鼠标或按任意键解除。　 <br />　　Fn+F4：进入待机，Suspend模式（挂起），所有的任务都被停止并且保存到内存中，除了内存之外所有的设备都被停止，按下Fn键一秒钟以上解除。　 <br />　　Fn+F7：切换显示输出（LCD，或外接，或同时显示），这是一个循环转换的过程。　 <br />　　Fn+12：Hibernate模式（休眠），所有的任务被停止，并且内存和当前状态被保存到硬盘中，系统关机。　 <br />　　Fn+Home/End：增大/减少屏幕亮度，共有七档。　 <br />　　Fn+PgUp：开关屏幕灯。　 <br />　　某些机型按Fn+F3不能关闭屏幕</p><p>　 <br />　　在一些机型上如T22，运行WIN2000时按Fn+F3不能关闭屏幕，主要原因是Modem的驱动程序版本太低，把它升级到5.95以上通常会解决问题<br /></p><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2471201.html">程序员创业三关</a> 2006-05-14</div><div><a href="/logs/2081878.html">从LiveJournal后台发展看大规模网站性能优化方法</a> 2006-03-17</div><div><a href="/logs/1750121.html">留言版留言自动折行问题</a> 2005-12-26</div><div><a href="/logs/1524534.html">Apache 服务器 Log 分析应用实例</a> 2005-10-21</div><div><a href="/logs/1524526.html">日志文件分析工具—AWStats在IIS中的配置步骤</a> 2005-10-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F1733000.html&title=IBM%E5%BF%AB%E6%8D%B7%E7%83%AD%E9%94%AE%E8%A1%A8%E3%80%80">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://tuijian.blogbus.com/" target="_blank">推荐：让我们寻找最优秀的Blogger！</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/1733000.html</link>
   <author>panbird</author>
   <pubDate>Wed, 21 Dec 2005 20:58:44 +0800</pubDate>
  </item>
  <item>
   <title>常用注册表修改</title>
   <description><![CDATA[<br />--------------------------------------------------------------------------------<br />-<br />REGEDIT4<br /><br />;恢复IE的标题及主页<br />[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main]<br />&quot;Window Title&quot;=&quot;Internet Explorer&quot;<br />&quot;Start Page&quot;=&quot;about:blank&quot;<br />&quot;Local Page&quot;=&quot;about:blank&quot;<br />&quot;Search Page&quot;=&quot;about:blank&quot;<br />&quot;First Home Page&quot;=-<br />&quot;ChannelsFirstURL&quot;=-<br />&quot;ChannelsURL&quot;=-<br />&quot;Search Bar&quot;=-<br />&quot;Default_Search_URL&quot;=-<br />&quot;Default_Page_URL&quot;=-<br /><br />[HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main]<br />&quot;Window Title&quot;=&quot;Internet Explorer&quot;<br />&quot;Start Page&quot;=&quot;about:blank&quot;<br />&quot;Default_Page_URL&quot;=&quot;about:blank&quot;<br />&quot;Default_Search_URL&quot;= &quot;about:blank&quot;<br />&quot;Local Page&quot;=&quot;about:blank&quot;<br />&quot;Search Page&quot;=&quot;about:blank&quot;<br /><br /><br />;清除IE的“分级审查”密码<br />[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Ratings]<br />&quot;Key&quot;=-<br /><br /><br />;恢复右键菜单功能（多种）<br />[HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions] <br />&quot;NoBrowserContextMenu&quot;=dword:00000000<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoChangeStartMenu&quot;=dword:00000000<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoTrayContextMenu&quot;=dword:00000000<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoViewContextMenu&quot;=dword:00000000<br /><br />;解除IE的“Internet选项”及其对话框中所有属性设置的禁用<br />[HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]<br />&quot;NoBrowserOptions&quot;=dword:00000000<br /><br />[HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Restrictions]<br />&quot;NoBrowserOptions&quot;=dword:00000000<br /><br />[-HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Control Panel]<br /><br /><br />;解除资源管理器“文件夹选项”的禁用<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoFolderOptions&quot;=dword:00000000<br /><br /><br />;解除“开始”菜单中的各种屏蔽<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoRun&quot;=dword:00000000<br />&quot;NoFind&quot;=dword:00000000<br />&quot;NoClose&quot;=dword:00000000<br />&quot;NoFavoritesMenu&quot;=dword:00000000<br />&quot;NoSetFolders&quot;=dword:00000000<br />&quot;NoRecentDocsMenu&quot;=dword:00000000<br />&quot;NoLogOff&quot;=hex:00,00,00,00<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp]<br />&quot;NoRealMode&quot;=dword:00000000<br /><br />;解除“显示属性”及“任务栏属性”的禁用<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]<br />&quot;NoDispCPL&quot;=dword:00000000<br />&quot;NoDisp BackgroundPage&quot;=dword:00000000<br />&quot;NoDispAppearancePage&quot;=dword:00000000<br />&quot;NoDispScrSavPage&quot;=dword:00000000<br />&quot;NoDispSettingsPage&quot;=dword:00000000<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoSetTaskbar&quot;=dword:00000000<br /><br /><br />;解除注册表编辑器的禁用<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]<br />&quot;DisableRegistryTools&quot;=dword:00000000<br /><br /><br />;解除“我的电脑”中驱动器的隐藏<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoDrives&quot;=hex:00,00,00,00<br /><br /><br />;解除桌面的隐藏<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoDesktop&quot;=dword:00000000<br /><br /><br />;解除MS-DOS窗口的限制<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp]<br />&quot;Disabled&quot;=dword:00000000<br /><br />;解除系统属性中“设备管理器”及“性能”的屏蔽<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]<br />&quot;NoDevMgrPage&quot;=dword:00000000<br />&quot;NoFileSysPage&quot;=dword:00000000<br />&quot;NoVirtMemPage&quot;=dword:00000000<br /><br /><br />;解除“网络属性”的禁用及其设置项的屏蔽<br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoNetSetup&quot;=dword:00000000<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Network]<br />&quot;NoEntireNetwork&quot;=dword:00000000<br />&quot;NoNetSetupIDPage&quot;=dword:00000000<br />&quot;NoNetSetupSecurityPage&quot;=dword:00000000<br />&quot;NoWorkgroupContents&quot;=dword:00000000<br />&quot;NoFileSharingControl&quot;=dword:00000000<br /><br /><br /><br /><br />;取消系统启动时的对话框<br />[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Winlogon]<br />&quot;LegalNoticeCaption&quot;=&quot;&quot;<br />&quot;LegalNoticeText&quot;=&quot;&quot;<br /><br />;恢复桌面上IE、“我的文档”等系统级图标<br />[HKEY_LOCAL_MACHINE\Software\CLASSES\CLSID\{871C5380-42A0-1069-A2EA-08002B30309D<br />}\ShellFolder]<br />&quot;Attributes&quot;=dword:00000024<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Documents]<br />&quot;HideMyDocsFolder&quot;=-<br /><br />[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\explorer\Desktop\NameSpace\{450d8fba-ad25-11d0-98a8-0800361b1103}]<br />@=&quot;我的文档&quot;<br /><br />[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\explorer\Desktop\NameSpace\{645FF040-5081-101B-9F08-00AA002F954E}]<br />@=&quot;回收站&quot;<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]<br />&quot;NoNetHood&quot;=dword:00000000<br /><br /><br />;清除“按Web页方式查看活动桌面”里的网址<br />[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Desktop\Components]<br /><br />[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]<br />&quot;ShellState&quot;=-<br /><br /><br />;恢复任务栏中的日期格式<br />[HKEY_CURRENT_USER\Control Panel\International]<br />&quot;sTimeFormat&quot;=&quot;H:mm:ss&quot;<br />&quot;s1159&quot;=&quot;上午&quot;<br />&quot;s2359&quot;=&quot;下午&quot;<br />&quot;iTime&quot;=&quot;0&quot;<br />&quot;iTLZero&quot;=&quot;1&quot;<br />&quot;sTime&quot;=&quot;:&quot;<br /><br /><br />;清除IE右键里多余的菜单<br />[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt]<br /><br /><br />;去掉IE“工具”菜单里多余的选项<br />[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Extensions]<br /><br />[-HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions]<br /><br /><br /><br />;允许导入REG文件<br />[HKEY_LOCAL_MACHINE\Software\Classes\.reg]<br />@=&quot;regfile&quot;<br />[HKEY_LOCAL_MACHINE\Software\Classes\regfile\shell\open\command]<br />@=&quot;regedit.exe \&quot;%1\&quot;&quot;<br /><br />;解除IE的“文件”等菜单里的各项屏蔽<br />[-HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]<br /><br />[-HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Restrictions]<br /><br /><br />;恢复Outlook Express的标题<br />[HKEY_CURRENT_USER\Software\Microsoft\Outlook Express]<br />&quot;WindowTitle&quot;=&quot;&quot;<br /><br />--------------------------------------------------------------------------------<!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/1902017.html">《Squid 中文权威指南》第3章</a> 2006-02-09</div><div><a href="/logs/1771287.html">Lucene倒排索引原理</a> 2005-12-31</div><div><a href="/logs/1762340.html">prototype.js开发笔记</a> 2005-12-29</div><div><a href="/logs/1564360.html">在unix上让apache支持asp</a> 2005-11-04</div><div><a href="/logs/1501159.html">容错wget脚本</a> 2005-10-12</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fpanbird.blogbus.com%2Flogs%2F1711786.html&title=%E5%B8%B8%E7%94%A8%E6%B3%A8%E5%86%8C%E8%A1%A8%E4%BF%AE%E6%94%B9">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://icity.cn" target="_blank">《城客》：第一本中文互动杂志！</a></b></div><br /><br />]]></description>
   <link>http://panbird.blogbus.com/logs/1711786.html</link>
   <author>panbird</author>
   <pubDate>Fri, 16 Dec 2005 17:00:16 +0800</pubDate>
  </item>
 </channel>
</rss>
