<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>jspengxue</title>
    <description></description>
    <link>http://jspengxue.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>国内不谈java----------java即将从中国绝种</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/66356" style="color:red;">http://jspengxue.javaeye.com/blog/66356</a>&nbsp;
          发表时间: 2007年03月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>装载:<a href="http://www.fundinchina.cn ">http://www.fundinchina.cn</a>&nbsp;中国IT信息网</p>
<p>国内不谈java－－会有千万人跳出来和你争嘴的。 <br />
越是如此，我越是不忍心不说出来，越是不不忍心看到在这个 <br />
领域被国外的同行越拉越远－－在硅谷的感受。 <br />
我是96年毕业的,正值java刚出,火气冲天之时。 <br />
我当时是一名C++的狂热者，有着3年的C++经验。 <br />
接触java也仅仅是在作毕业设计的时候用过，对java也算是有了基本了解， <br />
那时的java才jdk1.0，烂的很，连些基本功能都没有，和大家一样， <br />
对java根本就不认可。作完了设计之后，就把java扔到一边去了。自认为C++不错， <br />
还是干自己的老本行吧。毕业时我认为精通C++，并且有java的基础， <br />
算是身怀两种绝技了，在国内的IT（那时还不叫IT）还可以混个明堂出来吧。 <br />
怀着对未来美好的憧憬和对C++的无限的崇拜，我出来闯荡了。 <br />
唉－－出去的情况于我的想法完全两样，delphi,VB漫天飞，C＋＋高不可攀，根本 <br />
无用武之地。我大失所望，可我偏偏又是一个C＋＋偏执狂，要我去改学其它语言， <br />
在我看来简直是对C++的侮辱，也是对我信念的侮辱，是绝对不可能的！对国内失望之余 <br />
， <br />
于是我想到IT技术前沿的美国，于是满怀希望来到到了IT精英汇集的地方－－硅谷。 <br />
我想这下总算可以施展我深藏多年的C＋＋才华了吧。 <br />
我－－再一次的错了－－在硅谷，VB,delphi根本不入流，虽然C++还继续再用， <br />
但是已经是大不如以前了，不过有c++背景的找工作要相对容易些。 <br />
这里，程序员们，大小的managers，chargers只对Java感兴趣。 <br />
没想到，万万没想到。－－这里反微软的气氛很浓， <br />
也许是Sun,Oracle,IBM,AOL等巨头公司的大本营在此的缘由吧。呆过一段时间后， <br />
我发现这里只要是稍大一点的公司，都在同时在维护着几套System， <br />
要一劳永逸的解决这些问题，让这些System无缝的衔接起来， <br />
java是最好的不过的解决方案。 <br />
在这里，个大巨头公司们对java几乎在玩命似的疯狂： <br />
ibm在全球16个java实验室24小时续以奋战，扛着&ldquo;java就是一切&rdquo;的大旗， <br />
投入java的钱不比sun的少；</p>
<p>intel整装待发，全力以赴赶制java芯片，以求在java谋得一席之地； <br />
oracle,Sybase,informix,DB2这些王牌数据库厂商更是纷纷下马， <br />
把java绑定到自己的产品中，提供对java最全面，最直接的支持； <br />
Inprise,BEA,Iona,netscape联盟等一大批系统集成、支援厂商， <br />
也不甘落后，争先恐后的开发自己的java工具、应用服务软件， <br />
目的只有一个，让自己的产品带上一个响亮的&quot;J&quot;字； <br />
cisco,3Com,HP,NEC等一大批网络设备供应商对embed&nbsp;&nbsp;java表现了浓厚的兴趣， <br />
一批又一批的带java接口的智能设备相续涌现出来，在这个市场上的竞争异常激烈，谁 <br />
也不敢怠慢； <br />
sun自己就更不用说了，sun创造了java,但java并非sun的专有，来自巨头们的竞争， <br />
也让sun感到了前所未有的压力，在&ldquo;捍卫java，保卫java,发展java&rdquo;的方针下， <br />
带领巨头们发布了面向不同领域的各个版本：面向PC领域的java2&nbsp;Standard&nbsp;Edition， <br />
<br />
面向企业级计算的Java&nbsp;2&nbsp;Enterprise&nbsp;Edition，面向嵌入式系统的Java2&nbsp;Embedded&nbsp;Ed <br />
ition, <br />
面向智能终端的Personal&nbsp;Java&nbsp;Edition。 <br />
在这样的一种趋势下，迫不得已，只有放下曾经让我无限自豪、热情彭湃的C++－－我心 <br />
爱的C++！ <br />
一边，在国内，是还达不到使用C++这样的高度； <br />
另一边，在硅谷，C++已经丧失了昔日的辉煌。 <br />
感叹万余，痛定思痛－－随即，以着极大的热情投入到java的事业中， <br />
幸好有着C++的功底和以前对java的基本接触，java很快就上手， <br />
来到了java世界里，啊，原来java还可以这么用，这是以前根本没想到的， <br />
以前一直以为自己是个oop行家，这才发现跟java比，简直就是小巫见大巫－－ <br />
oop在java中被运用的炉火纯青，java本是是一个开放的体系，各家厂商都可以 <br />
对她扩展、实现，要维护整个java世界的纯洁，他们采用了一种绝妙的方法， <br />
运用java的100%oop特点，对于规范的定义只是一些接口，而这些接口的实现， <br />
则完全由各个厂家去负责，多么的和谐，多么的完美！理解不了这些，你就根本 <br />
无法理解象EJB,Servlet/JSP,JTA、RMI/IIOP、JNDI,JMS，Jini....这些java新秀的威力 <br />
， <br />
稍大一点的公司（除了Microsoft），无一不对她趋之若宠，源源不断的 <br />
钱财、人力都愿意往这里扔。这仅仅只是个j2ee，也是到目前为止， <br />
业界中最为完美的企业解决方案，就更不用说j2me了， <br />
想做下一代internet接入设备，除了j2me可以说是别无选择，更要命的是她 <br />
完全可以与现有系统紧密的衔接起来...... <br />
...... <br />
－－我并非是想把C＋＋说得一无是处，我本人对C＋＋仍然是有着无比的崇拜， <br />
只是每把刀都有每把刀的用处，在系统、支撑软件领域，C++还是老大， <br />
只是不要把这种老大的思想随处烂放。在应用领域现在是java，不管你承认也好， <br />
否认也罢，辛辛苦苦用C++写的一套Solution才买10万还不到，而java轻松 <br />
就完成的Solution可以卖到几百万，这就是区别；同样，如果仅仅把java当作 <br />
applet，application用在桌面环境中，她的的确确又比任何一种语言都烂。 <br />
我所说的只是国内的环境影响着我们每一个人，当java&nbsp;one&nbsp;2000在美国红红火火的举行 <br />
， <br />
多达4万家公司挤进会场，更是有3000余名专家、学者在会上慷慨陈辞时，而国内还是不 <br />
以为然， <br />
守着以前的老家当，倒是精明的日本人，早就预定了数十个座位； <br />
当个大公司在java的领域里进行惨烈争夺的时候，国内还抱着VB,Delphi&nbsp;枕着C＋＋睡大 <br />
觉。 <br />
&ldquo;java？－－不过是个玩具儿&rdquo;，朋友、兄弟－－我真的再也不想听到这样的话了，也 <br />
许你说这话的时候， <br />
有一丝的快感，但是你应该知道，在你笑得时候，人家国外的同行比你笑得更开心，他 <br />
们是何等的希望 <br />
我们永远都把她当作玩具！ <br />
我真的希望国内的朋友们，到网上去看一看，到国外的公司去看一看，不要被国内的氛 <br />
围、环境所左右。 <br />
我不想再说了，我实在是不忍心看到在这个领域里，被国外的同行越拉越远！－－事实 <br />
上是已经被远远的 <br />
拉在后面！ </p>
<p><font color="#ff0000">装载:<a href="http://www.fundinchina.cn/">http://www.fundinchina.cn</a>&nbsp;中国IT信息网</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/66356#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 29 Mar 2007 12:46:53 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/66356</link>
        <guid>http://jspengxue.javaeye.com/blog/66356</guid>
      </item>
      <item>
        <title>IE,Firefox对Javascript兼容性总结</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/53561" style="color:red;">http://jspengxue.javaeye.com/blog/53561</a>&nbsp;
          发表时间: 2007年02月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          全局文档的动作检测<br /><pre name="code" class="java">try{

	document.attachEvent("onclick",function(){onclick();},false);  // IE使用这个
			
}catch(e){
	document.addEventListener("onclick",function(){onclick();},false);//FireFox
				
}</pre><br /><br /><pre name="code" class="java">try{

	document.attachEvent("触发事件",function(){调用函数;},false);  // IE使用这个
			
}catch(e){
	document.addEventListener("触发事件",function(){调用函数;},false);//FireFox
				
}</pre>
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/53561#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 09 Feb 2007 17:08:10 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/53561</link>
        <guid>http://jspengxue.javaeye.com/blog/53561</guid>
      </item>
      <item>
        <title>炒纸黄金手续费要货比三家</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/51512" style="color:red;">http://jspengxue.javaeye.com/blog/51512</a>&nbsp;
          发表时间: 2007年01月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          晨报讯 昨日工商银行在江苏范围内开通了炒纸黄金，投资者在家中使用网上银行就能享受炒金的乐趣。这样南京市民能炒纸黄金的渠道增加到三家，另外两家分别是建设银行和中国银行。另外炒实物金可以到招商银行买卖高赛尔金条。据了解，目前用人民币炒纸黄金的门槛一般为每笔交易10克，价差就有区别了。中国银行纸黄金在手续费上采取了阶梯式，单笔交易量在200克以下的，单边价差0.5元/克；单笔交易量在200克 2000克，单边价差0.45元/克；单笔交易量在2000克以上，单边价差0.4元/克。以交易150克为例，基准报价是100元/克，那投资者买入价是100.50元/克，卖出价是99.50元/克。<br /><br />[被屏蔽广告] <br /><br />工商银行有关工作人员告诉记者，以6月20日16点时的报价146.7元/克为例，卖出价147.5元/克，不管买入的数量有多少，单边价差为0.4元/克。建设银行人士说：“我们就以报价为准，报价多少买入价就是多少，没有手续费。”有关专家分析说：想选择哪家炒金最优惠恐怕还要货比三家，最好比较一下各家银行的当时报价以及手续费，在报价上各家银行有所不同。工商银行黄金方面的专业人士告诉记者：炒金不是投机，马上大幅上涨的期望值不要过高。虽然金价的长期牛市并未改变，但是由于跌势过猛，市场人气聚集仍需要时间。但总体来说，仍有获利空间。所以此时需要提醒广大市民的是，目前处于震荡调整时段的金市，应作为投资者而不是投机者的心态去进行操作。
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/51512#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 31 Jan 2007 19:53:58 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/51512</link>
        <guid>http://jspengxue.javaeye.com/blog/51512</guid>
      </item>
      <item>
        <title>jsp生成验证码</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/50372" style="color:red;">http://jspengxue.javaeye.com/blog/50372</a>&nbsp;
          发表时间: 2007年01月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">&lt;%@ page contentType="image/jpeg" import="java.awt.*,
