分类归档: Programming

编程编程编程。。。

SQL的基本命令和几个常用函数汇总

–创建对象(表、视图、存储过程、函数)命令]
CREATE TABLE/VIEW/PROCEDURE/FUNCTION
–创建表
CREATE TABLE tabTestVB
(VbName varchar(10),value numeric(10))
GO
CREATE TABLE tabTestVB1
(VbName varchar(10),value1 numeric(10))
GO
–插入数据(两种方式)
INSERT INTO tabTestVB(VbName,value)
SELECT ‘AAA’,123
INSERT INTO tabTestVB1(VbName,value1)
SELECT ‘AAA’,456

INSERT INTO tabTestVB(VbName,value) VALUES (‘BBB’,345)
INSERT INTO tabTestVB1(VbName,value1) VALUES (‘CCC’,1002)
–更改数据
UPDATE tabTestVB SET value=798 WHERE VbName=’AAA’
–关联更改
UPDATE tabTestVB SET value=tabTestVB1.value1
FROM tabTestVB1 WHERE tabTestVB.VbName=tabTestVB1.VbName
–删除数据
DELETE tabTestVB WHERE VbName=’AAA’
–无日志删除数据
TRUNCATE TABLE tabTestVB
–删除对象(表、视图、存储过程、函数)命令
DROP TABLE/VIEW/PROC/FUNCTION
–删除表
DROP TABLE tabTestVB
DROP TABLE tabTestVB1
–赋值命令
SET
–定义变量
DECLARE

–流程控制语句
WHILE … BREAK
BEGIN … END
IF …ELSE
—-1…100 的和
DECLARE @NN NUMERIC(3)
DECLARE @SUM NUMERIC(8)
SET @NN=1
SET @SUM=0
WHILE @NN<=100
BEGIN
   SET @SUM=@SUM+@NN
   SET @NN=@NN+1
END
SELECT @SUM

–加上条件:当@NN=20 时退出循环(计算出1…19的和)
DECLARE @NN NUMERIC(3)
DECLARE @SUM NUMERIC(8)
SET @NN=1
SET @SUM=0
WHILE @NN<=100
BEGIN
   IF @NN<>20
    –BEGIN
    SET @SUM=@SUM+@NN
    –END
   ELSE
    –BEGIN
    BREAK
    –END
   SET @NN=@NN+1
END
SELECT @SUM

–全局变量
@@ROWCOUNT
–返回受上一语句影响的行数
SELECT ‘1’
UNION ALL
SELECT ‘3’
SELECT @@ROWCOUNT

@@ERROR
–返回最后执行的 Transact-SQL 语句的错误代码。
SET @N =1
SELECT @@ERROR

—-函数的使用
–返回当前日期
SELECT GETDATE()

–生成16进制的标志列uniqueidentifier
SELECT NEWID()

–转换数据类型和格式
SELECT CONVERT(VARCHAR(10),GETDATE(),120)

Read: 722

CSS下拉菜单

<!DOCTYPE html PUBliC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>css菜单演示</title>

<style type="text/css">
<!–

*{margin:0;padding:0;border:0;}
body {
   宋体, serif;
        ;
}

#nav {
   line-height: 24px; list-style-type: none; ;
}

#nav a {
   display: block; width: 80px; text-align:center;
}

#nav a:link {
   color:#666; text-decoration:none;
}
#nav a:visited {
   color:#666;text-decoration:none;
}
#nav a:hover {
   color:#FFF;text-decoration:none;;
}

#nav li {
   float: left; width: 80px; ;
}
#nav li a:hover{
   ;
}
#nav li ul {
   line-height: 27px; list-style-type: none;text-align:left;
   left: -999em; width: 180px; ;
}
#nav li ul li{
   float: left; width: 180px;
   ;
}

#nav li ul a{
   display: block; width: 180px;w idth: 156px;text-align:left;padding-left:24px;
}

#nav li ul a:link {
   color:#666; text-decoration:none;
}
#nav li ul a:visited {
   color:#666;text-decoration:none;
}
#nav li ul a:hover {
   color:#F3F3F3;text-decoration:none;;
   ;
}

#nav li:hover ul {
   left: auto;
}
#nav li.sfhover ul {
   left: auto;
}
#content {
   clear: left;
}

–>
</style>

<script type=text/"") + "sfhover";
       }
       sfEls[i].onMouseDown=function() {
       this.className+=(this.className.length>0? " ": "") + "sfhover";
       }
       sfEls[i].onMouseUp=function() {
       this.className+=(this.className.length>0? " ": "") + "sfhover";
       }
       sfEls[i].onmouseout=function() {
       this.className=this.className.replace(new RegExp("( ?|^)sfhover b"),

"");
       }
   }
}
window.onload=menuFix;

//–><!]]></script>

</head>
<body>

<ul >
<li><a href="#">产品介绍</a>
   <ul>
   <li><a href="#">产品一</a></li>
   <li><a href="#">产品一</a></li>
   <li><a href="#">产品一</a></li>
   <li><a href="#">产品一</a></li>
   <li><a href="#">产品一</a></li>
   <li><a href="#">产品一</a></li>
   </ul>