java.awt.image.*,java.util.*,javax.imageio.*" %>
&lt;%!
Color getRandColor(int fc,int bc){//给定范围获得随机颜色
Random random = new Random();
if(fc>255) fc=255;
if(bc>255) bc=255;
int r=fc+random.nextInt(bc-fc);
int g=fc+random.nextInt(bc-fc);
int b=fc+random.nextInt(bc-fc);
return new Color(r,g,b);
}
%>
&lt;%
//设置页面不缓存
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
// 在内存中创建图象
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图形上下文
Graphics g = image.getGraphics();
//生成随机类
Random random = new Random();
// 设定背景色
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);
//设定字体
g.setFont(new Font("Times New Roman",Font.PLAIN,18));
//画边框
//g.setColor(new Color());
//g.drawRect(0,0,width-1,height-1);
// 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到
g.setColor(getRandColor(160,200));
for (int i=0;i&lt;155;i++)
{
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x,y,x+xl,y+yl);
}
// 取随机产生的认证码(4位数字)
String sRand="";
for (int i=0;i&lt;4;i++){
String rand=String.valueOf(random.nextInt(10));
sRand+=rand;
// 将认证码显示到图象中
g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
//调用函数出来的颜色相同，可能是因为种子太接近，所以只能直接生成
g.drawString(rand,13*i+6,16);
}
// 将认证码存入SESSION
session.setAttribute("rand",sRand);
// 图象生效
g.dispose();
// 输出图象到页面
ImageIO.write(image, "JPEG", response.getOutputStream());
%></pre>
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/50372#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 25 Jan 2007 13:38:40 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/50372</link>
        <guid>http://jspengxue.javaeye.com/blog/50372</guid>
      </item>
      <item>
        <title>用IFRAME实现网页的内嵌和预载</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/50371" style="color:red;">http://jspengxue.javaeye.com/blog/50371</a>&nbsp;
          发表时间: 2007年01月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在HTM(HTML)文件中是否可以像PHP、ASP文件一样嵌入其他文件呢？下面笔者介绍用iframe来实现的方法。<br /><br />　　iframe元素的功能是在一个文档里内嵌一个文档，创建一个浮动的帧。其部分属性简介如下：<br /><br /><br />　　name：内嵌帧名称<br /><br />　　width：内嵌帧宽度(可用像素值或百分比)<br /><br />　　height：内嵌帧高度(可用像素值或百分比)<br /><br />　　frameborder：内嵌帧边框<br /><br />　　marginwidth：帧内文本的左右页边距<br /><br />　　marginheight：帧内文本的上下页边距<br /><br />　　scrolling：是否出现滚动条(“auto”为自动，“yes”为显示，“no”为不显示)<br /><br />　　src：内嵌入文件的地址<br /><br />　　style：内嵌文档的样式(如设置文档背景等)<br /><br />　　allowtransparency：是否允许透明<br /><br />　　明白了以上属性后，我们可用以下代码实现，在main.htm中把samper.htm文件的内容显示在一个高度为80、宽度为100%、自动显示边框的内嵌帧中：<br /><br />　　〈iframe name="import_frame" width=100%<br /><br />　　　height=80 src="samper.htm" frameborder=auto〉<br /><br />　　〈/iframe〉<br /><br />　　不错吧，马上“Ctrl+C”、“Ctrl+V”试试。<br /><br />　　有时我们为强调页面的某项内容，想让它先于页面的其他内容显示。同样用iframe即可轻松实现：<br /><br />　　先把要强调显示的内容另存为一个文件，如first.htm，然后通过一个预载页index.htm，内容如下：<br /><br />　　〈meta http-equiv="refresh" content="3,url=index2.htm"〉<br /><br />　　〈body〉<br /><br />　　页面加载中，请稍候……〈iframe src="first.htm" style="display:none"〉〈/iframe〉<br /><br />　　〈/body〉<br /><br />　　主文件index2.htm <br /><br />　　〈body〉<br /><br />　　〈iframe src="first.htm"加入其他属性限制〉〈/iframe〉<br /><br />　　〈/body〉
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/50371#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 25 Jan 2007 13:37:17 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/50371</link>
        <guid>http://jspengxue.javaeye.com/blog/50371</guid>
      </item>
      <item>
        <title>frameset</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/49779" style="color:red;">http://jspengxue.javaeye.com/blog/49779</a>&nbsp;
          发表时间: 2007年01月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          最近在搞网页编程，总结了frameset 的一些使用技巧，供大家参考哦，还是先剖析一下框架吧！<br />■ 框架标记<br /><br />　　&lt;FRAMESET> &lt;FRAME> <br />　　&lt;NOFRAMES> <br />　　&lt;IFRAME> <br /><br />　　欲明白本篇【HTML彻底剖析】之标记分类，请看 【标记一览】。 <br />　　也请先明白围堵标记与空标记的分别，请看 【HTML概念】。 <br /> <br />  <br />■ 框架概念 ：<br /><br />　　谓框架便是网页画面分成几个框窗，同时取得多个 URL。只需要 &lt;FRAMESET> &lt;FRAME> 即可，面所有框架标记需要放在一个总起的 html 档，这个档案只记录了该框架如何分割 ，不会显示任何资料，所以不必放入 &lt;BODY> 标记，浏览这框架必须读取这档案 面不是其他框窗的档案。&lt;FRAMESET> 是用来划分框窗，每一窗框由一个 &lt;FRAME> 标 记所标示，&lt;FRAME>必须在 &lt;FRAMESET> 范围中使用。如下例： <br /><br />　　&lt;frameset cols="50%,*"> &lt;frame name="hello" src="up2u.html"> &lt;frame name="hi" src="me2.html"> <br />　　&lt;/frameset> <br /><br />　　此例中 &lt;FRAMESET> 把画面分成左右两相等部分，左便是显示 up2u.html，右边则会显示 me2.html 这档案，&lt;FRAME> 标记所标示的框窗永远是按由上而下、由左至右的次序<br /> <br /><br />&lt;FRAME><br />用法：　　　　　　定义一个帧<br />开始／结束标识：　必须／非法<br />属性：　　　　　　name="..."定义帧的名字<br />　　　　　　　　　scr="..."定义在帧中显示的内容的来源<br />　　　　　　　　　frameborder="..."定义帧之间的边界(0或1)<br />　　　　　　　　　margwidth="..."设置帧的边界和其中内容之间的间距<br />　　　　　　　　　margheight="..."设置帧的边界和其中内容之间的间距化<br />　　　　　　　　　noresize="..."使帧的尺寸不能变<br />　　　　　　　　　scrolling="..."设置滚动条的表示方式(auto, yes, no)<br />空：　　　　　　　不允许<br /> <br />&lt;FRAMESET>...&lt;/FRAMESET><br />用法：　　　　　　定义在一个窗口中帧的布局<br />开始／结束标识：　必须／必须<br />属性：　　　　　　rows="..."设定行的数目<br />　　　　　　　　　cols="..."设定列的数目<br />　　　　　　　　　onload="..."当载入文档时的内部事件触发器<br />　　　　　　　　　onunload="..."当卸载文档时的内部事件触发器<br />空：　　　　　　　不允许<br />注释：　　　　　　FRAMESET可以嵌套<br /> <br />以上所述只是最简单的框架设定，若希望达到更合适的效果请加入或修改以下各参数。 <br />　　标记：&lt;FRAMESET> <br />　　例子：&lt;frameset rows="90,*" frameborder="0" border=0 framespacing="2" border="2" bordercolor="#008000">&lt;/frameset> <br />　　功用：宣告HTML文件为框架模式，并设定视窗如何分割。 <br /><br />　　参数： <br /><br />COLS="90,*" <br />垂直切割画面(如分左右两个画面)，接受整数值、百分数， * 则代表占用剩余的空间。数值的个数代表分成的视窗数目且以逗号分隔。例如 COLS="30,*,50%" 可以切成三个视窗，第一个视窗是 30 pixels 的宽度，为一绝对分割，第二个视窗是当分配完第一及第三个视窗后剩下的空间，第三个视窗则占整个视窗画面的 50% 宽度为一相对分割。你可自己调整数字。 <br /> <br /><br />ROWS="120,*" <br />这是横向切割，将画面上下分开，数值设定同上。 COLS 与 ROWS 两参数尽量不要放在同一个 &lt;FRAMESET> 标记中，因 Netacape 偶然不能显示这类型的框架，尽量采用多重分割，如以上各例。 <br /> <br /><br />frameborder="0" <br />设定框架的边框，其值只有 0 和 1 ， 0 表示不要边框， 1 表示要显示边框。 <br /> <br /><br />border="0" <br />设定框架的边框厚度，以 pixels 为单位。 <br /> <br /><br />bordercolor="#008000" <br />设定框架的边框颜色。颜色值请参考【调色原理】。 <br /> <br /><br />framespacing="5" <br />表示框架与框架间保留的空白的距离。 <br />　　标记：&lt;FRAME> <br />　　例子：&lt;frame name="top" src="a.html" marginwidth="5" marginheight="5" scrolling="Auto" frameborder="0" noresize framespacing="6" bordercolor="#0000FF"> <br />　　功能：设定每一个框窗内的参数属性。 <br />　　参数： <br /><br /><br />SRC="a.html"<br />设定此框窗中要显示的网页档案名称，每个框窗一定要对应一个网页档案。 <br /> <br /><br />NAME="top"<br />设定这个框窗的名称，这样才能指定框架来作链接，必须但任意命名。 <br /> <br /><br />frameborder=0<br />设定框架的边框，其值只有 0 和 1 ， 0 表示不要边框， 1 表示要边框。 <br /> <br /><br />framespacing="6"<br />表示框架与框架间的保留的空白的距离。 <br /> <br /><br />bordercolor="#008000"<br />设定框架的边框颜色。 <br /> <br /><br />scrolling="Auto"<br />设定是否要显示卷轴，YES 表示要显示卷轴，NO 表示无论如何都不要显示卷轴，AUTO 视情况而定。 <br /> <br /><br />noresize<br />设定不让使用者可以改变这个框框的大小，如没有设定此参数，使用者可随意地拉动框架改变其大小。 <br /> <br /><br />marginhight=5<br />表示框架高度部分边缘所保留的空间。 <br /> <br /><br />marginwidth=5<br />表示框架宽度部分边缘所保留的空间。
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/49779#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 24 Jan 2007 10:48:35 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/49779</link>
        <guid>http://jspengxue.javaeye.com/blog/49779</guid>
      </item>
      <item>
        <title>Linux下文件关联的实现原理 </title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48577" style="color:red;">http://jspengxue.javaeye.com/blog/48577</a>&nbsp;
          发表时间: 2007年01月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          我们知道在Windows下，双击一个可执行文件，文件管理器会自动运行这个应用程序。而双击一个数据文件时，文件管理器会用与之关联的应用程序打开它。数据文件与应用程序之间的关联是通过注册表来实现的：文件管理器查询注册表，找到数据文件对应的应用程序，然后运行这个应用程序，并把数据文件的文件名作为命令行参数传给它。<br /><br /> <br /><br />这种文件关联的方式非常好用，省去了先起动应用程序再打开文件的麻烦。Linux下的桌面环境也有类似的功能，而且实现方式更合理。最近负责开发一个资源管理器，本来GNOME有一个功能强大的资源管理器Nautilus，只是它过于庞大，不但有超过10万行的代码，还依赖于libgnome、gnome-vfs和CORBA等，故不适合于嵌入式应用。最终我们决定自己开发一个简化的资源管理器，但又要尽量兼容现有的应用程序，这要了解相关标准，文件关联方式是其中之一。把这几天学到的知识做个笔记吧，供有兴趣的朋友参考：<br /><br /> <br /><br />首先让我们看看文件关联要做些什么。<br /><br />1.         数据文件与应用程序的关联。一个应用程序通常只能打开一些特定的数据文件，比如图片浏览工具可以打开PNG、BMP和JPEG等图片文件。打开一词的意义比较宽泛，这里包括：打开、播放、安装、编辑和打印等等。<br /><br /> <br /><br />2.         文件类型信息。资源管理器把数据文件列出来时，通常会用一个图标来标识这类文件，同时也会加上一个简短的名称，以便用户可以很容易把它与其它类型的文件区分开来。<br /><br /> <br /><br />下面我们看看linux下是如何实现的。<br /><br />1.         判断文件类型。文件的数量是无限的，我们只能按文件类型来处理。如何判断一个文件所属的文件类型呢？可能有人会说，很简单，用扩展名区分就行了。没错，用扩展名可以做到，但这种方法有两个缺陷：一方面它不是很精确，相同扩展名的文件的类型可能完全不同，比如dat文件，可能是一个视频文件，也可能是一个普通数据文件。另一方面它不是很准确，扩展名可以任何改动，为了某种目的，完全可以把exe扩展名改为htm扩展名。<br /><br /> <br /><br />而且在Linux下扩展名只是一个可选项，很多文件根本没有扩展名，所以纯粹采用文件扩展名的方式来判断肯定是不行的。为了更好的判断文件类型，<span style="color: red">在linux下同时采用两种方式</span>：优先采用magic方式，其次才采用文件扩展名方式。所谓magic方式，就是根据文件内容来判断。绝大多数文件，内部都有一些特定的标记，这些标记称为magic，比如BMP图片文件以BM两个字符开头，BM就是一个magic。虽然即使采用了双保险机制也有误判的可能，但概率已经大大降低了。<br /><br /> <br /><br />2.         文件类型的表示。<br /><br />文件类型如何表示呢？我们说JPEG是图片文件，说txt是文本文件，WML是XML文件。这种分类很直观，但也有几个问题：对JPEG文件来说，称它图片文件太笼统了。有的图片浏览工具虽然能够打开大部分图片文件，但不一定能打开所有图片文件，它需要更详细的文件类型信息。对txt和WML来说，它们其实都是文本文件，有的编辑器可能以同样的方式处理它们。为了避免分类太细或者太粗，linux采用了MIME(可以参考相关RFC)规范，它用一种层次型的方式来分类，如：<br /><br />JPEG文件：image/jpeg<br /><br />文本文件：text/plain<br /><br />XML文件：text/xml<br /><br />这种分类方式就可以粗细兼顾了。<br /><br /> <br /><br />3.         文件类型的数据信息。<br /><br />在linux下，关于文件类型的信息通常放在/usr/share/mime、/usr/local/share/mime和用户目录下，所有应用程序可以共享这些信息。在该目录下，一般会有以下这些文件：<br /><br />1         aliases：文件类型的别名。比如application/pdf 有时也称为application/x-pdf 。<br /><br />2        magic：各种文件的<span style="color: red">内部标识</span>，用于从文件内容来判断文件类型。如BMP图片文件以BM开头。<br /><br />3         globs：扩展名与文件类型的对应关系。如*.cpp文件是text/x-c++src类型的。<br /><br />4         packages目录：用于安装新文件类型用。<br /><br />5        其它子目录及其下的文件：更详细的描述各种文件类型。比如image下的jpeg.xml文件描述了jpeg文件类型。为了方便国际化，这些描述信息有各种语言版本。<br /><br /> <br /><br />4.         图标文件与数据文件的关联。<br /><br />在资源管理器中，通常用不同的图标来区分不同的文件类型。同时图标也是桌面主题相关的，主题不同，图标的大小和外观也不一样。图标文件通常存放在<span style="color: red">/usr/share/icons/主题/大小/mimetypes目录下。</span><br /> <br /><br />文件类型与图标文件的对应关系是通过文件名来实现的。比如，JPEG文件对应的图标文件为gnome-mime-image-jpeg.png。<br /><br />(这块不是很确定，有待进一步研究)<br /><br /> <br /><br />5.         应用程序与数据文件的关联。<br /><br />应用程序与数据文件的关联是通过.desktop文件来实现的。应用程序要出现在开始菜单中或者桌面上，它要提供一个desktop文件才行。应用程序安装之后，desktop文件通常安装到/usr/share/applications下。<br /><br /> <br /><br />可以在desktop文件中，指明其可以操作的文件类型。如，软件包安装程序可以操作rpm文件，它的desktop文件(system-install-packages.desktop)内容为：<br /><br /><pre name="code" class="java">[Desktop Entry]

Name=Install Packages

GenericName=Install Packages

Comment=Install new packages on the system