</li>
<li><a href="#">服务介绍</a>
   <ul>
   <li><a href="#">服务二</a></li>
   <li><a href="#">服务二</a></li>
   <li><a href="#">服务二</a></li>
   <li><a href="#">服务二服务二</a></li>
   <li><a href="#">服务二服务二服务二</a></li>
   <li><a href="#">服务二</a></li>
   </ul>
</li>
<li><a href="#">成功案例</a>
   <ul>
   <li><a href="#">案例三</a></li>
   <li><a href="#">案例</a></li>
   <li><a href="#">案例三案例三</a></li>
   <li><a href="#">案例三案例三案例三</a></li>
   </ul>
</li>
<li><a href="#">关于我们</a>
   <ul>
   <li><a href="#">我们四</a></li>
   <li><a href="#">我们四</a></li>
   <li><a href="#">我们四</a></li>
   <li><a href="#">我们四111</a></li>
   </ul>
</li>

<li><a href="#">在线演示</a>
   <ul>
   <li><a href="#">演示</a></li>
   <li><a href="#">演示</a></li>
   <li><a href="#">演示</a></li>
   <li><a href="#">演示演示演示</a></li>
   <li><a href="#">演示演示演示</a></li>
   <li><a href="#">演示演示</a></li>
   <li><a href="#">演示演示演示</a></li>
   <li><a href="#">演示演示演示演示演示</a></li>
   </ul>
</li>
<li><a href="#">联系我们</a>
   <ul>
   <li><a href="#">联系联系联系联系联系</a></li>
   <li><a href="#">联系联系联系</a></li>
   <li><a href="#">联系</a></li>
   <li><a href="#">联系联系</a></li>
   <li><a href="#">联系联系</a></li>
   <li><a href="#">联系联系联系</a></li>
   <li><a href="#">联系联系联系</a></li>
   </ul>
</li>

</ul>

</body>
</html>

Read: 689

[转]Session详解

摘要:虽然session机制在web应用程序中被采用已经很长时间了,但是仍然有很多人不清楚session机制的本质,以至不能正确的应用这一 技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。

目录:
一、术语session
二、HTTP协议与状态保持
三、理解cookie机制
四、理解session机制
五、理解javax.servlet.http.HttpSession
六、HttpSession常见问题
七、跨应用程序的session共享
八、总结
参考文档

session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的 一系列过程可以称之为一个session。有时候我们可以看到这样的话“在一个浏览器会话期间,…”,这里的会话一词用的就是其本义,是指从一个浏览 器窗口打开到关闭这个期间①。最混乱的是“用户(客户端)在一次会话期间”这样一句话,它可能指用户的一系列动作(一般情况下是同某个具体目的相关的一系 列动作,比如从登录到选购商品到结账登出这样一个网上购物的过程,有时候也被称为一个transaction),然而有时候也可能仅仅是指一次连接,也有 可能是指含义①,其中的差别只能靠上下文来推断②。

然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义,“面向连接”指的是在通信双方在通信之 前要先建立一个通信的渠道,比如打电话,直到对方接了电话通信才能开始,与此相对的是写信,在你把信发出去的时候你并不能确认对方的地址是否正确,通信渠 道不一定能建立,但对发信人来说,通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来,使得消息之间可以互相依赖,比如一个服务员 能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session”③。

而到了web服务器蓬勃发展的时代,session在web开发语境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器之间保持状态的 解决方案④。有时候session也用来指这种解决方案的存储结构,如“把xxx保存在session里”⑤。由于各种用于web开发的语言在一定程度上 都提供了对这种解决方案的支持,所以在某种特定语言的语境下,session也被用来指代该语言的解决方案,比如经常把Java里提供的 javax.servlet.http.HttpSession简称为session⑥。

鉴于这种混乱已不可改变,本文中session一词的运用也会根据上下文有不同的含义,请大家注意分辨。
在本文中,使用中文“浏览器会话期间”来表达含义①,使用“session机制”来表达含义④,使用“session”表达含义⑤,使用具体的“HttpSession”来表达含义⑥

然而聪明(或者贪心?)的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用,就像给有线电视加上点播功能一 样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求,作为传输载体 的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的 session机制则是又一种在客户端与服务器之间保持状态的解决方案。

让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:
1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。

由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在 客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个 标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。

cookie机制的基本原理就如上面的例子一样简单,但是还有几个问题需要解决:“会员卡”如何分发;“会员卡”的内容;以及客户如何使用“会员卡”。

正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的 cookie。然而纯粹的客户端脚本如 PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html

这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分

浏览器在再次访问goolge的资源时自动向外发送cookie

使用Firefox可以很容易的观察现有的cookie的值
使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。

IE也可以设置在接受cookie前询问

这是一个询问接受cookie的对话框。

当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 – 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。

保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于 SEEESIONID,而。比如weblogic对于web应用程序生成的cookie,JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是 JSESSIONID。

由于cookie可以被人为的禁止,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种,一种是作为URL路径的附加信息,表现形式为http://…../xxx; jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
另一种是作为查询字符串附加在URL后面,表现形式为http://…../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。
为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如下面的表单
<form action="/xxx">
<input type="text">
</form>
在被传递给客户端之前将被改写成
<form action="/xxx">
<input type="hidden" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
这种技术现在已较少应用,笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。
实际上这种技术可以简单的用对action应用URL重写来代替。

在谈论session机制的时候,常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动 对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保 留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所 以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的 HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。

恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。

首先,Weblogic Server提供了一系列的参数来控制它的HttpSession的实现,包括使用cookie的开关选项,使用URL重写的开关选项,session持 久化的设置,session失效时间的设置,以及针对cookie的各种设置,比如设置cookie的名字、路径、域,cookie的生存时间等。

一般情况下,session都是存储在内存里,当服务器进程被停止或者重启的时候,内存里的session也会被清空,如果设置了session的 持久化特性,服务器就会把session保存到硬盘上,当服务器进程重新启动或这些信息将能够被再次使用,Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。

复制严格说来不算持久化保存,因为session实际上还是保存在内存里,不过同样的信息被复制到各个cluster内的服务器进程中,这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。

cookie生存时间的柚迷蚧嵊跋熹 榔魃 傻腸ookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。

cookie的路径对于web应用程序来说是一个非常重要的选项,Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。

关于session的设置参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

1、session在何时被创建
一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某 server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <%@page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。

由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。

2、session何时被删除
综合前面的讨论,session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止(非持久session)

3、如何做到在浏览器关闭时删除session
严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用

7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session
参见第三小节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。

8、如何防止用户打开两个浏览器窗口操作导致的session混乱
这个问题与防止表单多次提交是类似的,可以通过设置客户端的令牌来解决。 就是在服务器每次生成一个不同的id返回给客户端,同时保存在session里,客户端提交表单时必须把这个id也返回服务器,程序首先比较返回的id与 保存在session里的值是否一致,如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使 用" >

根据这个特性,我们可以推测Tomcat中session的内存结构大致如下。

笔者以前用过的iPlanet也采用的是同样的方式,估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器,解决的思路很 简单,实际实行起来也不难。要么让所有的应用程序共享一个session id,要么让应用程序能够获得其他应用程序的session id。

iPlanet中有一种很简单的方法来实现共享一个session id,那就是把各个应用程序的cookie路径都设为/(实际上应该是/NASApp,对于应用程序来讲它的作用相当于根)。
<session-info>
<path>/NASApp</path>
</session-info>

需要注意的是,操作共享的session应该遵循一些编程约定,比如在session attribute名字的前面加上应用程序的前缀,使得setAttribute("name", "neo")变成setAttribute("app1.name", "neo"),以防止命名空间冲突,导致互相覆盖。

在Tomcat中则没有这么方便的选择。在Tomcat版本3上,我们还可以有一些手段来共享session。对于版本4以上的 Tomcat,目前笔者尚未发现简单的办法。只能借助于第三方的力量,比如使用文件、数据库、JMS或者客户端cookie,URL参数或者隐藏字段等手 段。

我们再看一下Weblogic Server是如何处理session的。

从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/,这是不是意味着在Weblogic Server中默认的就可以共享session了呢?然而一个小实验即可证明即使不同的应用程序使用的是同一个session,各个应用程序仍然只能访问 自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下

对于这样一种结构,在session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量,比如使用文件、数据库、 JMS或者客户端cookie,URL参数或者隐藏字段等手段,还有一种较为方便的做法,就是把一个应用程序的session放到 ServletContext中,这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下,

应用程序A
context.setAttribute("appA", session);

应用程序B
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");

值得注意的是这种用法不可移植,因为根据ServletContext的JavaDoc,应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值,以上做法在Weblogic Server 8.1中通过。

那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢?原来是为了SSO,凡是共享这个session的应用程序都可以共享认证的信息。一 个简单的实验就可以证明这一点,修改首先登录的那个应用程序的描述符weblogic.xml,把cookie路径修改为/appA访问另外一个应用程序 会重新要求登录,即使是反过来,先访问cookie路径为/的应用程序,再访问修改过路径的这个,虽然不再提示登录,但是登录的用户信息也会丢失。注意做 这个实验时认证方式应该使用FORM,因为浏览器和web服务器对basic认证方式有其他的处理方式,第二次请求的认证不是通过session来实现 的。具体请参看[7] secion 14.8 Authorization,你可以修改所附的示例程序来做这些试验。

Read: 783

[转] 编 程 之 道

编 程 之 道
Geoffrey James

第一篇 静寂的空宇
第二篇 古代的大师
第三篇 设计
第四篇 编码
第五篇 维护
第六篇 管理
第七篇 公司里的学问
第八篇 硬件和软件
第九篇 尾声