MimeType=application/x-rpm;

Exec=/usr/bin/system-install-packages %F

Terminal=false

Type=Application

Icon=system-config-packages.png

Encoding=UTF-8

NoDisplay=true</pre><br /> <br /><br />MimeType项指明它可以操作rpm类型的文件。<br /><br /> <br /><br />Linux比windows的做法科学之处。<br /><br />1.         Linux采用了双保险机制，对文件类型的判断更正确，出错的概率更小。<br /><br /> <br /><br />2.         Linux分离文件类型判断信息和文件关联方式，这样文件类型信息可以被重用。比如file命令可以用这些信息来判断文件类型，而不必打开它。
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/48577#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Jan 2007 17:16:07 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/48577</link>
        <guid>http://jspengxue.javaeye.com/blog/48577</guid>
      </item>
      <item>
        <title>linux 的目录结构</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48568" style="color:red;">http://jspengxue.javaeye.com/blog/48568</a>&nbsp;
          发表时间: 2007年01月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">/usr/local 是存放你新装的软件的目录。 
/bin 目录用于存放普通用户可执行的命令，系统中的任何用户都可以执行该目录中的命令 
/boot 目录用于存放linux操作系统启动时所需使用的文件，为了系统能够启动，通常该目录需要使用独立的分区，这样boot分区和根分区相互独立可以保证启动文件更加安全可靠。 
/mnt 目录中的子目录用于作为系统中可移动存储设备的挂载点。如光驱。 
/root 目录是超级用户root的宿主目录，可见超级用户在系统中与普通用户有很大差异。 
/sbin 
/tmp 为系统临时目录，很多命令程序在该目录中存放临时使用的文件。 
/usr 目录用于存放大量的系统应用程序及相关文件。如说明文档、库文件等。 
/var 目录用于存放系统中经常变化的文件，如日志文件，用户邮件等。 
/dev 目录用于存放系统中的所有设备文件，如光盘驱动器、硬盘等。 
/etc 目录用于存放系统中的配置文件，linux 中的配置文件都是文本文件，可以使用相应的命令查看。 
/home 目录用于存放系统中普通用户的宿主目录，每个用户在该目录下都有一个与用户同名的目录。</pre><br /><br /><br /><br />/bin bin是Binary的缩写。这个目录存放着最经常使用的命令。<br /><br /><br />　　/boot这里存放的是启动Linux时使用的一些核心文件，包括一些链接文件以及镜像文件。<br /><br />　　/dev dev是Device(设备)的缩写。该目录下存放的是Linux的外部设备，在Linux中访问设备的方式和访问文件的方式是相同的。<br /><br />　　/etc这个目录用来存放所有的系统管理所需要的配置文件和子目录。<br /><br />　　/home用户的主目录，在Linux中，每个用户都有一个自己的目录，一般该目录名是以用户的账号命名的。<br /><br />　　/lib这个目录里存放着系统最基本的动态链接共享库，其作用类似于Windows里的DLL文件。几乎所有的应用程序都需要用到这些共享库。<br /><br />　　/lost+found这个目录一般情况下是空的，当系统非法关机后，这里就存放了一些文件。<br /><br />　　/mnt在这里面中有四个目录，系统提供这些目录是为了让用户临时挂载别的文件系统的，我们可以将光驱挂载在/mnt/cdrom上，然后进入该目录就可以查看光驱里的内容了。<br /><br />　　<pre name="code" class="java">/proc这个目录是一个虚拟的目录，它是系统内存的映射，我们可以通过直接访问这个目录来获取系统信息。<span style="color: red">这个目录的内容不在硬盘上而是在内存里</span>，我们也可以直接修改里面的某些文件，比如可以通过下面的命令来屏蔽主机的ping命令，使别人无法ping你的机器：

　　echo 1 > /proc/sys/net/ipv4/icmp_echo_

　　ignore_all。</pre><br /><br />　　/root该目录为系统管理员，也称作超级权限者的用户主目录。<br /><br />　　/sbin s就是Super User的意思，这里存放的是系统管理员使用的系统管理程序。<br /><br />　　/tmp这个目录是用来存放一些临时文件的。<br /><br />　　我们要用到的很多应用程序和文件几乎都存放在usr目录下。具体来说：<br /><br />　　/usr/X11R6存放X-Windows的目录；<br /><br />　　/usr/games存放着XteamLinux自带的小游戏；<br /><br />　　/usr/bin存放着许多应用程序；<br /><br />　　/usr/sbin存放root超级用户使用的管理程序；<br /><br />　　/usr/doc Linux技术文档；<br /><br />　　/usr/include用来存放Linux下开发和编译应用程序所需要的头文件；<br /><br />　　/usr/lib存放一些常用的动态链接共享库和静态档案库；<br /><br />　　/usr/local这是提供给一般用户的/usr目录，在这里安装一般的应用软件；<br /><br />　　/usr/man帮助文档所在的目录；<br /><br />　　/usr/src Linux开放的源代码，就存在这个目录，爱好者们别放过哦；<br /><br />　　/var这个目录中存放着在不断扩充着的东西，我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件。如果你想做一个网站，你也会用到/var/www这个目录。
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/48568#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Jan 2007 16:45:13 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/48568</link>
        <guid>http://jspengxue.javaeye.com/blog/48568</guid>
      </item>
      <item>
        <title>八种常见的网络广告防作弊技术</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48540" style="color:red;">http://jspengxue.javaeye.com/blog/48540</a>&nbsp;
          发表时间: 2007年01月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          小偷和骗子都是另人可恶的，但生活中又是客观存在，作弊和欺骗点击也同样另人可恶，但又防不甚防。杜绝是不可能的，而防止是我们所有广告人的一种责任。以下是易特广告联盟目前在使用的几种防作弊方式，希望给每个网络营销者带来一点有用的帮助。<br /><br />　　1、  IP防止作弊：一般计费方式是按照24小时内唯一IP，可以将每个IP记入数据库，当下一个访问IP与数据库已存在的IP相同时，则不计费。现在上网一般是动态IP，作弊者通过拨号器上下线来实现改变IP地址，你可以通过C段IP来辨别，如大量出现218.175.11.x这种相同C段的IP号，则可能作弊。可以通过IP加密提交，然后由接收端进行解密记录入库，可以杜绝采用模拟提交数据的作弊方式。<br /><br />　　2、  COOKIES防止作弊：当你访问过一个页面时，COOKIE并会记录，当你下一次访问该页面时，并会提交一个相同COOKIES参数，你可以判断重复的不计费。这种方式的缺陷是很容易改变物理信息进行作弊，比如通过INTERNET选项清空COOKIES.<br /><br />　　3、  点击比率上线设置：平均点击率从99年的5%下降到了1%以内，当然其中还需要广告面向对象与页面的访问者的交叉率，越高则表示该页面与广告的关联度越大，点击率越高。目前富媒体广告的点击率在2%至5%，普通图片点击在0.1%至1%，与图片的创意有关，可以设置当点击率超过一定的百分率提示可能作弊行为（易特联盟设置在8%）。为了提高点击率，最常见的创意方式是模拟WINDOWS系统提示、模拟关闭按钮以及美女激情诱惑性图片。<br /><br />　　4、  结合ALEXA数据防止作弊：ALEXA虽然不是一个标准，但却是极好的参考工具，当一个ALEXA数值很大的站点却做了很高的点击量，就产生疑问了，流量从何而来？<br /><br />　　5、  来源统计防止作弊：1、记录该点击的来路页面，即广告放置页面的地址，可以人工巡查广告放置是否正确，查看旁边是否有引导性不良语句。2、记录放置广告页面的来路，每个站点的搜索引擎来路总是占据很大的一个比例，如果该页面没有来路，可以判断这个页面的流量非连接流量，可以通过两种途径获得，一、浏览器直接访问或者收藏夹访问；二、弹窗流量没有来路统计，也有可能是目前流行的流氓插件弹窗。该种方式也可以查询到有些站长将广告代码放置在IFRAME里的最终页面。<br /><br />　　6、  通过唯一参数防止作弊：网卡MAC物理地址、硬盘序列号，通过该类软硬件信息生成机器码。这种方式的缺点是很难在WEB上应用，适合软件营销的防作弊方式。<br /><br />　　7、  时间顺差防止作弊：当你打开一个有广告的页面时，一般情况下不可能瞬间点击广告，因为每个广告都由印象转变为关注，再转变成点击行动，你可以设置当访问者打开网站页面几秒内点击广告为作弊行为（易特联盟设置为3秒内提供参考）。当几次广告点击的时间差完全一致时，也可以判断为机器人点击行为。当你打开一个广告，在几秒内立即关闭（易特联盟设置为2秒提供参考），也可以判断为无效点击。<br /><br />　　8、  鼠标值：1、显示屏幕上的每个点都具有一个坐标值，当你在某个点按下鼠标时，都会有一个坐标值，当采用机器人点击时，为同一个鼠标值，可以只记一次点击。2、每次点击都会产生鼠标的KEYUP 和KEYDOWN的行为，如果未能捕获到这个值，可能是模拟数据提交。
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/48540#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Jan 2007 14:38:49 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/48540</link>
        <guid>http://jspengxue.javaeye.com/blog/48540</guid>
      </item>
      <item>
        <title>proxy header</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48508" style="color:red;">http://jspengxue.javaeye.com/blog/48508</a>&nbsp;
          发表时间: 2007年01月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          通常，一般的浏览器(IE or Mozilla)都不会提交象偶上面这么简单的HTTP请求的，它还会把一些有关信息包括进去，比如浏览器的版本以及操作系统版本，(User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)，这样HTTP服务器就可以得到更多的客户端的信息，偶们监听这个HTTP会话的话，也可以看到这些信息。<br /><br />HTTP客户端(浏览器)通过HTTP Proxy来访问某个HTTP服务器的过程大概如下：<br /><br />　　　　　　　HTTP请求->　　　　　　　　　　　　　　　　　　　　　HTTP请求-><br />HTTP Client ------------------ HTTP Proxy (更改某些HTTP头部信息) ------------------- HTTP Server<br />　　　　　　　&lt;-HTTP应答　　　　　　　　　　　　　　　　　　　　　&lt;-HTTP应答<br /><br />HTTP Proxy基本上会做一个中间人的位置，以自己的身份向HTTP服务器发起请求，这个HTTP请求的主要内容来自HTTP Client发给HTTP Proxy的请求，但是某些细节可能会有改变，HTTP Proxy甚至会加一些信息进去(怎么样，是不是眼前一亮啊？这就是偶们的机会了)。<br /><br />OK，确定我们的方向，只要发现某个HTTP请求中有HTTP Proxy加进去的信息，那么我们就可以判断某个IP是HTTP Proxy了，甚至可以判断出真正提交这个HTTP请求的非法用户的真实IP。<br />HTTP Proxy何其多啊，xxbin熟悉的只有Linux/UNIX下著名了squid和M$ ISA Server(原来的M$ Proxy)中带的HTTP Proxy，偶只能针对这两个HTTP Proxy来讨论，下面的方法，对其它的HTTP Proxy是否适应，偶没有条件测试不了。  而且下面所描述的协议的细节，并不是RFC中的规范，仅仅是针对某几个产品的一些特性。   (不过HTTP Proxy，这两大巨头是占了相当市场份额的，还算是有点代表性的说)<br /><br />通常，HTTP Proxy会更改或者添加以下的HTTP请求变量：<br /><pre name="code" class="java">REMOTE_ADDR