第一篇 静寂的空宇
编程大师如是说:
“当你有本事夺走我手中的这块水晶石时,就是你出师的时侯了。”
1.1
在静寂的空宇里,一种神奇的物质形成并诞生了。它立刻便静止了,独自守侯着,豪无动静,然而又处于永恒的运动之中。它是所有程序的源头,我不知道它的名字,所以我将称它为编程之道。

如果此道是完美的,那些操作系统就是完美的,如果操作系统是完美的,那么编译程序就是完美的,如果编译程序是完美的,那么应用程序就是完美的。用户满意之至--和谐便应运而生。

编程之道流逝远去,又乘着晨风而归。
1.2
此道产生了机器语言,机器语言又产生了汇编语言,
汇编语言产生了编译程序,如今有了上万种的语言。
每一种语言都有其各自的卑微用途。每一种语言都表达出软件的阴和阳。每一种语言都在此道之中有其一席之地。
但是,应尽量避免用COBOL语言编写程序。
1.3
宇宙之初有道,道产生了空间和时间。空间和时间便是程序设计之阴阳。
不能领悟此道的编程者总是耗尽他们所要编写的程序的时间和空间;而领悟了此道的编程者却总有足够的时间和空间来达到他们的目标。
除此之外,难道还有其它的情形吗? 1.4
精明的编程者听说了此道,并遵循它;平庸的编程者听说了此道,并寻觅它;愚蠢的编程者听说了此道,却嘲笑它。
要不是因为有嘲笑,道也就不复存在了。
最高的声音最难被听见。前进也是一种倒退。大器晚成。即使是一个完美的程序也仍然会有隐患。
道深藏不露,难于理解。

第二篇 古代的大师
编程大师如是说:
“倘若三天不编程,生活将变得毫无意义。”
2.1
老一辈的程序员是神秘的、深奥的。我们没法揣摩他们的想法,我们所能做的只是描述一下他们的表象。
他们是清醒的,就像一只游过水面的狐狸;
他们是警惕的,就像一位战场上的将军;
他们是友善的,就像一位招待客人的女主人;
他们是简单的,就像未经刻凿的木头;
他们还是难以琢磨的,就像黑暗的洞穴中漆黑的池水。
谁能说出他们心中的秘密?
答案只存在于道中。
2.2
计算机科学巨擘图灵曾经梦到他是一台机器。当他醒来时,他惊叹道:
“我不知道--我是梦到了自己是台机器的图灵,还是一台梦到了自己是图灵的机器?”
2.3
一家大电脑公司的一名程序员参加了一次软件研讨会。他回来后向经理汇报说:“为其它公司工作的那些程序员都是些什么的人啊?他们行为拙劣,不顾及自己的仪表。他们的头发又长又乱,衣服又皱又旧。他们闯进我们的会客组,还在我演讲时发生粗鲁的喧闹。”

经理说:“我本不应该让你去参加这个会议。那些程序员是生活在物质世界之外的。他们认为生活是荒唐的,一种意外的巧合。他们来去自如。他们只为他们的程序而活着,无忧无虑地活着。为什么要用社会习俗来约束他们呢?

他们活在此道之中。”
2.4
一个礼堂者问大师:“有位程序员,从不构思、编写文档或测试他的程序,然而所有知道他的人都认为他是世界上最棒的程序员。这是为什么呢?”
大 师回答说:“那个人掌握了道。他不需要事先进行构思,当系统崩溃时,他不会因此而闷闷不乐,而是心平气和地接受整个事实。他还从编写程序说明文档的需要之 中超脱了出来,不在意是否有人看他的编码。他也不需要进行测试。他的每个程序都完美无缺。宁静而优雅,程序的用途也显而易见。
的的确确,他已经进入了道的神奇境界。”

第三篇 设计
编程大师如是说:
“当程序被测试时,再修改设计方案就太迟了。”
3.1
曾经有个人去参加一次电脑展示会,每天当他进入展馆时,都对门卫说:
“我是个大盗,我偷盗的本领是出了名的。事先警告你,这次展示会也在劫难逃。”
这番话让门卫坐立不安,因为里面有价值数百万美元的电脑设备,所以他紧紧地盯住这个人。但这个人只是从一个展摊逛到另一个展摊,嘴里轻轻地哼着小曲。
当这个人出门时,门卫把他拉到一边,搜查他的衣服,但一无所获。
第二天,这个人又来了,并对着门卫嚣张地嚷着:“昨天我满载而归,但今天的收获会更大。”于是,门卫盯他盯得更紧了,但仍一无所获。
在展示会的最后一天,门卫再也抑制不住自己的好奇心了。“大盗先生,”门卫说,“我被你搞糊涂了,实在想不明白。请告诉我,你究竟在偷什么?”
这个人笑了。“我在偷想法。”他说。
3.2
曾经有位编程大师,喜欢编写非结构化的编程。一位初学者试图模仿他,也开始编写非结构化的程序。当这位徒弟请师父评价他的进展时,师父批评了他的做法。他说:“对一位编程高手适合的,对初学者来说并不一定适合。在超越结构化之前,你必须先领悟道。”

3.3
曾经有位程序员被派到IBM的军机大臣手下工作。军机大臣问程序员:“设计一个财务软件包,和设计一个操作系统,哪一个更容易?”
“操作系统。”程序员回答说。
军机大臣立刻发生一种不信任的惊叹,“与一个复杂的操作系统,一个财务软件包简直是小巫见大巫。”他说。
“并 非如此,”程序员说,“在设计一个财务软件包时,编程人员是作为一个中介者在观念各异的人们之间起作用的:这个软件必须如何操作,它的报表必须是什么形 式,它必须如何与税法一致,等等,一个操作系统则不为其外观所限制。当设计一个操作系统时,编程人员只要在机器与人的思维之间寻找一种最简单的和谐就可以 了。这就是为什么操作系统更容易设计。”

军机大臣点点头,笑了。“说来也是。但要想检测和纠正其中的错误,哪个更容易呢?”
程序员没有回答。
3.4
一位经理到编程大师那里,交给他一份有关一个新应用程序的需求说明。经理问编程大师:“如果我分配五个程序员给你,你需要多久能设计好这个系统?”
“那将花费一年的时间。”大师立刻回答。
“但我们马上就需要这个系统,甚至要求更快!如果我分配十个程序员给你,你需要多长时间?”
大师皱了皱眉头,“那样的话,需要两年。”
“如果我分配一百个程序员给你怎么样?”
大师耸了耸肩膀,“那么这项设计将永远无法完成。”他说

第四篇 编码
编程大师如是说:
“一个写得完美的程序是其自身的天堂,而一个写得糟糕的程序则是其自身的地狱。”
4.1
一个程序应当是轻盈的、灵活的,它的子程序就像一串珍珠一样连接着。它的精神和意图应该贯穿始终。在程序中,内容既不应太多,也不应太少;既不应该有不需要的循环结构,也不该有冗余的变量;既不缺乏结构性,又不过分僵化。

一个程序,无论多么复杂,都应该以一个整体的方式运行。程序应以其内在的逻辑为指引,而非外在形态。
如果一个程序不能达到这些要求,它将处于一种杂乱无章的混淆不清的状态。唯一的方法就是重写这个程序。
4.2
一位初学者问大师:“我有个程序,时灵时不灵。我一直都遵循着编程的规则,结果却整个儿搞糊涂了。这是什么原因呢?”
大师回答说:“因为你没有领悟道,所以你迷惑不解。只有傻瓜才会指望从人类身上看到理性的行为,你又能指望一台人类制造的机器怎么样呢?计算机模仿的是决定论,只有道才是尽善尽美。

编程用的那些条条框框式的规则仅仅是昙花一现,只有道才是永恒的。因此,在你受到道的启发之前,你必须沉思于道。”
“但是我怎样才能知道我已经受到了启发了呢?”初学者问。
“当你的程序运行无误时。”大师回答说。
4.3
一位大师正在向他的一名初学编程的弟子解释道的真谛。“此道体现在所有的软件当中--不管它看上去多么无足轻重。”大师说着。
“此道体现在手掌计算器中吗?”初学者问。
“是的。”
“此道在电子游戏中吗?”初学者继续问。
“此道甚至也体现在电子游戏之中。”大师说。
“那么此道也体现在个人电脑的DOS系统之中吗?”
大师咳嗽一声,并稍稍挪动了一下位置。“今天的课就到这里吧。”他说。
4.4
一位项目经理手下的一名程序员正编写软件。他的手指在键盘上飞舞着,在程序的编译过程中没有出现任何错误信息。程序运行起来就像一阵和风。
“太好了!”经理高兴地大叫了起来,“你的技艺简直是完美无缺。”
“技 艺?”程序员说着便从他的终端机前转过身来,“我遵循的是道--所有的技艺远不能及!当我刚开始编程时,我眼前看见的是整个问题乱成一团。三年之后,我再 也看不见这种一团糟的情形了。相反,我用了各种各样的子程序。但现在,我什么也看不见了。我的整个身心存在于一种无形的虚空里,我的知觉是空荡荡的。

我 的精神随其本能而动,不无原则计划就能自由地工作。总而言之,是我的程序自己写出了自己。诚然,有时会有一些难题。我看见那些难题向我走来,于是我放慢了 速度,默默地注视着他们。然后我更改了一行编码,那些问题就烟消云散了。然后我完成程序的编译。我静静地坐着,让工作的欢心情舒畅遍布我的全身。我闭上双 眼,歇息片刻,然后退出系统。”
经理说,“希望我的所有的程序员都这么聪明!”