HTTP_VIA
HTTP_X_FORWARDED_FOR</pre><br /><br />当<span style="color: red">没有使用HTTP Proxy</span>的时候，这几个变量的值应该如下：<br /><pre name="code" class="java">REMOTE_ADDR: HTTP Client(浏览器)所在机器的IP
HTTP_VIA: 无定义，也就是说不会在HTTP请求中出现
HTTP_X_FORWARDED_FOR: 无定义，同上</pre><br /><br />当你使用了普通<span style="color: red">配置的HTTP Proxy的时候</span>，这几个变量就变成下面的样子了:<br />REMOTE_ADDR: HTTP Proxy's IP (不变的话就容易判断了，呵呵)<br />HTTP_VIA: HTTP Proxy's IP or HTTP Proxy' ServerName或HTTP协议版本号或HTTP Proxy版本信息(有什么办法呢，这可没有RFC定义的说，不同的厂商做出来的HTTP Proxy这个字段的东东是不一样的说)<br />HTTP_X_FORWARDED_FOR: HTTP Client(浏览器)所在机器的IP (<span style="color: red">Squid使用，ISA不支持此字段)</span><br />其实分析到这里，偶们的目的已经可以实现了。<br />只要发现某个HTTP请求头部带有HTTP_VIA或HTTP_X_FORWARDED_FOR，那么这个发起HTTP请求的IP必定是个HTTP Proxy。OK，知道IP就好办了，接下去的事情~~~罚款！！！
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/48508#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Jan 2007 11:31:44 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/48508</link>
        <guid>http://jspengxue.javaeye.com/blog/48508</guid>
      </item>
      <item>
        <title>真正的取真实IP地址及利弊</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48502" style="color:red;">http://jspengxue.javaeye.com/blog/48502</a>&nbsp;
          发表时间: 2007年01月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          目前网上流行的所谓"取真实IP地址"的方法，都有bug，没有考虑到多层透明代理的情况。<br />多数代码类似：<br /><pre name="code" class="java"> string IpAddress = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]!=null
             && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] !=String.Empty)
             ?HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]
             :HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];</pre>事实上，上面的代码只试用与用户只使用了1层代理，如果用户有2层，3层<br /><span style="color: red">HTTP_X_FORWARDED_FOR 的值是："本机真实IP,1层代理IP,2层代理IP,....." </span>，如果这个时候你的数据中保存IP字段的长度很小（15个字节），数据库就报错了。<br />实际应用中，因为使用多层透明代理的情况比较少，所以这种用户并不多。<br />其他应用情况，现在越来越多的网站使用了代理加速方式，比如 新浪、SOHU的新闻 都使用Squid做代理方式，利用多台服务器分流。Squid本身类似透明代理，会发送"HTTP_X_FORWARDED_FOR" ，HTTP_X_FORWARDED_FOR 中包括客户的IP地址，如果此时客户已经使用了一层透明代理，那么程序取的 "HTTP_X_FORWARDED_FOR" 就包括两个IP地址。（我遇到过3个IP地址的情况，4个的未遇到过）<br /><span style="color: red">所以取"真正"IP地址的方式，还应该判断  "HTTP_X_FORWARDED_FOR"  中是否有","逗号，或者长度是否超长（超过15字节 xxx.xxx.xxx.xxx）。</span><br />所以代码应该如下：<br /><br /><pre name="code" class="java">  /// &lt;summary>
 /// 取得客户端真实IP。如果有代理则取第一个非内网地址
 /// by flower.b
 /// &lt;/summary>
 public static string IPAddress
   {
     get
       {
         string result = String.Empty;

         result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
         if(result!=null&&result!= String.Empty)
           {
             //可能有代理
             if(result.IndexOf(".")==-1)    //没有"."肯定是非IPv4格式
                 result = null;
             else
               {
                 if(result.IndexOf(",")!=-1)
                   {
                     //有","，估计多个代理。取第一个不是内网的IP。
                     result = result.Replace(" ","").Replace("","");
                     string[] temparyip = result.Split(",;".ToCharArray());
                     for(int i=0;i&lt;temparyip.Length;i++)
                       {
                         if( Text.IsIPAddress(temparyip[i])
                             && temparyip[i].Substring(0,3)!="10."
                             && temparyip[i].Substring(0,7)!="192.168"
                             && temparyip[i].Substring(0,7)!="172.16.")
                           {
                             return temparyip[i];    //找到不是内网的地址
                         }
                     }
                 }
                 else if(Text.IsIPAddress(result)) //代理即是IP格式
                     return result;
                 else
                     result = null;    //代理中的内容 非IP，取IP
             }

         }

         string IpAddress = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]!=null && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] !=String.Empty)?HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]:HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];

 

         if (null == result || result == String.Empty)
             result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];

         if (result == null || result == String.Empty)
             result = HttpContext.Current.Request.UserHostAddress;

         return result;
     }
 }</pre><br /><br />取"HTTP_X_FORWARDED_FOR" 的弊端。<br />HTTP_X_FORWARDED_FOR 是HTTP协议中头的一部分，不影响TCP的通讯。也就是说实际上客户端可以发送任意内容的 HTTP_X_FORWARDED_FOR，以就是伪造IP。最简单的是WEB程序的IP记录，本来是要记录真实IP的，反而被"黑客"欺骗。当你的应用程序记录客户的访问IP、拒绝或允许部分IP的访问、错误日志 都会出错，甚至误杀。<br />因此必要的安全日志应该记录 完整的 "HTTP_X_FORWARDED_FOR" （至少给数据库中的字段分配 3*15+2 个字节，以记录至少3个IP） 和 "REMOTE_ADDR"。对 HTTP_X_FORWARDED_FOR 的IP格式检查也是不可少的。
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/48502#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Jan 2007 11:08:36 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/48502</link>
        <guid>http://jspengxue.javaeye.com/blog/48502</guid>
      </item>
      <item>
        <title>SQUID的参考文档</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48495" style="color:red;">http://jspengxue.javaeye.com/blog/48495</a>&nbsp;
          发表时间: 2007年01月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Linux下架设代理服务器 <br /><br />作者：bye2000 <br /><br />一、代理服务器概述 <br />  <br />1.1什么是代理服务器  <br />在TCP/IP网络中，传统的通信过程是这样的：客户端向服务器请求数据，服务器响应该请求，将数据传送给客户端。在引入了代理服务器以后，这一过程变成了这样：客户端向服务器发起请求，该请求被送到代理服务器；代理服务器分析该请求，先查看自己缓存中是否有请求数据，如果有就直接传送给客户端，如果没有就代替客户端向该服务器发出请求。服务器响应以后，代理服务器将响应的数据传送给客户端，同时在自己的缓存中保留一份该数据的拷贝。这样，再有客户端请求相同的数据时，代理服务器就可以直接将数据传送给客户端，而不需要再向该服务器发起请求。 <br />  <br />1.2 代理服务器的功能  <br />一般说来，代理服务器具有以下的功能：  <br />1.通过缓存增加访问速度  <br />随着Internet的迅猛发展，网络带宽变得越来越珍贵。所以为了提高访问速度，好多ISP都提供代理服务器，通过代理服务器的缓存功能来加快网络的访问速度。一般说来，大多数的代理服务器都支持HTTP缓存，但是，有的代理服务器也支持FTP缓存。在选择代理服务器时，对于大多数的组织，只需要HTTP缓存功能就足够了。  <br />通常，缓存有主动缓存被动缓存之分。所谓被动缓存，指的是代理服务器只在客户端请求数据时才将服务器返回的数据进行缓存，如果数据过期了，又有客户端请求相同数据时，代理服务器又必须重新发起新的数据请求，在将响应数据传送给客户端时又进行新的缓存。所谓主动缓存，就是代理服务器不断地检查缓存中的数据，一旦有数据过期，则代理服务器主动发起新的数据请求来更新数据。这样，当有客户端请求该数据时就会大大缩短响应时间。还需要说明的是，对于数据中的认证信息，大多数的代理服务器都不会进行缓存的。  <br />2.提供用私有IP访问Internet的方法  <br />IP地址是不可再生的宝贵资源，假如你只有有限的IP地址，但是需要提供整个组织的Internet访问能力，那么，你可以通过使用代理服务器来实现这一点。  <br />3.提高网络的安全性  <br />这一点是很明显的，如果内部用户访问Internet都是通过代理服务器，那么，代理服务器就成为进入Internet的唯一通道；反过来说，代理服务器也是Internet访问内部网的唯一通道，如果你没有做反向代理，则对于Internet上的主机来说，你的整个内部网只有代理服务器是可见的，从而大大增强了网络的安全性。  <br /><br />1.3 代理服务器的分类及特点  <br />通常的代理服务器分类方法，是从实现的机理分为线路层代理、应用层代理、智能线路层代理等等。在这里，我想从另外一个角度出发，把代理服务器分为传统代理服务器和透明代理服务器。  <br />我认为有必要好好搞清楚两者的区别，只有真正明白了内在地机理，才能在遇到问题时，有章可循，才不会一头雾水，不知从何解决问题。因此，下面我们就通过具体的实例来说明。本章的写作思路来源于Paul Russell所写的IPCHAINS-HOWTO。下面所举的例子也来源于该文章，我觉得我读该文的最大收获在于对内部网访问外部网以及外部网访问内部网的实现手段有了一个清晰的认识。当然，这里所谓的内部网是指使用私有IP的内部网络。  <br />我们的例子都基于以下假设：  <br />你的域名为sample.com,你的内部网(192.168.1.*)用户通过proxy.sample.com(外部接口 eth0:1.2.3.4;内部接口 eth1:192.168.1.1)的代理服务器访问Internet，换句话说，该代理服务器是唯一一台直接与Internet和内部网相连的机器。并假该设代理服务器上运行着某种代理服务器软件（如squid)。假设内部网中某一客户机为client.sample.com(192.168.1.100)。  <br />+-------------------+  <br />|内部网(192.168.1.*)| eth1+--------+eth0 DDN  <br />| +------------| proxy |&lt;===============>;Internet  <br />|client198.168.1.100| +--------+  <br />+-------------------+  <br />eth0: 1.2.3.4  <br />eth1: 198.168.1.1  <br /><br />1.3.1传统代理  <br />在以上基础上我们做以下工作：  <br />1.代理服务软件被绑定到代理服务器的8080端口。  <br />2.客户端浏览器被配置使用代理服务器的8080端口。  <br />3.客户端不需要配置DNS。  <br />4.代理服务器上需要配置代理服务器。  <br />5.客户端不需要配置缺省路由。  <br />当我们在客户端浏览器中打开一个web请求，比如“http://www.linuxaid.com.cn”，这时将陆续发生以下事件：  <br />1.客户端使用某一端口（比如1025)连接代理服务器8080端口，请求web页面“http://www.linuxaid.com.cn”  <br />2.代理服务器向DNS请求“www.linuxaid.com.cn”,得到相应的IP地址202.99.11.120。然后，代理服务器使用某一端口（比如1037)向该IP地址的80端口发起web连接请求，请求web页面。  <br />3.收到响应的web页面后，代理服务器把该数据传送给客户端。  <br />4.客户端浏览器显示该页面。  <br />从www.linuxaid.com.cn的角度看来，连接是在1.2.3.4地1037端口和202.99.11.120的80端口之间建立的。从client的角度看来，连接是在192.168.1.100的1025端口和1.2.3.4的8080端口之间建立的。 <br />  <br />1.3.2 透明代理  <br />透明代理的意思是客户端根本不需要知道有代理服务器的存在。  <br />在以上基础上我们做以下工作：  <br />1.配置透明代理服务器软件运行在代理服务器的8080端口。  <br />2.配置代理服务器将所有对80端口的连接重定向到8080端口。  <br />3.配置客户端浏览器直接连解到Internet。  <br />4.在客户端配置好DNS.  <br />5.配置客户端的缺省网关为192.168.1.1.  <br />当我们在客户端浏览器中打开一个web请求，比如“http://www.linuxaid.com.cn”，这时将陆续发生以下事件：  <br />1.客户端向DNS请求“www.linuxaid.com.cn”,得到相应的IP地址202.99.11.120。然后，客户端使用某一端口（比如1066)向该IP地址的80端口发起web连接请求，请求web页面。  <br />2.当该请求包通过透明代理服务器时，被重定向到代理服务器的绑定端口8080。于是，透明代理服务器用某一端口（比如1088)向202.99.11.120的80端口发起web连接请求，请求web页面。  <br />3.收到响应的web页面后，代理服务器把该数据传送给客户端。  <br />4.客户端浏览器显示该页面。  <br />从www.linuxaid.com.cn的角度看来，连接是在1.2.3.4地1088端口和202.99.11.120的80端口之间建立的。从client的角度看来，连接是在192.168.1.100的1066端口和202.99.11.120的80端口之间建立的。  <br />以上就是传统代理服务器和透明代理服务器的区别所在。  <br /><br />二、各种代理服务器的比较  <br />linux下的代理服务器软件很多，我从www.freshmeat.com(一个著名的linux软件站点）查看了一下，足有六十多个。但是被广泛应用的只有Apache、socks、squid等几个实践证明是高性能的代理软件。下面我们分别来比较一下这几个软件：  <br /><br />2.1 Apache  <br />Apache是世界上用的最广泛的HTTP服务器，之所以用的最广泛，是因为它强大的功能、高效率、安全性和速度。从1.1.x版本开始，Apache开始包含了一个代理模块。用Apache作代理服务器的性能优势并不明显，不建议使用。  <br /><br />2.2 Socks  <br />Socks是一种网络代理协议，该协议可以让客户机通过Socks服务器获得对Internet的完全访问能力。Scoks在服务器和客户端之间建立一个安全的代理数据通道，从客户的角度看来，Scoks是透明的；从服务器的角度看来，Socks就是客户端。客户端不需要具有对Internet的直接访问能力(也就是说，可以使用私有IP地址），因为Socks服务器能够把来自于客户端的连接请求重定向到Internet。此外，Socks服务器可以对用户连接请求进行认证，允许合法用户建立代理连接。同理，Socks也能防止非授权的Internet用户访问及的内部网络。所以常常把Socks当作防火墙来使用。  <br />常见的浏览器如netscape、IE等可以直接使用Socks, 并且我们也可以使用socsk5的所带的client来使那些不直接支持socks的internet软件使用Socks。  <br />更多的资料可以参考Socks官方站点http://www.socks.nec.com。  <br /><br />2.3 Squid  <br />对于web用户来说，Squid是一个高性能的代理缓存服务器，Squid支持FTP、gopher和HTTP协议。和一般的代理缓存软件不同，Squid用一个单独的、非模块化的、I/O驱动的进程来处理所有的客户端请求。  <br />Squid将数据元缓存在内存中，同时也缓存DNS查询的结果，除此之外，它还支持非模块化的DNS查询，对失败的请求进行消极缓存。Squid支持SSL，支持访问控制。由于使用了ICP（轻量Internet缓存协议），Squid能够实现层叠的代理阵列，从而最大限度地节约带宽。  <br />Squid由一个主要的服务程序squid,一个DNS查询程序dnsserver，几个重写请求和执行认证的程序，以及几个管理工具组成。当Squid启动以后，它可以派生出预先指定数目的dnsserver进程，而每一个dnsserver进程都可以执行单独的DNS查询，这样一来就大大减少了服务器等待DNS查询的时间。  <br /><br />2.4 选择  <br />从上面的比较可以看出，Apache主要功能是web服务器，代理功能只不过是其一个模块而已，Socks虽然强大，但有欠灵活，因此我们着重推荐你使用Squid。下面的章节我们就一起来学习Squid激动人心的特性及相关的安装与配置。 <br /><br />三、安装Squid Proxy Server  <br /><br />3.1获取软件  <br />你可以通过以下途径获取该软件：  <br />1.从Squid的官方站点http://www.squid-cache.org下载该软件；  <br />2.从你的linux发行版本中获取该软件；  <br />通常，Squid软件包有两种：一种是源代码，下载后需要自己重新编译；可执行文件，下载后只需解压就可以使用；另一种是就是RedHat所使用的rpm包。下面我们分别讲讲这两种软件包的安装方法。  <br /><br />3.2安装软件  <br />我们以目前最新的稳定版本squid-2.3.STABLEX为例。  <br /><br />3.2.1rpm包的安装  <br />1.进入/mnt/cdrom/RedHat/RPMS  <br />2.执行rpm -ivh squid-2.2.STABLE4-8.i386.rpm。  <br />当然，我们也可以在开始安装系统的过程中安装该软件。  <br /><br />3.2.2 源代码包的安装  <br />1.从http://www.squid-cache.org下载squid-2.3.STABLE2-src.tar.gz。  <br />2.将该文件拷贝到/usr/local目录。  <br />3.解开该文件 tar xvzf squid-2.3.STABLE2-src.tar.gz。  <br />4.解开后，在/usr/local生成一个新的目录squid-2.3.STABLE2，为了方便用mv命令将 该目录重命名为squid mv squid-2.3.STABLE2 squid;  <br />5.进入squid cd squid  <br />6.执行./configure 可以用./confgure --prefix=/directory/you/want指定安装目录  <br />系统缺省安装目录为/usr/local/squid。  <br />7.执行 make all  <br />8.执行 make install  <br />9.安装结束后，squid的可执行文件在安装目录的bin子目录下，配置文件在etc子目录下。  <br /><br />四、配置squid基础篇——让代理服务器跑起来  <br />由于RedHat各方面的优势（包括易用性，稳定性等等），全世界范围内使用该发行版的用户比较多，所以，我们下面的说明都是以RedHat6.1环境下squid-2.2.STABLE4-8版本为主。从我的使用经验看来，该版本的squid要比其他版本稳定的多，以前的1.1.22版本也比较稳定，但是在功能及灵活性方面有所欠缺。  <br />squid有一个主要的配置文件squid.conf,在RedHat环境下所有squid的配置文件位于/etc/squid子目录下。  <br /><br />4.1常用的配置选项  <br />因为缺省的配置文件有问题，所以我们必须首先修改该配置文件的有关内容,以便让squid跑起来。  <br />下面我们来看一看squid.conf文件的结构以及一些常用的选项：  <br />squid.conf配置文件的可以分为十三个部分，这十三个部分分别是：  <br />1.NETWORK OPTIONS （有关的网络选项）  <br />2.OPTIONS WHICH AFFECT THE NEIGHBOR SELECTION ALGORITHM （作用于邻居选择算 法的有关选项）  <br />3.OPTIONS WHICH AFFECT THE CACHE SIZE （定义cache大小的有关选项）  <br />4.LOGFILE PATHNAMES AND CACHE DIRECTORIES (定义日志文件的路径及cache的目录）  <br />5.OPTIONS FOR EXTERNAL SUPPORT PROGRAMS （外部支持程序选项）  <br />6.OPTIONS FOR TUNING THE CACHE （调整cache的选项）  <br />7.TIMEOUTS （超时）  <br />8.ACCESS CONTROLS （访问控制）  <br />9.ADMINISTRATIVE PARAMETERS （管理参数）  <br />10.OPTIONS FOR THE CACHE REGISTRATION SERVICE （cache注册服务选项）  <br />11.HTTPD-ACCELERATOR OPTIONS （HTTPD加速选项）  <br />12.MISCELLANEOUS （杂项）  <br />13.DELAY POOL PARAMETERS （延时池参数）  <br />虽然squid的配置文件很庞大，但是如果你只是为一个中小型网络提供代理服务，并且只准备使用一台服务器，那么，你只需要修改配置文件中的几个选项。这些几个常用选项分别是：  <br />1.http_port  <br />说明：定义squid监听HTTP客户连接请求的端口。缺省是3128，如果使用HTTPD加速模式 则为80。你可以指定多个端口，但是所有指定的端口都必须在一条命令行上。  <br />2.cache_mem (bytes)  <br />说明：该选项用于指定squid可以使用的内存的理想值。这部分内存被用来存储以下对象 ：  <br />In-Transit objects （传入的对象）  <br />Hot Objects （热对象，即用户常访问的对象）  <br />Negative-Cached objects （消极存储的对象）  <br />需要注意的是，这并没有指明squid所使用的内存一定不能超过该值，其实，该选项只 定义了squid所使用的内存的一个方面，squid还在其他方面使用内存。所以squid实际 使用的内存可能超过该值。缺省值为8MB。  <br />3.cache_dir Directory-Name Mbytes Level-1 Level2  <br />说明：指定squid用来存储对象的交换空间的大小及其目录结构。可以用多个cache_dir命令来定义多个这样的交换空间，并且这些交换空间可以分布不同的磁盘分区。"directory "指明了该交换空间的顶级目录。如果你想用整个磁盘来作为交换空间，那么你可以将该目录作为装载点将整个磁盘mount上去。缺省值为/var/spool/squid。“Mbytes”定义了可用的空间总量。需要注意的是，squid进程必须拥有对该目录的读写权力。“Level-1”是可以在该顶级目录下建立的第一级子目录的数目，缺省值为16。同理，“Level-2”是可以建立的第二级子目录的数目，缺省值为256。为什么要定义这么多子目录呢？这是因为如果子目录太少，则存储在一个子目录下的文件数目将大大增加，这也会导致系统寻找某一个文件的时间大大增加，从而使系统的整体性能急剧降低。所以，为了减少每个目录下的文件数量，我们必须增加所使用的目录的数量。如果仅仅使用一级子目录则顶级目录下的子目录数目太大了，所以我们使用两级子目录结构。  <br />那么，怎么来确定你的系统所需要的子目录数目呢？我们可以用下面的公式来估算。  <br />已知量：  <br />DS = 可用交换空间总量（单位KB）/ 交换空间数目  <br />OS = 平均每个对象的大小= 20k  <br />NO = 平均每个二级子目录所存储的对象数目 = 256  <br />未知量：  <br />L1 = 一级子目录的数量  <br />L2 = 二级子目录的数量  <br />计算公式：  <br />L1 x L2 = DS / OS / NO  <br />注意这是个不定方程，可以有多个解。  <br />4.acl  <br />说明：定义访问控制列表。  <br />定义语法为：  <br />acl aclname acltype string1 ...  <br />acl aclname acltype "file" ...  <br />当使用文件时，该文件的格式为每行包含一个条目。  <br />acltype 可以是 src dst srcdomain dstdomain url_pattern urlpath_pattern time port proto method browser user 中的一种。  <br />分别说明如下：  <br />src 指明源地址。可以用以下的方法指定：  <br />acl aclname src ip-address/netmask ... (客户ip地址)  <br />acl aclname src addr1-addr2/netmask ... (地址范围)  <br />dst 指明目标地址。语法为：  <br />acl aclname dst ip-address/netmask ... (即客户请求的服务器的ip地址)  <br />srcdomain 指明客户所属的域。语法为：  <br />acl aclname srcdomain foo.com ... squid将根据客户ip反向查询DNS。  <br />dstdomain 指明请求服务器所属的域。语法为：  <br />acl aclname dstdomain foo.com ... 由客户请求的URL决定。  <br />注意，如果用户使用服务器ip而非完整的域名时，squid将进行反向的DNS解析来确 定其完整域名，如果失败就记录为“none”。  <br />time 指明访问时间。语法如下：  <br />acl aclname time [day-abbrevs] [h1:m1-h2][hh:mm-hh]  <br />day-abbrevs:  <br />S - Sunday  <br />M - Monday  <br />T - Tuesday  <br />W - Wednesday  <br />H - Thursday  <br />F - Friday  <br />A - Saturday  <br />h1:m1 必须小于 h2:m2，表达示为[hh:mm-hh]。  <br />port 指定访问端口。可以指定多个端口，比如：  <br />acl aclname port 80 70 21 ...  <br />acl aclname port 0-1024 ... （指定一个端口范围）  <br />proto 指定使用协议。可以指定多个协议：  <br />acl aclname proto HTTP FTP ...  <br />method 指定请求方法。比如：  <br />acl aclname method GET POST ...  <br />5.http_access  <br />说明：根据访问控制列表允许或禁止某一类用户访问。  <br />如果某个访问没有相符合的项目,则缺省为应用最后一条项目的“非”。比如最后一条为允许，则缺省就是禁止。所以，通常应该把最后的条目设为"deny all" 或 "allow all" 来避免安全性隐患。 <br />4.2 应用实例  <br />假想情景：某公司用squid作代理服务器，该代理服务器配置为PII450/256M/8.4G,公司所用ip段为1.2.3.0/24,并且想用8080作为代理端口。  <br />则相应的squid配置选项为：  <br />1.http_port  <br />http_port 8080  <br />2.cache_mem  <br />思路：由于该服务器只提供代理服务，所以该值可以尽量设得大一些。  <br />cache_mem 194M  <br />3.cache_dir Directory-Name Mbytes Level-1 Level2  <br />思路：硬盘为8.4G的，在安装系统时应该做好规划，为不同的文件系统划分可用空间。在本例中，我们可以这样来划分：  <br />/cache1 3.5G  <br />/cache2 3.5G  <br />/var 400M  <br />swap 127M  <br />/ 剩余部分  <br />并且，在安装时，我们尽量不安装不必要的包。这样在节约空间的同时可以提高系统的安全性和稳定性。下面我们来计算所需的第一级和第二级子目录数。  <br />已知量：  <br />DS = 可用交换空间总量（单位KB）/ 交换空间数目＝7G/2=3500000KB  <br />OS = 平均每个对象的大小= 20k  <br />NO = 平均每个二级子目录所存储的对象数目 = 256  <br />未知量：  <br />L1 = 一级子目录的数量  <br />L2 = 二级子目录的数量  <br />计算公式：  <br />L1 x L2 = DS / OS / NO＝3500000/20/256=684  <br />我们取  <br />L1=16  <br />L2=43  <br />所以，我们的cache_dir语句为：  <br />cache_dir /cache1 3500M 16 43  <br />cache_dir /cache2 3500M 16 43  <br />4.acl  <br />思路：通过src来定义acl.  <br />acl allow_ip src 1.2.3.4/255.255.255.0  <br />5.http_access  <br />http_access allow allow_ip  <br /><br />4.3启动、停止squid。  <br />配置并保存好squid.conf后，可以用以下命令启动squid。  <br />squid  <br />或者，使用RedHat的启动脚本来启动squid.  <br />/etc/rc.d/init.d/squid start  <br />同样地，你也可以用下列脚本停止运行squid或重启动squid.  <br />/etc/rc.d/init.d/squid stop  <br />/etc/rc.d/init.d/squid restart  <br /><br />五、根据需求配置你的squid——进阶篇  <br /><br />5.1其它配置选项  <br />在进行squid的一些高级应用之前，我们有必要对其他有用的配置选项作一个全面的了解。下面我们分类来讲一讲这些选项，用于某些特殊应用的选项我们将放在讲该种应用时来讲。  <br /><br />5.1.1网络选项  <br />1.tcp_incoming_address  <br />tcp_outgoing_address  <br />udp_incoming_address  <br />udp_outgoing_address  <br />说明：  <br />tcp_incoming_address指定监听来自客户或其他squid代理服务器的绑定ip地址；  <br />tcp_outgoing_address指定向远程服务器或其他squid代理服务器发起连接的ip地址  <br />udp_incoming_address为ICP套接字指定接收来自其他squid代理服务器的包的ip地址 udp_outgoing_address为ICP套接字指定向其他squid代理服务器发送包的ip地址；  <br />缺省为没有绑定任何ip地址。该绑定地址可以用ip指定，也可以用完整的域名指定。  <br /><br />5.1.2交换空间设定选项  <br />1.cache_swap_low (percent, 0-100)  <br />cache_swap_high (percent, 0-100)  <br />说明：squid使用大量的交换空间来存储对象。那么，过了一定的时间以后，该交换空间就会用完，所以还必须定期的按照某种指标来将低于某个水平线的对象清除。squid使用所谓的“最近最少使用算法”（LRU）来做这一工作。当已使用的交换空间达到cache_swap_high时，squid就根据LRU所计算的得到每个对象的值将低于某个水平线的对象清除。这种清除工作一直进行直到已用空间达到cache_swap_low。这两个值用百分比表示，如果你所使用的交换空间很大的话，建议你减少这两个值得差距，因为这时一个百分点就可能是几百兆空间，这势必影响squid的性能。缺省为：  <br />cache_swap_low 90  <br />cache_swap_high 95  <br />2.maximum_object_size  <br />说明：大于该值得对象将不被存储。如果你想要提高访问速度，就请降低该值；如果你想最大限度地节约带宽，降低成本，请增加该值。单位为K，缺省值为：  <br />maximum_object_size 4096 KB  <br /><br />5.1.3有关日志的选项  <br />1.cache_access_log  <br />说明：指定客户请求记录日志的完整路径（包括文件的名称及所在的目录），该请求可以是来自一般用户的HTTP请求或来自邻居的ICP请求。缺省值为：  <br />cache_access_log /var/log/squid/access.log  <br />如果你不需要该日志，可以用以下语句取消：cache_access_log none  <br />2.cache_store_log  <br />说明：指定对象存储记录日志的完整路径（包括文件的名称及所在的目录）。该记录表明哪些对象被写到交换空间，哪些对象被从交换空间清除。缺省路径为：  <br />cache_log /var/log/squid/cache.log  <br />如果你不需要该日志，可以用以下语句取消：cache_store_log none  <br />3.cache_log  <br />说明：指定squid一般信息日志的完整路径（包括文件的名称及所在的目录）。  <br />缺省路径为：cache_log /var/log/squid/cache.log  <br />4.cache_swap_log  <br />说明：该选项指明每个交换空间的“swap.log”日志的完整路径（包括文件的名称及所在的目录）。该日志文件包含了存储在交换空间里的对象的元数据（metadata）。通常，系统将该文件自动保存在第一个“cache_dir”说定义的顶级目录里，但是你也可以指定其他的路径。如果你定义了多个“cache_dir”，则相应的日志文件可能是这样的：  <br />cache_swap_log.00  <br />cache_swap_log.01  <br />cache_swap_log.02  <br />后面的数字扩展名与指定的多个“cache_dir”一一对应。  <br />需要注意的是，最好不要删除这类日志文件，否则squid将不能正常工作。  <br />5.pid_filename  <br />说明：指定记录squid进程号的日志的完整路径（包括文件的名称及所在的目录）。缺省路径为  <br />pid_filename /var/run/squid.pid  <br />如果你不需要该文件，可以用以下语句取消：pid_filename none  <br />6.debug_options  <br />说明：控制作日志时记录信息的多寡。可以从两个方面控制：section控制从几个方面作记录；level控制每个方面的记录的详细程度。推荐的方式（也是缺省方式）是：debug_options ALL,1  <br />即，对每个方面都作记录，但详细程度为1(最低)。  <br />7.log_fqdn on|off  <br />说明：控制在 access.log 中对用户地址的记录方式。打开该选项时，squid记录客户的完整域名，取消该选项时，squid记录客户的ip地址。注意，如果打开该选项会增加系统的负担，因为squid还得进行客户ip的DNS查询。缺省值为：log_fqdn off  <br /><br />5.1.4有关外部支持程序的选项  <br />1.ftp_user  <br />说明：设置登录匿名ftp服务器时的提供的电子邮件地址，登录匿名ftp服务器时要求用你的电子邮件地址作为登录口令（更多的信息请参看本书的相关章节）。需要注意的是，有的匿名ftp服务器对这一点要求很苛刻，有的甚至会检查你的电子邮件的有效性。缺省值为：ftp_user Squid@  <br />2.ftp_list_width  <br />说明：设置ftp列表的宽度，如果设得太小将不能的浏览到长文件名。缺省值为： ftp_list_width 32  <br />3.cache_dns_program  <br />说明：指定DNS查询程序的完整路径（包括文件的名称及所在的目录）。缺省路径为：  <br />cache_dns_program /usr/lib/squid/dnsserver  <br />4.dns_children  <br />说明：设置DNS查询程序的进程数。对于大型的登录服务器系统，建议该值至少为10。最大值可以是32，缺省设置为5个。注意，如果你任意的降低该值，可能会使系统性能急剧降低，因为squid主进程要等待域名查询的结果。没有必要减少该值，因为DNS查询进程并不会消耗太多的系统的资源。  <br />5.dns_nameservers  <br />说明：指定一个DNS服务器列表，强制squid使用该列表中的DNS服务器而非使用/etc/resolv.conf文件中定义的DNS服务器。你可以这样指定多个DNS服务器：dns_nameservers 10.0.0.1 192.172.0.4  <br />缺省设置为：dns_nameservers none  <br />6.unlinkd_program  <br />说明：指定文件删除进程的完整路径。  <br />缺省设置为：  <br />unlinkd_program /usr/lib/squid/unlinkd  <br />7.pinger_program  <br />说明：指定ping进程的完整路径。该进程被squid利用来测量与其他邻居的路由距离。该选项只在你启用了该功能时有用。缺省为：  <br />pinger_program /usr/lib/squid/pinger  <br />8.authenticate_program  <br />说明：指定用来进行用户认证的外部程序的完整路径。squid的用户认证功能我们将在后面的章节讲述。缺省设置为不认证。  <br /><br />5.1.5用户访问控制选项  <br />1.request_size (KB)  <br />说明：设置用户请求通讯量的最大允许值(单位为KB)。如果用户用POST方法请求时，应该设一个较大的值。缺省设置为：  <br />request_size 100 KB  <br />2.reference_age  <br />说明：squid根据对象的LRU（最近最少使用算法）来清除对象，squid依据使用磁盘空间的总量动态地计算对象的LRU年龄。我们用reference_age定义对象的最大LRU年龄。如果一个对象在指定的reference_age内没有被访问，squid将删除该对象。缺省值为一个月。你可以使用如下所示的时间表示方法。  <br />1 week  <br />3.5 days  <br />4 months  <br />2.2 hours  <br />3.quick_abort_min (KB)  <br />quick_abort_max (KB)  <br />quick_abort_pct (percent)  <br />说明：控制squid是否继续传输被用户中断的请求。当用户中断请求时，squid将检测  <br />quick_abort 的值。如果剩余部分小于“quick_abort_min”指定的值,squid 将继续完成剩余部分的传输；如果剩余部分大于“quick_abort_max”指定的值,squid 将终止剩余部分的传输；如果已完成“quick_abort_pct”指定的百分比，squid将继续完成剩余部分的传输。缺省的设置为：  <br />quick_abort_min 16 KB  <br />quick_abort_max 16 KB  <br />quick_abort_pct 95  <br /><br />5.1.6各类超时设置选项  <br />1.negative_ttl time-units  <br />说明：设置消极存储对象的生存时间。所谓的消极存储对象，就是诸如“连接失败”及"404 Not Found"等一类错误信息。缺省设置为：negative_ttl 5 minutes  <br />2.positive_dns_ttl time-units  <br />说明：设置缓存成功的DNS查询结果的生存时间。缺省为6小时。  <br />positive_dns_ttl 6 hours  <br />3.negative_dns_ttl time-units  <br />说明：设置缓存失败的DNS查询结果的生存时间。缺省为5分钟。  <br />negative_dns_ttl 5 minutes  <br />4.connect_timeout time-units  <br />说明：设置squid等待连接完成的超时值。缺省值为2分钟。  <br />connect_timeout 120 seconds  <br />5.read_timeout time-units  <br />说明：如果在指定的时间内squid尚未从被请求的服务器读入任何数据，则squid将终止该客户请求。缺省值为15分钟。  <br />read_timeout 15 minutes  <br />6.request_timeout  <br />说明：设置在建立与客户的连接后，squid将花多长时间等待客户发出HTTP请求。缺省值为30秒。  <br />request_timeout 30 seconds  <br />7.client_lifetime time-units  <br />说明：设置客户在与squid建立连接后，可以将该连接保持多长时间。  <br />注意，因为客户建立的每个连接都会消耗一定的系统资源，所以如果你是为一个大型网络提供代理服务的话，一定要正确地修改该值。因为如果同一时间的连接数量太大的话，可能会消耗大量的系统资源，从而导致服务器宕机。缺省值为1天，该值太大了，建议根据你自己的情况适当减小该值。  <br />client_lifetime 1 day  <br />8.half_closed_clients on/off  <br />说明：有时候由于用户的不正常操作，可能会使与squid的TCP连接处于半关闭状态，  <br />这时候，该TCP连接的发送端已经关闭，而接收端正常工作。缺省地，squid将一直保持这种处于半关闭状态的TCP连接，直到返回套接字的读写错误才将其关闭。如果将该值设为off，则一旦从客户端返回“no more data to read”的信息，squid就立即关闭该连接。half_closed_clients on  <br />9.pconn_timeout  <br />说明：设置squid在与其他服务器和代理建立连接后，该连接闲置多长时间后被关闭。缺省值为120秒。  <br />pconn_timeout 120 seconds  <br />10.ident_timeout  <br />说明：设置squid等待用户认证请求的时间。缺省值为10秒。  <br />ident_timeout 10 seconds  <br />11.shutdown_lifetime time-units  <br />说明：当收到SIGTERM 或者 SIGHUP 信号后, squid将进入一种shutdown pending的模式，等待所有活动的套接字关闭。在过了shutdown_lifetime所定义的时间后，所有活动的用户都将收到一个超时信息。缺省值为30秒。  <br />shutdown_lifetime 30 seconds  <br /><br />5.1.7管理参数选项  <br />1.cache_mgr  <br />说明:设置管理员邮件地址。缺省为：  <br />cache_mgr root  <br />2. cache_effective_user  <br />cache_effective_group  <br />说明：如果用root启动squid，squid将变成这两条语句指定的用户和用户组。缺省变为squid用户和squid用户组。注意这里指定的用户和用户组必须真是存在于/etc/passwd中。如果用非root帐号启动squid，则squid将保持改用户及用户组运行，这时候，你不能指定小于1024地http_port。  <br />cache_effective_user squid  <br />cache_effective_group squid  <br />3.visible_hostname  <br />说明：定义在返回给用户的出错信息中的主机名。  <br />如: visible_hostname www-cache.foo.org  <br />4.unique_hostname  <br />说明：如果你有一个代理服务器阵列，并且你为每个代理服务器指定了同样的“visible_hostname”，同时你必须为它们指定不同的“unique_hostname”来避免“forwarding loops ”（传输循环）发生。  <br /><br />5.1.8其它杂项  <br />1. dns_testnames  <br />说明：设置进行DNS查询测试,如果第一个站点解析成功则立即结束DNS查询测试。如果你不愿意进行DNS查询测试，就不要去掉缺省的设置。  <br />#dns_testnames netscape.com internic.net nlanr.net microsoft.com  <br />2.logfile_rotate  <br />说明：通常，squid会定期的将日志文件更名并打包。比如正在使用的日志文件为access.log,squid会将其更名并打包为access.log.1.gz；过了一定时间后，squid又会将  <br />access.log.1.gz更名为access.log.2.gz并将当前的日志文件更名并打包为access.log.1.gz，以此循环。logfile_rotate所指定的数字即为打包并备份的文件的数量，当达到这一数目时，squid将删除最老的备份文件。缺省值为10。如果你想手动来进行这些操作，你可以用logfile_rotate 0来取消自动操作。  <br />3.err_html_text  <br />说明：用该语句定义一个字符串变量，可以用％L在返回给用户的错误信息文件中引用。错误信息文件通常在/etc/squid/errors目录中，这是一些用HTML写成的脚本文件，你可以自己修改它。  <br />4.deny_info  <br />说明：你可以定制自定义的拒绝访问信息文件，并且可以和不同的用户列表相关联。当用户被http_access相关规则拒绝时，squid可以向用户显示你自定义的相应的拒绝访问信息文件。语法为：  <br />Usage: deny_info err_page_name acl  <br />比如：  <br />deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys  <br />5.memory_pools on|off  <br />说明:如果你将该项设为on，则squid将保留所有已经分配（但是未使用）的内存池以便在将来使用。缺省为on.  <br />memory_pools on  <br />6.log_icp_queries on|off  <br />说明：设置是否对ICP请求作日志。如果你的系统负载很大，你可以用off来取消该功能。缺省为:  <br />log_icp_queries on  <br />7.always_direct  <br />说明：该选项允许你指定某些用户类，squid将这些用户类的请求直接转发给被请求的服务器。语法为:  <br />always_direct allow|deny [!]aclname ...  <br />如：直接转发FTP请求可以这样设置：  <br />acl FTP proto FTP  <br />always_direct allow FTP  <br />8.never_direct  <br />说明：与always_direct相反。语法为：  <br />Usage: never_direct allow|deny [!]aclname ...  <br />比如，为了强制除了本地域的其他用户使用代理服务器，你可以这样设置：  <br />acl local-servers dstdomain foo.net  <br />acl all src 0.0.0.0/0.0.0.0  <br />never_direct deny local-servers  <br />never_direct allow all  <br />9.icon_directory  <br />说明：指明向用户传送错误信息时所用到的图标文件的目录。缺省路径为： icon_directory /usr/lib/squid/icons  <br />10.error_directory  <br />说明：指明向用户传送错误信息所用到的错误描述文件的目录。缺省路径为：  <br />error_directory /etc/squid/errors  <br /><br />5.2 用户认证设置  <br />缺省的，squid本身不带任何认证程序，但是我们可以通过外部认证程序来实现用户认证。一般说来有以下的认证程序：  <br />1.LDAP认证：你可以访问以下资源来获取更多的有用信息。  <br />http://www.geocities.com/ResearchTriangle/Thinktank/5292/projects/ldap/  <br />http://home.iae.nl/users/devet/squid/proxy_auth/contrib/ldap_auth.tar.gz  <br />2.SMB认证：可以实现基于NT和samba的用户认证。更多的信息请访问以下资源。  <br />http://www.hacom.nl/~richard/software/smb_auth.html  <br />3.基于mysql的用户认证。  <br />http://home.iae.nl/users/devet/squid/proxy_auth/contrib/mysql_auth.c  <br />4.基于sock5密码用户认证。  <br />http://nucleo.freeservers.com/  <br />5.基于Radius 的用户认证。  <br />http://home.iae.nl/users/devet/squid/proxy_auth/contrib/auth.pl  <br />但是我们一般常用的是用ncsa实现的认证和用smb_auth实现的基于NT和samba的用户认证。下面我们就来讲这两种认证方法的具体实现。  <br /><br />5.2.1 ncsa用户认证的实现  <br />ncsa是squid源代码包自带的认证程序之一，下面我们以squid-2.3.STABLE2版本为例讲述ncsa的安装和配置。  <br />1.从www.squid-cache.org下载squid源代码包squid-2.3.STABLE2-src.tar.gz并放到/tmp目录下。  <br />2.用tar解开：  <br />tar xvzf squid-2.3.STABLE2-src.tar.gz  <br />%make  <br />%make install  <br />3.然后，进入/tmp/squid-2.3.STABLE2/auth_modules/NCSA目录。  <br />% make  <br />% make install  <br />编译成功后，会生成ncsa_auth的可执行文件。  <br />4.拷贝生成的执行文件ncsa_auth到/usr/bin目录  <br />cp ncsa_auth /usr/bin/bin  <br />5.修改squid.conf中的相关选项如下所示：  <br />authenticate_program /usr/local/squid/bin/ncsa_auth /usr/bin/passwd  <br />6.定义相关的用户类  <br />acl auth_user proxy_auth REQUIRED  <br />注意，REQUIRED关键字指明了接收所有合法用户的访问。  <br />7.设置http_access  <br />http_access allow auth_user  <br />注意，如果你在改行中指定了多个允许访问的用户类的话，应该把要认证的用户类放在第一个。如下所示：  <br />错误的配置：http_access allow auth_user all manager  <br />正确的配置：http_access allow auth_user manager all  <br />8.利用apache携带的工具软件htpasswd在/usr/local/squid/etc下生成密码文件并添加相应的用户信息。一般说来，该密码文件每行包含一个用户的用户信息，即用户名和密码。  <br />用htpasswd生成密码文件passwd并添加用户bye。  <br />htpasswd -c /usr/local/squid/etc/passwd bye  <br />然后重新启动squid，密码认证已经生效。  <br /><br />5.2.2 smb用户认证的实现  <br />国内介绍并使用ncsa实现用户认证的文章不多，而使用smb_auth和samba实现基于NT的用户认证我还没有看到过，下面我们就来看一看在squid中实现基于NT的用户认证。  <br />当前smb_auth的最高版本是smb_auth-0.05，你可以在以下地址下载。当然，squid的源代码包中也包含smb_auth,但是是0.02版的。  <br />http://www.hacom.nl/~richard/software/smb_auth-0.05.tar.gz  <br />smb_auth的主页地址是http://www.hacom.nl/~richard/software/smb_auth.html。  <br />1.系统需求：  <br />squid2.0以上版本。  <br />安装samba2.0.4以上版本。你并不需要运行samba服务，因为smb_auth只用到了 samba的客户端软件。  <br />2.下载smb_auth-0.05.tar.gz并复制到/tmp.  <br />3.tar xvzf smb_auth-0.05.tar.gz  <br />4.根据你的要求修改Makefile中的SAMBAPREFIX和INSTALLBIN参数。SAMBAPREFIX指定了你的samba安装路径，INSTALLBIN指明了smb_auth的安装路径。我们指定：  <br />SAMBAPREFIX=/usr,INSTALLBIN=/usr/bin.  <br />5.make  <br />6.make install,成功后会在INSTALLBIN指定路径中生成可执行文件smb_auth.  <br />7.按下列步骤设置你要用于认证的主域控制器：  <br />首先在NETLOG共享目录中建立一个“proxy”文件，该文件只包含一个“allow”的字符串，一般说来，该NETLOG目录位于winntsystem32Replimportscripts目录中；然后，设置所有你想让其访问squid的用户和用户组拥有对该文件的读的权力。  <br />8.修改squid.conf中的相关选项如下所示：  <br />authenticate_program /usr/local/squid/bin/smb_auth your_domain_name  <br />9.定义相关的用户类  <br />acl auth_user proxy_auth REQUIRED  <br />注意，REQUIRED关键字指明了接收所有合法用户的访问。  <br />10.设置http_access  <br />http_access allow auth_user  <br />注意，如果你在改行中指定了多个允许访问的用户类的话，应该把要认证的用户类放在第一个。如下所示：  <br />错误的配置：http_access allow auth_user all manager  <br />正确的配置：http_access allow auth_user manager all  <br />如果一切正确的话，然后重新启动squid，密码认证已经生效。  <br />说明：smb_auth的调用方法：  <br />1.smb_auth -W your_domain_name  <br />用your_domain_name指定你的域名。smb_auth将进行广播寻找该主域控制器。  <br />2.smb_auth -W your_domain_name -B  <br />如果你有多个网络接口，可以用-B 指定用于广播的网络接口的ip地址。  <br />3.smb_auth -W your_domain_name -U  <br />也可以用-U直接指定该主域控制器的ip地址。  <br />4.smb_auth -W your_domain_name -S share  <br />可以用-S指定一个不同于NETLOG的共享目录。  <br /><br />5.2.3 squid.conf中关于认证的其他设置  <br />1.authenticate_children  <br />说明：设置认证子进程的数目。缺省为5个。如果你处于一个繁忙的网络环境中，你可以适当增大该值。  <br />2.authenticate_ttl  <br />说明：设置一次认证的有效期，缺省是3600秒。  <br />3.proxy_auth_realm  <br />说明：设置用户登录认证时向用户显示的域名。  <br /><br />5.3透明代理的设置  <br />关于透明代理的概念我们已经在第一节将过了，下面我们看一下怎么样在squid中实现透明代理。  <br />透明代理的实现需要在Linux 2.0.29以上，但是Linux 2.0.30并不支持该功能，好在我们现在使用的通常是2.2.X以上的版本，所以不必担心这个问题。下面我们就用ipchains+squid来实现透明代理。在开始之前需要说明的是,目前我们只能实现支持HTTP的透明代理，但是也不必太担心，因为我们之所以使用代理，目的是利用squid的缓存来提高Web的访问速度，至于提供内部非法ip地址的访问及提高网络安全性，我们可以用ipchains来解决。  <br />实现环境：RedHat6.x+squid2.2.x+ipchains  <br /><br />5.3.1 linux的相关配置  <br />确定你的内核已经配置了以下特性：  <li> Network firewalls  </li>[ ] Socket Filtering  <li> Unix domain sockets  </li><li> TCP/IP networking  </li>[ ] IP: multicasting  <br />[ ] IP: advanced router  <br />[ ] IP: kernel level autoconfiguration  <li> IP: firewalling  </li>[ ] IP: firewall packet netlink device  <li> IP: always defragment (required for masquerading)  </li><li> IP: transparent proxy support  </li>如果没有，请你重新编译内核。一般在RedHat6.x以上，系统已经缺省配置了这些特性。  <br /><br />5.3.2squid的相关配置选项  <br />设置squid.conf中的相关选项，如下所示：  <br />http_port 3218  <br />httpd_accel_host virtual  <br />httpd_accel_port 80  <br />httpd_accel_with_proxy on  <br />httpd_accel_uses_host_header on  <br />说明：  <br />1.http_port 3128  <br />在本例中，我们假设squid的HTTP监听端口为3128,即squid缺省设置值。然后，把所有来自于客户端web请求的包（即目标端口为80)重定向到3128端口。  <br />2.httpd_accel_host virtual  <br />httpd_accel_port 80  <br />这两个选项本来是用来定义squid加速模式的。在这里我们用virtual来指定为虚拟主机模式。80端口为要加速的请求端口。采用这种模式时，squid就取消了缓存及ICP功能，假如你需要这些功能，这必须设置httpd_accel_with_proxy选项。  <br />3.httpd_accel_with_proxy on  <br />该选项在透明代理模式下是必须设置成on的。在该模式下，squid既是web请求的加速器，又是缓存代理服务器。  <br />4.httpd_accel_uses_host_header on  <br />在透明代理模式下，如果你想让你代理服务器的缓存功能正确工作的话，你必须将该选项设为on。设为on时，squid会把存储的对象加上主机名而不是ip地址作为索引。这一点在你想建立代理服务器阵列时显得尤为重要。  <br /><br />5.3.3 ipchains的相关配置  <br />ipchains在这里所起的作用是端口重定向。我们可以使用下列语句实现将目标端口为80端口的TCP包重定向到3128端口。  <br />#接收所有的回送包  <br />/sbin/ipchains -A input -j ACCEPT -i lo  <br />#将目标端口为80端口的TCP包重定向到3128端口  <br />/sbin/ipchains -A input -p tcp -d 0.0.0.0/0 80 -j REDIRECT 80  <br />当然在这以前，我们必须用下面的语句打开包转发功能。  <br />echo 1 >; /proc/sys/net/ipv4/ip_forward  <br /><br />小节  <br />开始，我们讨论了代理服务器的概念，代理服务器的分类；然后，我们把注意力集中在squid，讲述了如何安装和配置squid；最后我们讲了一些squid配置中的高级话题，即实现用户认证的两种方法，透明代理的实现等。当然，还有一些高级话题本章没有讲到，如代理阵列的实现，加速模式的运用等等。但是，我们不可能把所有东西都讲完讲全，希望读者能举一反三，自己去摸索，去尝试。
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/48495#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Jan 2007 10:42:06 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/48495</link>
        <guid>http://jspengxue.javaeye.com/blog/48495</guid>
      </item>
      <item>
        <title>squid透明相关选项的说明 </title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48494" style="color:red;">http://jspengxue.javaeye.com/blog/48494</a>&nbsp;
          发表时间: 2007年01月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          5.3.2squid的相关配置选项  <br />设置squid.conf中的相关选项，如下所示：  <br /><pre name="code" class="java">http_port 3218  