第五篇 维护
编程大师如是说:
“即使一个程序只有三行长,总有一天它也不得不需要维护。”
5.1
一记扇经常开启的门的绞链不需要润滑油。
一条湍急的河流不会变得污浊。
无论是声音还是想法都不可能在真空中传播。
软件如果不用就会腐朽。
这世界真奇妙。
5.2
一个程序员正在编写他的程序,经理问他还需要多长时间完成。
“明天就可以完成。”程序员立刻回答。
“我想你这是不切实际,”经理说,“实话实说,这需要多长时间?”
程序员想了一会儿。“我还想加进一些新的特色,这需要花至少两个星期的时间。”他最后说。
“即使那样也期望过高,”经理坚持说,“只要你编完程序时告诉我一声,我也就满足了。”
程序员答应了。
几年以后,那位经理要退休了。在他去退休午餐会的路上。他发现那个程 序员趴在他的终端机前睡着了。整个晚上都在忙于编写那个程序。
5.3
一次一位初学编程者被指派编写一个简单的财务软件包。这位初学者大张旗鼓地工作了许多天。但当他的师父检查这套程序时,发现其中包含有一个屏幕编辑器,一套通用图表程序,一个人工智能界面,然而却没有任何财务方面的东西。

当师父问及此事时,初学者显得愤愤不平。“不要这样没有耐心嘛,”他说,“我最后加些财务的素材进去就是了。”
5.4
难道一位好农民会漏掉他所种的一株庄稼吗?
难道一位好老师会放弃哪怕是最差的学生吗?
难道一位好父亲会允许哪一个孩子挨饿吗?
难道一位好程序员会不愿维护他的程序吗?

第六篇 管理
编程大师如是说:
“让程序员多而经理少--然后生产效率就会高。”
6.1
当经理们没完没了地开会时,程序员就写些游戏玩;当财务主管们谈到季度利润时,开发用的预算马上就要被削减;当资深科学家们谈论蓝蓝的天空时,马上就会风起云涌。
其实,这并不是编程之道。
当经理们忠于职守时,游戏程序就会被搁置到一边;财务主管们制订出长 远的计划时,和谐秩序将很快恢复;当资深科学家们着手于眼前的问题时,这些问题不久就会解决。
其实,这才是编程之道。
6.2
为什么程序员没有效率?
因为他们的时间浪费在开会上。
为什么程序员很难管束?
因为管理层多管闲事。
为什么程序员接二连三地辞职?
因为他们的热情已耗尽。
在糟糕的管理之下工作,他们不再敬业。
6.3
一位经理即将被解职,但此时他手下的一名程序员发明了一个新的程序。这个程序流行起来,并且极为畅销。结果,经理又回到了原来的岗位上。
经理试图要发给那位程序员一笔资金,但程序员拒绝了。他说:“我写这个程序,因为我认为这是个很有意思的想法。我并不期望有所回报。”
经理听到这话,评论说:“这位程序员虽然身居卑位,却能很好地理解一位雇员应尽的职责。让我们提拔他到管理顾问的高位上吧!”
然而,接到通知后,那位程序员又一次拒绝了。他说:“我在属于我的位置上,才能较好地编程。如果我被提升了,除了浪费每个人的时间,我将一事无成。现在我可以走了吗?我还有一个程序要编呢。”

6.4
一位经理走过来对他的程序员们说:“关于你们的上班时间:你们要早上九点钟到,下午五点钟下班。”听了这话,所有的程序员都很气愤,其中有几位要当场辞职。
于是,经理只好又说:“好吧,那样的话,你们可以自己安排上班时间,只要你们能按时完成项目。”程序员们满意了。以后,他们中午来到办公室,一起工作到凌晨。

第七篇 公司里的学问
编程大师如是说:
“你可以向一位公司总裁演示一个程序,但你无法使他学会使用电脑。”
7.1
一 位初学者问大师:“在东方(此处喻指美国的东海岸,有许多大公司的总部--译注),有一个不寻常的树状结构,人们称它为‘公司总部’。它的副总裁们和财务 主管们的数量之大,使它鼓得不成开关。它签发大师的便函,每份上都写着”归去”“来兮”,却没有人知道那是什么意思。它的那些分支机构每年都要换新的名 字,但都毫无价值。如此一个不正常的实体怎么能继续存在呢?”

大师回答说:“你探察这个庞大的邓因其没有合理的用途而心神不定。难道你不能从它那无尽的回旋中得到乐趣吗?你不会享受一下在它所蔽护的部分里的编程的那种无忧无虑的轻松吗?你为什么要因为它毫无用处而心烦意乱呢?”

7.2
在东方,有一条大鱼,比其它所有的鱼都要大。它变成了一只鸟,它的翅膀就像云朵一个布满了天空。当这只鸟飞过陆地时,它带来了“公司总部”的消息,像蜻蜓点水一样把这个消息丢在了那些程序员中间。然后这只鸟驾着风,背负蓝天,返回了家园。

初学编程者惊奇地盯着那只鸟,因为他根本无法理解;平庸的程序员畏惧那只鸟的到来,因为他害怕鸟儿带来的消息;而编程大师却仍然在他的终端机前工作,因为他不知道那只鸟来了又去了。