httpd_accel_host virtual  
httpd_accel_port 80  
httpd_accel_with_proxy on  
httpd_accel_uses_host_header on </pre> <br />说明：  <br />1.http_port 3128  <br />在本例中，我们假设squid的HTTP监听端口为3128,即squid缺省设置值。然后，把所有来自于客户端web请求的包（即目标端口为80)重定向到3128端口。  <br />2.httpd_accel_host virtual  <br />httpd_accel_port 80  <br />这两个选项本来是用来定义squid加速模式的。在这里我们用virtual来指定为虚拟主机模式。80端口为要加速的请求端口。采用这种模式时，squid就取消了缓存及ICP功能，假如你需要这些功能，这必须设置httpd_accel_with_proxy选项。  <br />3.httpd_accel_with_proxy on  <br />该选项在透明代理模式下是必须设置成on的。在该模式下，squid既是web请求的加速器，又是缓存代理服务器。  <br />4.httpd_accel_uses_host_header on  <br />在透明代理模式下，如果你想让你代理服务器的缓存功能正确工作的话，你必须将该选项设为on。设为on时，squid会把存储的对象加上主机名而不是ip地址作为索引。这一点在你想建立代理服务器阵列时显得尤为重要。  <br /><br /><br />1．  Squid反向代理单个后台WEB服务器<br /><br />A、如果WEB服务器和反向代理服务器是两台单独的机器（一般的反向代理应该有两块网卡分别连接了内外部网络）。那么，应该修改下面的内容来设置反向代理服务。<br /><br /><pre name="code" class="java">http_port 80 # squid监听的端口

httpd_accel_host 192.168.0.100 # 内部WEB服务器的IP地址

httpd_accel_port 80 # WEB服务器的IP地址

httpd_accel_single_host on # 转发为缓冲的请求到一台单独的机器

httpd_accel_with_proxy on #

httpd_accel_uses_host_header off</pre><br /><br />       B、如果WEB服务器和反向代理服务器是同一台机器。那么，应该设置WEB服务器的监听端口为非80端口（比如：81端口）。要修改的内容如下： <br /><br /> <br /><br /><pre name="code" class="java">http_port 80 # squid监听的端口

httpd_accel_host localhost # 内部WEB服务器的IP地址

httpd_accel_port 81 # WEB服务器的IP地址

httpd_accel_single_host on # 转发为缓冲的请求到一台单独的机器

httpd_accel_with_proxy on #

httpd_accel_uses_host_header off</pre><br /><br />下面解释一下配置指令。 <br /><br />http_port 80 <br /><br />选项 http_port 指定squid监听HTTP请求的端口，一般都设置成80端口，这样使用户感觉不到反向代理的存在，就像访问真正的WEB服务器一样。<br /><br />httpd_accel_host 192.168.0.100 和 httpd_accel_port 80 <br /><br />选项httpd_accel_host 和 httpd_accel_port 指定WEB服务器的IP地址和端口号，可以根据自己的WEB服务器的实际情况而定。 <br /><br />httpd_accel_single_host on <br /><br />选项httpd_accel_single_host 为on 时，squid被设置成仅对单一的web服务器作反向代理。不考虑HTTP头信息，Squid转发所有的为被缓冲的页面请求到这个web服务器。如果squid需要做多个web服务器反向代理，必须将此选项设置为off，并且使用转向器或者DNS去映射请求到合适的后台WEB服务器。<br /><br />httpd_accel_with_proxy on <br /><br />如果希望squid既作反向代理服务器又作本地机器的上网代理，需要将httpd_accel_with_proxy 改为 on，默认情况下是off<br /><br />httpd_accel_uses_host_header off <br /><br />在HTTP协议1.1中，HTTP请求包括一个主机头信息，指定URL的主机名或者主机的IP地址。这个选项可以用来完成多个后台WEB服务器的反向代理功能。<br /><br /> <br /><br />2.    Squid反向代理多个后台WEB服务器<br /><br />我们可以用Squid反向代理多个后台WEB服务器。例如：我们可以配置squid同时反向代理www.xxx.com, www.yyy.com, www.zzz.com三个后台WEB服务器， <br /><br />       <br /><br />Squid的配置如下：<br /><br /><pre name="code" class="java">httpd_accel_host virtual