7.3
象牙塔里的魔术师带来了他最新的发明,要让编程大师检验一下。魔术师把一只大黑箱子推进办公室,大师静静地等侯着。
“这是一台集成的、分布式的、通用的工作站,”魔术师开始,“运用人类工程学原理,使用享有专利的操作系统、第六代评议和多重状态用户界面而设计完成。建造这台工作站,花了我几百名助手几年的时间。这不足以令人惊奇吗?”

大师轻轻地扬了扬眉毛。“这的确令人惊奇。”他说。
“公司总部已经命令,”魔术师继续说,“每个人都得使用这台工作站作为操作平台来设计新的程序。你同意吗?”
“当然同意,”大师说,“我马上就把它运到数据中心去。”于是魔术师兴高采烈地回到了象牙塔去了。
几天后,一位初学者走进大师的办公室问道:“我找不到我的新程序清单了。你知道它会放在哪儿吗?”
“知道,”大师回答说,“那些清单就堆放在数据中心的台子(platform“可以指操作平台”,也可以指普通的台子--译注)上。”
7.4
编程大师从不惧怕在设计不同程序的岗位间调来调去;管理层的变动不可能对他有所损害;他不会被解雇,即使项目取消了。这是为什么呢?因为他胸有成“道”。

第八篇 硬件和软件
编程大师如是说:
“没有风,草儿静止不动;没有软件,硬件则无所为用。”
8.1
一位初学者问大师:“我觉察到有一家电脑公司比其它所有的公司都要大得多。它在中遥遥领先,就如同鹤立鸡群一般。它的任意一个部门都可以组成一个完整的企业。这是为什么呢?”

大 师回答说:“你怎么问这么愚蠢的问题呢?因为那家公司大,所以它就大嘛。如果它仅仅生产硬件,没人愿买;如果它仅仅生产软件,没人愿用;如果它仅仅维护一 下系统,人们将把它当作是佣人。然而,因为它把所有这些东西都结合了起来,它便摇身一变,被人们看作是诸神之一。不费吹灰之力,它便能取胜。

8.2
一天,一位大师从初学编程者身边经过,他发现这位初学者正在全神贯注于掌上电脑游戏。“对不起,”他说,”我可以看一下吗?”
初学者立刻紧张起来,把那个玩意儿递给了大师。“我知道这种设备提供了三个游戏级别:容易、中等和高难,”大师说,“然而每个这样的设备都有另一个级别,在这一级,游戏机既不想赢人,也不想被人打败。”

“请问,尊敬的大师,”初学者恳求道,“怎样才能找到这个奇妙的级别设置呢?”
大师把那个玩意儿扔到地上,踩到粉碎。突然间,那个初学者明白了什么。
8.3
曾 经有一个程序员,擅长在微电脑上编程,“瞧,我在这里过得多好呀,”他对另一位来访的程序员说,这位程序员是在大型主机上工作的,“我有自己的操作系统和 文件存储设备,我不必和其他任何人分享我的资源。这里的软件自相一致,很容易使用。你为何不辞去现在的工作,加入到我这里来呢?”

于 是,主机程序员开始向他的这位朋友描绘他的系统:“主机就像一位陷入沉思的圣人一样,端坐在数据中心。它的磁盘器首尾声相连,就如同机器的海洋。这里的软 件既像钻石一样能多面反射光芒,又像原始丛林一样复杂难测。这里的程序,各具特色,它们像湍急的河流穿过系统。这就是我乐于此处的原因。

微电脑程序员听到这里,陷入了沉默。但这两位程序员至死都保持着友谊。
8.4
在去硅谷的路上,硬件碰上了软件。软件说:“你是阴,我是阳。如果我们携手同路,我们将闻名于世,并能赚大笔的钱。”于是,这一对阴和阳便一同往前走,想着怎么征服世界。

不 一会儿,他们遇到了固件(firmware,硬件和软件结合在一起的部件,如IC卡--译注),他衣衫褴褛,手里拄着根带刺的拐杖,蹒跚地走着。固件对他 们说:“道存在于阴、阳之外。它默默无闻,静如止水。它不追求名誉,所以没人知道它的存在;它不追求财富,因其自身完整圆满。它存在于空间和时间之外。”
软件和硬件,自觉惭愧,掉头回家去了。

第九章 尾声
编程大师如是说:
“现在该是你出师的时侯了。”

Read: 690

WinPcap 教程