httpd_accel_port 80

httpd_accel_single_host off

httpd_accel_uses_host_header on</pre><br /><br />注意:编译Squid时需激活Internal DNS选项: --disable-internal-dns<br /><br /> <br /><br /> <br /><br />然后设置设置反响代理需要的域名解析（加入hosts）如下：<br /><br /> <br /><pre name="code" class="java">
<a href="http://www.xxx.com" target="_blank">www.xxx.com</a> 111.222.333.444

<a href="http://www.yyy.com" target="_blank">www.yyy.com</a> 111.222.333.444

<a href="http://www.zzz.com" target="_blank">www.zzz.com</a> 111.222.333.444</pre><br /><br />使三个域名都指向反向代理服务器的IP地址111.222.333.444。<br /><br />下面设置反向代理所需要的DNS入口信息（即设置内部DNS，仅仅是squid在内部使用，Internet用户不可见）。有两种方法可以设置内部DNS，使用内部DNS服务器来解析或者使用/etc/hosts文件来实现。<br /><br />使用内部DNS服务器的资源记录如下：<br /><br /><br /><pre name="code" class="java">www.xxx.com IN A 192.168.0.101

<a href="http://www.yyy.com" target="_blank">www.yyy.com</a> IN A 192.168.0.102

<a href="http://www.zzz.com" target="_blank">www.zzz.com</a> IN A 192.168.0.103</pre><br /><br />如果使用/etc/hosts文件来实现内部DNS（编译时应使用disable internal dns选项）,编辑/etc/hosts文件添加如下条目：<br /><br /><pre name="code" class="java">192.168.0.101 www.xxx.com