原文出处:http://winpcap.polito.it/docs/man/html/index.html
作者:
Loris Degioanni (degioanni@polito.it), NetGroup, Politecnico di Torino
http://winpcap.polito.it
概述:
这 篇教程将会指引读者逐步了解WinPcap编程, 从简单的基础函数(获取网络接口列表, 捕捉数据包)到更高级的内容(处理发送队列, 网络流量统 计). 教程中包括一些代码片断, 以及一些简单但完整的例子, 读者可以参考这些例子更好的理解教程的内容. 这些例子全部用C语言写成, 所以基本的 C语言编程知识是必要. 同时, 因为这篇教程的内容是与底层网络紧密相连的, 所以笔者假设读者已经具备有关网络和协议的相关知识.
译者的话:
WinPcap 是一套免费的, 基于Windows的网络接口API, 它在底层网络操作方面对程序员很有帮助. 这篇文档翻译自 "WinPcap Documentation 3.0" 中的 "WinPcap tutorial: a step by step guide to program WinPcap" 一部分. 这篇教程对初学者的帮助很大, 尤其是简短清晰的例 子, 但这篇教程只是整个文档的一小部分, 我认为你仍然需要参考文档的其它部分来了解各种结构等信息. 教程中注有前缀 "Y-" 的部分是译者为了让 读者更明白作者的意思添加的, 原文中没有.
1. 获取网络接口列表
通常, 一个基于WinPcap的应用程序所要做的第一件 事, 就是获得适合的网络接口的列表. Libpcap中的pcap_findalldevs()函数就是干这活的: 这个函数然回一个pcap_if结 构的列表, 每个元素都记录了一个接口的信息. 其中, name和description以人类可以阅读的形式, 记录了设备的信息.
下面的源代码输出可用的网络接口的列表, 并且在没有找到任何借口的情况下输出错误信息:

代码  
#include "pcap.h"
main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
/* 取得列表 */
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %sn", errbuf);
exit(1);
}
/* 输出列表 */
for(d=alldevs;d;d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)n", d->description);
else
/* Y- 没有有效的描述 */
printf(" (No description available)n");
}
if(i==0)
{
/* Y- 没有有效的接口, 可能是因为没有安装WinPcap */
printf("nNo interfaces found! Make sure WinPcap is installed.n");
return;
}
/* 我们不再需要列表了, 释放 */
pcap_freealldevs(alldevs);
}

我们来看看这段代码.
首 先, 和其他的libpcap函数一样, pcap_findalldevs(), 有一个错误缓冲区(errbuf)参数. 这个参数是一个字符串指 针, 一旦发生错误,libpcap将会在这里填入错误描述. 然后, 请注意, pcap_findalldev系统下的s()函数同时也被UNIX下 的libpcap所支持, 但是并不是所有的操作系统都支持“网络接口描述”(description)这一项. 所以, 如果我们想写一个可以移植的的 应用程序,那么我们必须要为描述为“空”(null)的情况做好准备:遇到这种情况我们就输出一个“没有有效的描述”的消息.
最后我们通过pcap_freealldevs()函数来释放接口列表.
现在让我们编译并运行我们的第一个WinPcap程序. 如果你使用UNIX或者Cgywin的话, 你只需要以下命令:
gcc -o testaprog testprog.c -lpcap
在Windows环境中(Y – 如果你使用Microsoft Visual C++), 你需要建立一个工程, 按照"Using WinPcap in your programs " 一节中说明来做.
不过, 我仍然建议你参照Winpcap开发者包(WinPcap developer’s pack)中的例子, 那些例子包括了所以配置完善的工程, 以及全部你所需要的库和包含文件.
(Y – 你可以在本章最后找到Microsoft Visual C++ 的配置方法)
假设现在你已经成功编译了程序, 我们就来运行它. 在我的WinXP工作站上, 输出结果是:
1. {4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter)
2. {5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI)
就如你所看到的, 网络接口的名称(当打开这个接口时, 需要传递这个名称给libpcap库)在windows环境下几乎是没有办法读懂的(Y-严重同意), 所以输出一个描述对于你的用户来说是非常有帮助的.

附注: Microsoft Visual C++ 工程的设置
1. 下载并安装 WinPcap, 推荐的版本是3.0
2. 从 http://winpcap.polito.it 下载 WinPcap Developer’s Pack 并解压缩
3. 用 Microsoft Visual C++ 建立一个空工程 (empty project)
4. 复制源代码
5. 把 Winpcap Developer’s Pack 中的 Includes 目录添加为新的包含文件目录
6. 添加库 wpcap.lib 和 wsock32.lib
原文出处:http://winpcap.polito.it/docs/man/html/index.html
作者:
Loris Degioanni (degioanni@polito.it), NetGroup, Politecnico di Torino
http://winpcap.polito.it
2. 获取设备的高级信息
上 一课我们介绍了如何获取一个设备的基本信息(比如设备名称和设备描述). 实际上, WinPcap 也可以为我们提供关于接口的更多信息. 由 pcap_findalldevs() 函数返回的 pcap_if 结构也包含了一个 pcap_addr 结构的列表, 它记录了以下信息:
1. 接口的地址列表
2. 接口的掩码列表 (与地址列表一一对应)
3. 接口的广播地址列表 (与地址列表一一对应)
4. 目标地址列表 (与地址列表一一对应)
下面例子中的 ifprint() 函数将会输出 pcap_if 结构的全部内容. 它包括了 pcap_findalldevs() 函数所返回的所有元素. ( Y- 全部有效接口)

代码  

/*
* Copyright (c) 1999 – 2002
* Politecnico di Torino. All rights reserved.

Read: 761