192.168.0.102 www.yyy.com

192.168.0.103 www.zzz.com</pre><br /><br /><br /><br />在局域网通过透明代理访问外部的web服务器时,<br />在web服务器端,<br />通过header  HTTP_X_FORWARDED_FOR 可以知道代理服务器的服务器名以及端口,<br />通过HTTP_VIA可以知道客户的内部ip,这会带来一些安全问题,并且某些论坛会发现用的是代理访问,<span style="color: red">怎么让squid隐藏这些信息</span>呢.<br />通过研究squid的源代码,发现在/etc/squid/squid.conf中添加2行:<br />       <pre name="code" class="java">header_access Via deny all
       header_access X-Forwarded-For deny all</pre>就可以把它关闭<br /><br /><br />要去掉其他的header,也可以照此操作
          <br/>
          <span style="color:red;">
            <a href="http://jspengxue.javaeye.com/blog/48494#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Jan 2007 10:40:22 +0800</pubDate>
        <link>http://jspengxue.javaeye.com/blog/48494</link>
        <guid>http://jspengxue.javaeye.com/blog/48494</guid>
      </item>
      <item>
        <title>Java多线程程序设计详细解析</title>
        <author>jspengxue</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jspengxue.javaeye.com">jspengxue</a>&nbsp;
          链接：<a href="http://jspengxue.javaeye.com/blog/48395" style="color:red;">http://jspengxue.javaeye.com/blog/48395</a>&nbsp;
          发表时间: 2007年01月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          一、理解多线程<br /><br />　　多线程是这样一种机制，它允许在程序中并发执行多个指令流，每个指令流都称为一个线程，彼此间互相独立。<br /><br />　　线程又称为轻量级进程，它和进程一样拥有独立的执行控制，由操作系统负责调度，区别在于线程没有独立的存储空间，而是和所属进程中的其它线程共享一个存储空间，这使得线程间的通信远较进程简单。<br /><br />　　多个线程的执行是并发的，也就是在逻辑上“同时”，而不管是否是物理上的“同时”。如果系统只有一个CPU，那么真正的“同时”是不可能的，但是由于CPU的速度非常快，用户感觉不到其中的区别，因此我们也不用关心它，只需要设想各个线程是同时执行即可。<br /><br />　　多线程和传统的单线程在程序设计上最大的区别在于，由于各个线程的控制流彼此独立，使得各个线程之间的代码是乱序执行的，由此带来的线程调度，同步等问题，将在以后探讨。<br /><br />　　二、在Java中实现多线程<br /><br />　　我们不妨设想，为了创建一个新的线程，我们需要做些什么？很显然，我们必须指明这个线程所要执行的代码，而这就是在Java中实现多线程我们所需要做的一切！<br /><br />　　真是神奇！Java是如何做到这一点的？通过类！作为一个完全面向对象的语言，Java提供了类java.lang.Thread来方便多线程编程，这个类提供了大量的方法来方便我们控制自己的各个线程，我们以后的讨论都将围绕这个类进行。<br /><br />　　那么如何提供给 Java 我们要线程执行的代码呢？让我们来看一看 Thread 类。Thread 类最重要的方法是run()，它为Thread类的方法start()所调用，提供我们的线程所要执行的代码。为了指定我们自己的代码，只需要覆盖它！<br /><br />　　方法一：继承 Thread 类，覆盖方法 run()，我们在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。下面是一个例子：<br /><br />　　public class MyThread extends Thread<br />　　{<br />　　int count= 1, number;<br />　　public MyThread(int num)<br />　　{<br />　　number = num;<br />　　System.out.println<br />　　("创建线程 " + number);<br />　　}<br />　　public void run() {<br />　　while(true) {<br />　　System.out.println<br />　　("线程 " + number + ":计数 " + count);<br />　　if(++count== 6) return;<br />　　}<br />　　}<br />　　public static void main(String args[])<br />　　{<br />　　for(int i = 0;<br />　　i 〈 5; i++) new MyThread(i+1).start();<br />　　}<br />　　}<br />　　<br />　　这种方法简单明了，符合大家的习惯，但是，它也有一个很大的缺点，那就是如果我们的类已经从一个类继承（如小程序必须继承自 Applet 类），则无法再继承 Thread 类，这时如果我们又不想建立一个新的类，应该怎么办呢？<br /><br />　　我们不妨来探索一种新的方法：我们不创建Thread类的子类，而是直接使用它，那么我们只能将我们的方法作为参数传递给 Thread 类的实例，有点类似回调函数。但是 Java 没有指针，我们只能传递一个包含这个方法的类的实例。<br /><br />　　那么如何限制这个类必须包含这一方法呢？当然是使用接口！（虽然抽象类也可满足，但是需要继承，而我们之所以要采用这种新方法，不就是为了避免继承带来的限制吗？）<br /><br />　　Java 提供了接口 java.lang.Runnable 来支持这种方法。<br /><br />　　方法二：实现 Runnable 接口<br /><br />　　Runnable接口只有一个方法run()，我们声明自己的类实现Runnable接口并提供这一方法，将我们的线程代码写入其中，就完成了这一部分的任务。但是Runnable接口并没有任何对线程的支持，我们还必须创建Thread类的实例，这一点通过Thread类的构造函数 public Thread(Runnable target);来实现。下面是一个例子：<br /><br />　　public class MyThread implements Runnable<br />　　{<br />　　int count= 1, number;<br />　　public MyThread(int num)<br />　　{<br />　　number = num;<br />　　System.out.println("创建线程 " + number);<br />　　}<br />　　public void run()<br />　　{<br />　　while(true)<br />　　{<br />　　System.out.println<br />　　("线程 " + number + ":计数 " + count);<br />　　if(++count== 6) return;<br />　　}<br />　　}<br />　　public static void main(String args[])<br />　　{<br />　　for(int i = 0; i 〈 5;<br />　　i++) new Thread(new MyThread(i+1)).start();<br />　　}<br />　　}<br />　　<br />　　严格地说，创建Thread子类的实例也是可行的，但是必须注意的是，该子类必须没有覆盖 Thread 类的 run 方法，否则该线程执行的将是子类的 run 方法，而不是我们用以实现Runnable 接口的类的 run 方法，对此大家不妨试验一下。<br /><br />　　使用 Runnable 接口来实现多线程使得我们能够在一个类中包容所有的代码，有利于封装，它的缺点在于，我们只能使用一套代码，若想创建多个线程并使各个线程执行不同的代码，则仍必须额外创建类，如果这样的话，在大多数情况下也许还不如直接用多个类分别继承 Thread 来得紧凑。<br /><br />　　综上所述，两种方法各有千秋，大家可以灵活运用。<br /><br />　　下面让我们一起来研究一下多线程使用中的一些问题。<br /><br />　　三、线程的四种状态<br /><br />　　1. 新状态：线程已被创建但尚未执行（start() 尚未被调用）。<br /><br />　　2. 可执行状态：线程可以执行，虽然不一定正在执行。CPU 时间随时可能被分配给该线程，从而使得它执行。<br /><br />　　3. 死亡状态：正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果，但是不被推荐，前者会产生异常，后者是强制终止，不会释放锁。<br /><br />　　4. 阻塞状态：线程不会被分配 CPU 时间，无法执行。<br /><br />　　四、线程的优先级<br /><br />　　线程的优先级代表该线程的重要程度，当有多个线程同时处于可执行状态并等待获得 CPU 时间时，线程调度系统根据各个线程的优先级来决定给谁分配 CPU 时间，优先级高的线程有更大的机会获得 CPU 时间，优先级低的线程也不是没有机会，只是机会要小一些罢了。<br /><br />　　你可以调用 Thread 类的方法 getPriority() 和 setPriority()来存取线程的优先级，线程的优先级界于1(MIN_PRIORITY)和10(MAX_PRIORITY)之间，缺省是5(NORM_PRIORITY)。<br /><br />　　五、线程的同步<br /><br />　　由于同一进程的多个线程共享同一片存储空间，在带来方便的同时，也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突，有效避免了同一个数据对象被多个线程同时访问。<br /><br />　　由于我们可以通过 private 关键字来保证数据对象只能被方法访问，所以我们只需针对方法提出一套机制，这套机制就是 synchronized 关键字，它包括两种用法：synchronized 方法和 synchronized 块。<br /><br />　　1. synchronized 方法：通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如：<br /><br />　　public synchronized void accessVal(int newVal);<br />　　<br />　　 synchronized 方法控制对类成员变量的访问：每个类实例对应一把锁，每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行，否则所属线程阻塞，方法一旦执行，就独占该锁，直到从该方法返回时才将锁释放，此后被阻塞的线程方能获得该锁，重新进入可执行状态。<br /><br />　　这种机制确保了同一时刻对于每一个类实例，其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态（因为至多只有一个能够获得该类实例对应的锁），从而有效避免了类成员变量的访问冲突（只要所有可能访问类成员变量的方法均被声明为 synchronized）。<br /><br />　　在 Java 中，不光是类实例，每一个类也对应一把锁，这样我们也可将类的静态成员函数声明为 synchronized ，以控制其对类的静态成员变量的访问。<br /><br />　　synchronized 方法的缺陷：若将一个大的方法声明为synchronized 将会大大影响效率，典型地，若将线程类的方法 run() 声明为 synchronized ，由于在线程的整个生命期内它一直在运行，因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中，将其声明为 synchronized ，并在主方法中调用来解决这一问题，但是 Java 为我们提供了更好的解决办法，那就是 synchronized 块。<br /><br />　　2. synchronized 块：通过 synchronized关键字来声明synchronized 块。语法如下：<br /><br />　　synchronized(syncObject)<br />　　{<br />　　//允许访问控制的代码<br />　　}<br />　　<br />　　synchronized 块是这样一个代码块，其中的代码必须获得对象 syncObject （如前所述，可以是类实例或类）的锁方能执行，具体机制同前所述。由于可以针对任意代码块，且可任意指定上锁的对象，故灵活性较高。<br /><br />　　六、线程的阻塞<br /><br />　　为了解决对共享存储区的访问冲突，Java 引入了同步机制，现在让我们来考察多个线程对共享资源的访问，显然同步机制已经不够了，因为在任意时刻所要求的资源不一定已经准备好了被访问，反过来，同一时刻准备好了的资源也可能不止一个。为了解决这种情况下的访问控制问题，Java 引入了对阻塞机制的支持。<br /><br />　　阻塞指的是暂停一个线程的执行以等待某个条件发生（如某资源就绪），学过操作系统的同学对它一定已经很熟悉了。Java 提供了大量方法来支持阻塞，下面让我们逐一分析。<br /><br />　　1. sleep() 方法：sleep() 允许指定以毫秒为单位的一段时间作为参数，它使得线程在指定的时间内进入阻塞状态，不能得到CPU 时间，指定的时间一过，线程重新进入可执行状态。典型地，sleep() 被用在等待某个资源就绪的情形：测试发现条件不满足后，让线程阻塞一段时间后重新测试，直到条件满足为止。<br /><br />　　2. suspend() 和 resume() 方法：两个方法配套使用，suspend()使得线程进入阻塞状态，并且不会自动恢复，必须其对应的resume() 被调用，才能使得线程重新进入可执行状态。典型地，suspend() 和 resume() 被用在等待另一个线程产生的结果的情形：测试发现结果还没有产生后，让线程阻塞，另一个线程产生了结果后，调用 resume() 使其恢复。<br /><br />　　3. yield() 方法：yield() 使得线程放弃当前分得的 CPU 时间，但是不使线程阻塞，即线程仍处于可执行状态，随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。<br /><br />　　4. wait() 和 notify() 方法：两个方法配套使用，wait() 使得线程进入阻塞状态，它有两种形式，一种允许指定以毫秒为单位的一段时间作为参数，另一种没有参数，前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态，后者则必须对应的 notify() 被调用。<br /><br />　　初看起来它们与 suspend() 和 resume() 方法对没有什么分别，但是事实上它们是截然不同的。区别的核心在于，前面叙述的所有方法，阻塞时都不会释放占用的锁（如果占用了的话），而这一对方法则相反。<br /><br />　　上述的核心区别导致了一系列的细节上的区别。<br /><br />　　首先，前面叙述的所有方法都隶属于 Thread 类，但是这一对却直接隶属于 Object 类，也就是说，所有对象都拥有这一对方法。初看起来这十分不可思议，但是实际上却是很自然的，因为这一对方法阻塞时要释放占用的锁，而锁是任何对象都具有的，调用任意对象的 wait() 方法导致线程阻塞，并且该对象上的锁被释放。<br /><br />　　而调用 任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞（但要等到获得锁后才真正可执行）。<br /><br />　　其次，前面叙述的所有方法都可在任何位置调用，但是这一对方法却必须在 synchronized 方法或块中调用，理由也很简单，只有在synchronized 方法或块中当前线程才占有锁，才有锁可以释放。<br /><br />　　同样的道理，调用这一对方法的对象上的锁必须为当前线程所拥有，这样才有锁可以释放。因此，这一对方法调用必须放置在这样的 synchronized 方法或块中，该方法或块的上锁对象就是调