2012年9月20日星期四

转:利用.htaccess 保護網頁

摘自: http://blog.csdn.net/wghshy/article/details/628126

網站上的網頁, 一般說來都是開放給所有人來瀏覽, 但是有時候, 某些網頁希望只讓特定的人瀏覽, 此時可利用密碼確認與來源 IP 管制這兩種方式來過濾使用者.

要對瀏覽網頁的人作密碼確認與來源 IP 管制, 最簡單的就是透過 .htaccess 了 
 

透過 .htaccess 替網頁作密碼保護

  1. 首先建立一個要用密碼來保護的目錄 (如 secure)
  2. 在這個目錄下建立一個 .htaccess 的檔案, 內容如下


    AuthUserFile /user1/staff/tung/public_html/secure/.passwd 
    AuthGroupFile /dev/null 
    AuthName  "access" 
    AuthType Basic

    <Limit GET> 
    require valid-user 
    </Limit>

    上面這個檔案會把整個 security 目錄 (含所有子目錄), 都用紅色部份所標明的 .passwd 保護起來, 任何想要瀏覽 security 目錄內網頁的人, 都必須輸入正確的使用者名稱與密碼才行 
     

  3. 建立 .passwd 這個密碼檔


    cd security 
    htpasswd -c .passwd test 
    然後輸入一組密碼 
    上面這個命令會建立 .passwd 這個檔, 並放入使用者 test 與其密碼

    如果你希望多放幾個使用者到密碼檔裡, 那麼繼續 
    htpasswd .passwd test2 
    並輸入 test2 的密碼

    要注意只有在第一次時才要用 -c 這個參數, 它代表重新建立一個密碼檔, 如果在密碼檔已存在的情形下使用 -c 這個參數, 密碼檔舊有記錄會被清除

    .passwd 檔案是一個普通的文字檔, 你可以用一般的文書編輯器去處理它, 刪除不要的使用者名稱與密碼 
     

  4. 最後將要被保護的網頁放到 .htaccess 所在的子目錄中
測試一下 
(name=test, passwd=111 或 name=test2, passwd=222) 
 

透過 .htaccess 替網頁作來源 IP 管制

比如說你希望只有來自 *.ncku.edu.tw 或是 140.116.* 的使用者才能瀏覽你的網頁, 請在上述的 .htaccess 檔案中, 加入下列片段即可

<Limit GET> 
order deny,allow 
deny from all 
allow from .ncku.edu.tw 
allow from 140.116. 
</Limit>

如果你要保護的是 CGI 程式所在的目錄, 除了要產生上述的 .htaccess 檔案外, 還要把 <Limit GET> 這行改成<Limit GET POST PUT> 才行 

转:如何实现一个应用程序只能打开一个进程

摘自:http://it.114study.com/program/article369328.html

    在开发过程中可以使用互斥对象控制应用程序只能打开一个进程。避免误操作或其他原因造成因同时打开多个应用程序而使数据录入或统计错误。本例是在工程单元中打开互斥对象,如果句柄为0,说明互斥对象不存在,创建互斥对象并运行程序,如果句柄大于0,说明存在互斥对象,程序直接退出,主要代码如下:
    if  OpenMutex(MUTEX_ALL_ACCESS,True,'Mutex')=0 then 
      begin 
       CreateMutex(nil,True,'Mutex'); 
       Application.Initialize; 
       Application.CreateForm(TForm1, Form1); 
       Application.Run; 
       CloseHandle(OpenMutex(MUTEX_ALL_ACCESS,True,'Mutex')); 
      end;

    使用CreateMutex函数创建互斥对象。 
    语法格式如下: 
    Handle CreateMutex( 
       LPSECURITY_ATTRIBUTES lpMutexAttributes, 
       BOOL bInitialOwner,     
       LPCTSTR lpName 
       );

    参数说明 
    lpMutexAttributes:安全属性。 
    BInitialOwner:指定互斥对象是否拥有所有者标识。值为true时,程序创建的Create Process 方法能够继承互斥对象句柄。 
    LpName:创建的互斥对象名称。 
    Return_Value:返回创建的互斥对象句柄。

    使用OpenMutex函数打开互斥对象。 
    语法格式如下: 
    Handle OpenMutex( 
       DWORD dwDesiredAccess,      // access flag 
       BOOL bInheritHandle,    // inherit flag 
       LPCTSTR lpName        // pointer to mutex-object name 
       );

    参数说明 
    dwDesiredAccess:访问标识。 
    BInheritHandle:继承标识。 
    LpName:互斥对象名称 
    Return_Value:返回打开的互斥对象句柄。


转:Delphi实现程序只运行一次并激活已打开的程序

Delphi实现程序只运行一次并激活已打开的程序

我们的程序有时候只允许运行一次,并且最好的情况是,如果程序第二次运行,就激活原来的程序。网上有很多的方法实现程序只运行一次,但对于激活原来的窗口却都不怎么好。
关键就在于激活原来的程序,一般的做法是在工程开始时,打开互斥量对象,如果打不开表示程序还没有运行,创建一个互斥量对象;如果打得开表示程序已经运行了,查找程序中一个特定的窗口,一般是主窗口,然后发送一个自定义消息,主窗口在这个消息处理中激活自己。我原来就是这么做的,却发现有很多问题。
主窗口在消息处理函数中激活不了自己,众所周知激活一个窗口最有效的方法当然就是SetForegroundWindow,但在主窗口中调用这个函数激活自己的效果却是只在标题栏闪了一闪,如果在其他进程调用该函数则不会有问题;另外,如果程序是最小化的,它连闪都不闪了。
对于这些问题,我想了下面的办法,在知道原程序已经运行后,用FindWindow找原程序主窗口的句柄,找到了,就发送一个自定义消息过去,而在原程序主窗口的消息处理函数中,只是调用Application.Restore方法,这样如果原程序是最小化的就会还原过来。在发送消息之后,紧接着我调用SetForegroundWindow并传入原程序主窗口的句柄,由于上面的处理,原程序肯定不是最小化了,且调用SetForegroundWindow的地方已经不是原程序了(是第二次运行的程序,也可以说是另一个进程),所以原程序可以很好的被激活。
看来一切都很好,当然不是,不然就不会有下面的代码了,我又发现了一些问题,首先当主窗体不是活动窗口时,比如主窗体被隐藏了,而目前活动的窗体是其他窗体,则上面的代码无效。另一个,如果主窗体前面有一个ShowModal的窗体,则上面的代码后,主窗体跑到ShowModal窗体的前面了。
只有继续探索了,看来问题出在SetForegroundWindow上,激活那个窗体都不好,因为那个窗体都有可能不在,有没有办法激活工程呢,我在Application中找方法,我找到Application.BringToFront,也许这个有点用,于是新建一个工程,加一个Timer控件,然后每隔3秒调用一次Application.BringToFront,运行看结果。可惜窗体仍然只是闪一下,并没有激活,这和我上面说的在自己进程中激活自己的结果一样,可能BringToFront方法里面也调用了SetForegroundWindow了吧,但它激活哪个窗口呢,这让我好奇,打开源码来看,看到了如下有代码:
procedure TApplication.BringToFront;
var
  TopWindow: HWnd;
begin
  if Handle <> 0 then
  begin
    TopWindow := GetLastActivePopup(Handle);
    if (TopWindow <> 0) and (TopWindow <> Handle) and
      IsWindowVisible(TopWindow) and IsWindowEnabled(TopWindow) then
      SetForegroundWindow(TopWindow);
  end;
end;
原来是用GetLastActivePopup这个API找到程序拥有的窗体中最近激活的窗体,然后再激活它。
哈,我有了一个技术方案,首先我要在第二次运行的程序中找到第一次运行的程序的Application的Handle,然后调用SendMessage(APPHandle, WM_SYSCOMMAND, SC_RESTORE, 0),Application类有处理这个消息的,最终它会调用Application.Restore方法,让自己变为显示的状态,即最大化或正常。接着,就执行上面方法中的代码,让第一次运行的程序激活。现在关键是怎么找到第一次运行的Application的Handle,自然而然就想到了共享内存的技术,程序第一次运行时,先打开一个内存映射文件,如果打不开,则表示程序第一次运行,建一个内存映射文件对象,开辟一块共享的内存,这块内存保存Application的Handle。程序第二次运行,打开内存映射文件,可以打开了,得到一块共享内存,并取得了第一次运行程序的Application的Handle,然后,用我上面说的方法,即可大功告成。
花了一个小时的试验,最终有了下面的代码,结果非常成功:
unit wdRunOnce;

{*******************************************
 * brief: 让程序只运行一次
 * autor: linzhenqun
 * date: 2005-12-28
 * email: linzhengqun@163.com
 * blog: http://blog.csdn.net/linzhengqun
********************************************}

interface

(* 程序是否已经运行,如果运行则激活它 *)
function AppHasRun(AppHandle: THandle): Boolean;


implementation
uses
  Windows, Messages;

const
  MapFileName = '{CAF49BBB-AF40-4FDE-8757-51D5AEB5BBBF}';

type
  //共享内存
  PShareMem = ^TShareMem;
  TShareMem = record
    AppHandle: THandle;  //保存程序的句柄
  end;

var
  hMapFile: THandle;
  PSMem: PShareMem;

procedure CreateMapFile;
begin
  hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(MapFileName));
  if hMapFile = 0 then
  begin
    hMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
      SizeOf(TShareMem), MapFileName);
    PSMem := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
    if PSMem = nil then
    begin
      CloseHandle(hMapFile);
      Exit;
    end;
    PSMem^.AppHandle := 0;
  end
  else begin
    PSMem := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
    if PSMem = nil then
    begin
      CloseHandle(hMapFile);
    end
  end;
end;

procedure FreeMapFile;
begin
  UnMapViewOfFile(PSMem);
  CloseHandle(hMapFile);
end;

function AppHasRun(AppHandle: THandle): Boolean;
var
  TopWindow: HWnd;
begin
  Result := False;
  if PSMem <> nil then
  begin
    if PSMem^.AppHandle <> 0 then
    begin
      SendMessage(PSMem^.AppHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
      TopWindow := GetLastActivePopup(PSMem^.AppHandle);
      if (TopWindow <> 0) and (TopWindow <> PSMem^.AppHandle) and
        IsWindowVisible(TopWindow) and IsWindowEnabled(TopWindow) then
        SetForegroundWindow(TopWindow);
      Result := True;
    end
    else
      PSMem^.AppHandle := AppHandle;
  end;
end;

initialization
  CreateMapFile;

finalization
  FreeMapFile;

end.
 
你所要做的,就是将这个单元加进你的程序中,然后在你的工程文件中调用AppHasRun,并传入Application的Handle,你的程序就可以只运行一次了,工程大概如下:
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1}
  wdRunOnce in 'wdRunOnce.pas',
  Unit2 in 'Unit2.pas' {Form2}

{$R *.res}

begin
  Application.Initialize;
  if not AppHasRun(Application.Handle) then
    Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
多新建一些窗口测试一下吧,不过要注意新建的窗口得不能是自动创建的。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/air_supply1118/archive/2006/08/30/1143115.aspx

摘自:http://www.cnblogs.com/talo/articles/1677946.html

[转]Sniffer抓包软件学习(二)----- 数据报文解码详解


本章主要对:数据报文分层、以太报文结构、IP协议、ARP协议、PPPOE协议、Radius协议等的解码分析做了简单 的描述,目的在于介绍Sniffer软件在协议分析中的功能作用并通过解码分析对协议进一步了解。对其其他协议读者可以通过协议文档和Sniffer捕获 的报文对比分析。

1.1   数据报文分层

如下图所示,对于四层网络结构,其不同层次完成不通功能。每一层次有众多协议组成。


如上图所示在Sniffer的解码表中分别对每一个层次协议进行解码分析。链路层对应"DLC";网络层对应"IP";传输层对应"UDP";应用层对对 应的是"NETB"等高层协议。Sniffer可以针对众多协议进行详细结构化解码分析。并利用树形结构良好的表现出来。

1.2   以太报文结构

EthernetII以太网帧结构

Ethernet_II以太网帧类型报文结构为:目的MAC地址(6bytes)+源MAC地址+(6bytes)上层协议类型(2bytes)+数据字段(46-1500bytes)+校验(4bytes)。
           
Sniffer会在捕获报文的时候自动记录捕获的时间,在解码显示时显示出来,在分析问题时提供了很好的时间记录。

源目的MAC地址在解码框中可以将前3字节代表厂商的字段翻译出来,方便定位问题,例如网络上2台设备IP地址设置冲突,可以通过解码翻译出厂商信息方便 的将故障设备找到,如00e0fc为华为,010042为Cisco等等。如果需要查看详细的MAC地址用鼠标在解码框中点击此MAC地址,在下面的表格 中会突出显示该地址的16进制编码。

IP网络来说Ethertype字段承载的时上层协议的类型主要包括0x800为IP协议,0x806为ARP协议。

IEEE802.3以太网报文结构

         
上图为IEEE802.3SNAP帧结构,与EthernetII不通点是目的和源地址后面的字段代表的不是上层协议类型而是报文长度。并多了LLC子层。

1.3   IP协议

IP报文结构为IP协议头+载荷,其中对IP协议头部的分析,时分析IP报文的主要内容之一,关于IP报文详细信息请参考相关资料。这里给出了IP协议头部的一个结构。


版本:4——IPv4
首部长度:单位为4字节,最大60字节
TOS:IP优先级字段
总长度:单位字节,最大65535字节
标识:IP报文标识字段
标志:占3比特,只用到低位的两个比特
     MF(More Fragment)
     MF=1,后面还有分片的数据包
     MF=0,分片数据包的最后一个
     DF(Don't Fragment)
     DF=1,不允许分片
     DF=0,允许分片
段偏移:分片后的分组在原分组中的相对位置,总共13比特,单位为8字节
寿命:TTL(Time To Live)丢弃TTL=0的报文
协议:携带的是何种协议报文
     1   :ICMP
     6   :TCP
     17:UDP
     89:OSPF
头部检验和:对IP协议首部的校验和
源IP地址:IP报文的源地址
目的IP地址:IP报文的目的地址

上图为Sniffer对IP协议首部的解码分析结构,和IP首部各个字段相对应,并给出了各个字段值所表示含义的英文解释。如上图报文协议 (Protocol)字段的编码为0x11,通过Sniffer解码分析转换为十进制的17,代表UDP协议。其他字段的解码含义可以与此类似,只要对协 议理解的比较清楚对解码内容的理解将会变的很容易。


---------------------------------------------------

1.1   ARP协议
    以下为ARP报文结构

ARP分组具有如下的一些字段:
HTYPE(硬件类型)。这是一个16比特字段,用来定义运行ARP的网络的类型。每一个局域网基于其类型被指派给一个整数。例如,以太网是类型1。ARP可使用在任何网络上。
PTYPE(协议类型)。这是一个16比特字段,用来定义协议的类型。例如,对IPv4协议,这个字段的值是0800。ARP可用于任何高层协议。
HLEN(硬件长度)。这是一个8比特字段,用来定义以字节为单位的物理地址的长度。例如,对以太网这个值是6。
PLEN(协议长度)。这是一个8比特字段,用来定义以字节为单位的逻辑地址的长度。例如,对IPv4协议这个值是4。
OPER(操作)。这是一个16比特字段,用来定义分组的类型。已定义了两种类型:ARP请求(1),ARP回答(2)。
SHA(发送站硬件地址)。这是一个可变长度字段,用来定义发送站的物理地址的长度。例如,对以太网这个字段是6字节长。
SPA(发送站协议地址)。这是一个可变长度字段,用来定义发送站的逻辑(例如,IP)地址的长度。对于IP协议,这个字段是4字节长。
THA(目标硬件地址)。这是一个可变长度字段,用来定义目标的物理地址的长度。例如,对以太网这个字段是6字节长。对于ARP请求报文,这个字段是全0,因为发送站不知道目标的物理地址。
TPA(目标协议地址)。这是一个可变长度字段,用来定义目标的逻辑地址(例如,IP地址)的长度。对于IPv4协议,这个字段是4字节长。

上面为通过Sniffer解码的ARP请求和应答报文的结构。
1.2   PPPOE协议
PPPOE简介
简单来说我们可能把PPPOE报文分成两大块,一大块是PPPOE的数据报头,另一块则是PPPOE的净载荷(数据域),对于PPPOE报文数据域中的内容会随着会话过程的进行而不断改变。下图为PPPOE的报文的格式:

Ÿ          数据报文最开始的4位为版本域,协议中给出了明确的规定,这个域的内容填充0x01。
Ÿ          紧接在版本域后的4位是类型域,协议中同样规定,这个域的内容填充为0x01。
Ÿ          代码域占用1个字节,对于PPPOE 的不同阶段这个域内的内容也是不一样的。
Ÿ          会话ID点用2个字节,当访问集中器还未分配唯一的会话ID给用户主机的话,则该域内的内容必须填充为0x0000,一旦主机获取了会话ID后,那么在后续的所有报文中该域必须填充那个唯一的会话ID值。
Ÿ          长度域为2个字节,用来指示PPPOE数据报文中净载荷的长度。
Ÿ          数据域,有时也称之为净载荷域,在PPPOE的不同阶段该域内的数据内容会有很大的不同。在PPPOE的发现阶段时,该域内会填充一些Tag(标记);而在PPPOE的会话阶段,该域则携带的是PPP的报文。

捕获报文测试用例图
如图所示,Radius Server IP地址为172.16.20.76。PPPOE用户Radius报文交互过程分析如下。
上图为PPPOE从发现阶段到PPP LCP协商,认证IPCP协商阶段和PPPOE会话阶段交互过程。
PPPOE发现阶段,PADI报文,Sniffer解码结构如下所示。

PPPOE会话阶段,Sniffer解码结构如下所示。
  
1.3   Radius协议
Radius报文简介
标准Radius协议包结构

图9    Radius包格式
Code:包类型;1字节;指示RADIUS包的类型。
          1      Access- request                    认证请求 
          2      Access- accept                      认证响应
          3      Access- reject                       认证拒绝
          4      Accounting-request              计费请求
          5      Accounting-response            计费响应
        *11    Access-challenge                  认证挑战
Identifier: 包标识;1字节,取值范围为0 ~255;用于匹配请求包和响应包,同一组请求包和响应包的Identifier应相同。
Length: 包长度;2字节;整个包中所有域的长度。
Authenticator:16 字节长;用于验证RADIUS服务器传回来的请求以及密码隐藏算法上。
该验证字分为两种:
   1、请求验证字---Request Authenticator
         用在请求报文中,必须为全局唯一的随机值。
   2、响应验证字---Response Authenticator
          用在响应报文中,用于鉴别响应报文的合法性。
          响应验证字=MD5(Code+ID+Length+请求验证字+Attributes+Key)
Attributes:属性

图10    属性格式属性域是TLV结构编码。

-----------------------------------------------------------------



---------------------------------------

下图为PPPOE用户发为BAS的经过CHAP加密后的用户密码和BAS发给Radius Server中认证请求报文用户秘密属性域的比较。可以看出在Radius 认证过程中,BAS设备将Challenge属性和用户加密后的密码发给Radius进行验证。

通过比较可以清楚了解协议各字段含义相互关系,为问题处理提供有效的手段。
下面为PPPOE用户Radius认证的Sniffer捕获的报文。下图为用户端PPPOE,Radius Server和BAS交互的认证上线和下线的过程。


报文1:BAS请求Radius Server认证报文。
报文2:Radius Server回应BAS认证通过报文。
报文3:BAS计费请求报文。
报文4:Radius Server计费响应报文。
报文5:BAS计费结束报文。
报文6:Radius Server计费结束响应报文。
从中可以看出对于报文请求和响应是通过IP地址+Radius 协议域中ID号进行配对识别的。

上图显示了BAS发起的Radius认证请求(Code=1)报文的结构。Radius报文是承载在UPD协议之上的,这里我没不关注上层报文的结构。
下图为PPPOE CHAP认证过程的Radius认证请求报文和PPPOE中CHAP认证的Challenge报文。通过比较可以方便看出BAS发出的Challenge 值为"26fe8768341de68a72a1276771e1c1ca"与PPPOE中CHAP认证过程中BAS发给PPPOE用户的 Challenge值是一致的。

下图为PPPOE用户发为BAS的经过CHAP加密后的用户密码和BAS发给Radius Server中认证请求报文用户秘密属性域的比较。可以看出在Radius 认证过程中,BAS设备将Challenge属性和用户加密后的密码发给Radius进行验证。

通过比较可以清楚了解协议各字段含义相互关系,为问题处理提供有效的手段。
下面为PPPOE用户Radius认证的Sniffer捕获的报文。

2012年9月19日星期三

【转】sniffer使用及图解 sniffer pro 汉化注册版下载 简体中文破解版

sniffer使用及图解 sniffer pro 汉化注册版下载 简体中文破解版

注:

sniffer软件的安装还是比较简单的,我们只需要按照常规安装方法进行即可。需要说明的是:

      在选择sniffer pro的安装目录时,默认是安装在c:\program files\nai\snifferNT目录中,我们可以通过旁边的Browse按钮修改路径,不过为了更好的使用还是建议各位用默认路径进行安装。

      在注册用户时,随便输入注册信息即可,不过EMAIL一定要符合规范,需要带“@”。(如图1)

图1 点击放大

      注册诸多数据后我们就来到设置网络连接状况了,一般对于企业用户只要不是通过“代理服务器”上网的都可以选择第一项——direct connection to the internet。(如图2)

图2

      接下来才是真正的复制sniffer pro必需文件到本地硬盘,完成所有操作后出现setup complete提示,我们点finish按钮完成安装工作。

      由于我们在使用sniffer pro时需要将网卡的监听模式切换为混杂,所以不重新启动计算机是无法实现切换功能的,因此在安装的最后,软件会提示重新启动计算机,我们按照提示操作即可。(如图3)

重新启动计算机后我们可以通过sniffer pro来监测网络中的数据包。我们通过“开始->所有程序->sniffer pro->sniffer”来启动该程序。

      第一步:默认情况下sniffer pro会自动选择你的网卡进行监听,不过如果不能自动选择或者本地计算机有多个网卡的话,就需要我们手工指定网卡了。方法是通过软件的file菜单下的select settings来完成。

      第二步:在settings窗口中我们选择准备监听的那块网卡,记得要把右下角的“LOG ON”前打上对勾才能生效,最后点“确定”按钮即可。(如图4)

图4

      第三步:选择完毕后我们就进入了网卡监听模式,这种模式下将监视本机网卡流量和错误数据包的情况。首先我们能看到的是三个类似汽车仪表的图象,从左到右依次为“Utilization% 网络使用率”, “Packets/s数据包传输率”,“Error/s错误数据情况”。其中红色区域是警戒区域,如果发现有指针到了红色区域我们就该引起一定的重视了, 说明网络线路不好或者网络使用压力负荷太大。一般我们浏览网页的情况和我图11中显示的类似,使用率不高,传输情况也是9到30个数据包每秒,错误数基本 没有。(如图5)

图5

      第四步:在三个仪表盘下面是对网络流量,数据错误以及数据包大小情况的绘制图,我们可以通过点选右边一排参数来有选择的绘制相应的数据信息,可选网络使用 状况包括数据包传输率,网络使用率,错误率,丢弃率,传输字节速度,广播包数量,组播包数量等,其他两个图表可以设置的参数更多,随着时间的推移图象也会 自动绘制。(如图6)

图6 点击放大

      第五步:为了更好更详细的看出差别,笔者决定通过FTP来下载大量数据,由于是内网传输所以速度非常快,在这种情况下我们继续通过sniffer pro来查看本地网络流量情况,FTP下载速度接近4Mb/s。(如图7)

图7 点击放大

      第六步:网络传输速度提高后在sniffer pro中的显示也有了很大变化,utiliazation使用百分率一下到达了30%左右,由于我们100M网卡的理论最大传输速度为12.5Mb/s, 所以4Mb/s刚好接近这个值的30%,实际结果和理论符合;数据包传输速度也从原来的几十变成了3500到5200,当然令人满意的是错误数据包依然没 有出现,这说明网络负载并不大,网卡性能不错。(如图8)

图8 点击放大

      第七步:除了上面三个仪表能看出比较大的差别外下面的数据大小绘制图也能看出明显区别。各个数据的峰值跳动很大。

      第八步:如果在实际使用中使用的不是百兆而是千兆的话,默认设置的单位肯定不能满足需求,这时就需要我们点仪表上面的“set thresholds”按钮了,之后我们可以对所有参数的名称和最大显示上限进行设置,方便我们根据实际需求更贴切的显示信息。

      第九步:如果为了统计的话我们还可以点仪表下的“Detail”按钮来查看具体详细信息,在这里可以看到各项参数的总流量以及平均流量,可以帮助我们更好 的了解到网络的基本情况,包括数据丢失率与组播广播数量,这些数据的异常都是网络出现问题的先兆。(如图9)

图9 点击放大

      第十步:除了仪表按钮sniffer pro还为我们提供了很多显示面板,例如在host table界面,我们可以看到本机和网络中其他地址的数据交换情况,包括进数据量、出数据量以及基本速度等,当然所有显示信息都是根据MAC地址来判断 的,虽然不方便我们查看但是数据是有保障的,绝对不会出现被别人伪造地址而带来迷惑问题。(如图10)

图10 点击放大

      第十一步:在host table界面中点“this station”可以查看本机与网络其他地址的流量图,这个图是一个圆,通过连线决定本机和网络其他地址的传输情况,连线的粗细决定了数据流量的多少,这 种流量图可以让我们更加直观的了解本机网络的状况。(如图11)

图11 点击放大

      第十二步:我们也可以直接点“Matrix”按钮切换到流量图面板,这样看到的流量连接和传输情况会更加清晰。(如图12)

图12 点击放大

      总结:
      本文主要介绍了通过sniffer pro了解本机网络的使用情况,也许读者会说大部分网络管理工具也具有此功能,但是笔者要说的是,第一这种流量显示和图表绘制功能只有sniffer pro最为强大最为灵活;第二sniffer pro的真谛在于混杂模式下的监听,也就是说他可以监听到来自于其他计算机发往另外计算机的数据,当然很多混杂模式下的监听是以本文设置为基础的,只有了 解了对本机流量的监听设置才能够进行高级混杂模式监听。由于篇幅关系笔者将在下篇文章中为各位IT168的读者介绍如何让sniffer pro在混杂模式下监听和查看网络中的其他数据流量,从而实现更高级的排除网络故障的功能。

sniffer pro 4.70.530汉化注册版
sniffer pro,NAI公司出品的可能是目前最好的网络协议分析软件之一了,支持各种平台,性能优越,做为一名合格的网络管理员肯定需要有这么一套好的网络协议分析软件了,只是有点大请用下载工具下载。SN:SA154-2558Y-255T9-2LASH


摘自:http://hi.baidu.com/ws202001/item/3856c9fb35f57e18a62988a1

2012年9月7日星期五

转:Delphi中TFrame组件的使用

Delphi中TFrame组件的使用  

        从Delphi 5.0开始,Borland 引进了一个新的可视化的容器类TFrame。

        这个类,我们称之为TFrame框架组件,使程序开发人员能够可视化的设置一组组件,之后系统中对它进行重用。

TFrame 框架概观

        TFrame框架有两个主要的好处:

        第一、框架可大幅减少需要存储在工程中的资源量。

        第二、框架允许你可视化的创建能复制和扩展的对象。对可视化窗体继承(VFI), 你可以享受同样的好处。

        VFI允许你很简单的创建由继承得来的窗体。VFI的限制是你必须用“全部或全无”的方式来使用窗体。更具体的说,当你用VFI时,你总是创建一个新的窗 体。框架,相反的,在这一方面更类似面板(TPanel组件),这就是说一个窗体可包含两个或更多框架。每一个框架保持它与父 TFrame的关系,即对父类的改变将自动被实例继承。这一点是很重要的。虽然你可以用TPanel组件达到同样的效果,但它只局限于 基于代码的操作,即你必须写代码来手工定义TPanel的子孙le。相反的,框架被可视化的设计,就像窗体一样。

        TFrame框架也可认为与组件模板(含一个或更多组件并用Component | Create Component Template命令保存到组件 面板的一个组)相似。但是,相似之处仅限于它们都是被可视化设计的(不象传统的完全基于代码的组件设计)。实际上,框架与组件模板的差异是巨大的。正如我 们已学过的,框架是一定义类的实例,当定义类发生改变时框架也将发生变化。与之相比,组件模板是组件的集合。对组件模板的改变不影响以前从这一模板创建的 对象。

创建框架

        以下步骤演示如何建立一个框架:

1>  选择 File | New Application 建立一个新的工程。
2>  选择 File | New Frame 建立一个新的TFrame框架。在这一框架上,添加三个Label和三个DBEdit,还有一个 DBNavigator和一个DataSource。将Label的Caption分别设为ID,First Name和Last Name。将 DBEdit和DBNavigator的DataSource属性设为DataSource1。
3>  将框架的Name属性设为NameFrame。(相比其它对象,起一个有意义的名字对框架来说非常重要)最后,选择File | Save As 保存框 架。在这里,用文件名NAMEFRAM.PAS保存框架。   

这就是建立一个框架的所有步骤。

使用框架

        以下步骤演示如何使用框架:

1>  在由上面步骤建立的工程中选择Form1。
2>  加两个GroupBox到窗体上,其中一个在另一个之上。设置第一个的Caption为Customers,第二个的Caption为 Employees。
3>  现在添加框架。选择组件面板的Standard页,点击Frame组件并将其拖到名为Customers的GroupBox中。这时Delphi会显示一 个Select frame to insert对话框。
4>  在对话框中选择NameFrame。现在框架将在名为Customers的GroupBox中显示。重复这一步骤,这一次将框架放在名为 Employees的GroupBox中。你可能要调节框架的尺寸,这跟你最初是如何放置有关。
5>  将两个Table组件放到窗体中,将其DatabaseName属性都设为IBLocal。将Table1的TableName属性设为 CUSTOMER,将Table2的TableName属性设为EMPLOYEE。将两个Table的Active属性都设为True,使它们有效。 
6>  下面的步骤将把事情变得有趣。选择名为Customers的GroupBox中的DataSource,将其DataSet属性设为Table1。一般的 你不能直接选择组件中的对象,但是框架是个例外。你可以选择框架中的任何对象,操作它们的属性。然后,选择名名为Customers的GroupBox中 DataSource,其DataSet属性设为Table2。
7>  最后,设置好所有的DBEdits。将名为Customers的 GroupBox中的三个DBEdits的DataField属性分别设为CUST_NO,CONTACT_FIRST和CONTACT_LAST。对 Employees中的,设置DataField属性为EMP_NO,FIRST_NAME和LAST_NAME。
8>  保存工程并运行。

框架和继承

        到此为止,使用框架似乎没有什么好处。但是,当你要在一些地方使用同一个框架, 然后又要改变所有这些实例时,框架的威力就表现得很明显了。例如,假设你要使所有的NameFrame框架变为只读的,你只需要将初始 的框架修改,所有的修改就会被框架实例立刻继承。

你依照如下步骤就可以验证这一点:

1>  在上面建立的工程中,按[Shift][F12]并在窗体列表中选择NameFrame。
2>  将DataSource的AutoEdit属性设为False 。
3>  然后,选择DBNavigator,展开它的VisibleButtons属性,并设置nbInsert,nbDelete,nbEdit,nbPost 和nbCancel标志为False。 
4>  现在看一下你的主窗体,注意两个NameFrame的后代都继承了你对框架做的修改。  

重载包含组件的属性

        框架的优点之一(与VFI一样)是你可以改变框架中对象的属性和事件处理函数。这些修改重载了继承的值。说得具体些,随后对初始框架的重载属性的修改将不 改变后代的重载属性的值。以下步骤可以验证这一行为:

1>  在名为Customers的GroupBox中,选择标题为"ID"的label,在Object Inspector将其Caption属性改为 “Customer No:”。现在选择名为Customers的GroupBox中的标题为"ID"的Label,其Caption属性改为 “Employee ID:”。 
2>  按[Shift][F12]并选择NameFrame。将标题为"ID"的Label的Caption属性改为Identifier。 
3>  回到主窗体,注意Label的Caption属性没有变为Identifier。它们仍保持它们的重载值。
4>  这一效果是由保存在DFM文件中的信息实现的。

        注意所有其属性改变过的在框架中的对象,都出现在DFM文件中的内置部分。但是,这一部分仅列出那些改变的值,所有其它属性值要么按初始框架的值设置(它 们已经存储在框架的DFM文件中),要么按每一组件的默认类定义值。

包含组件的事件处理函数

        框架中的对象也可以有事件处理函数。虽然事件只是一个方法指针型属性,但它们的默认行为被重载后的处理与其它属性不同。

        让我们先考虑一下框架对象的事件处理函数是如何定义的。假设一个框架有两个按钮,一个标为Help,另一个标为Done(显然按钮的标题可以在框架后代中 重载)。这两个按钮都有onClick的事件处理函数:

procedure TTwoButtonFrame.Button1Click(Sender: TObject); 
begin 
if  (TComponent(Sender).Tag = 0)   or   (Application.HelpFile = '''''''')   then 
MessageBox(Application.Handle,''''Help not available'''', ''''Help'''',MB_OK) 
else 
Application.HelpContext(TComponent(Sender).Tag); 
end; 

---------------------------------------------------------------------------------------------------------

procedure TTwoButtonFrame.Button2Click(Sender: TObject); 
var 
AParent: TComponent; 
begin 
AParent := TComponent(Sender).GetParentComponent; 
while not (AParent is TCustomForm) do 
AParent := AParent.GetParentComponent; 
TCustomForm(AParent).Close; 
end; 
 
就象窗体中的对象的事件处理函数是窗体类的公开方法,框架中的对象的事件处理函数也是框架类的公开方法。(代码段实际上并没有说框架的这些方法是公开的, 而是它们在框架声明的默认可见部分被声明,其可见性默认是公开的。)

如果你查看与Done按钮相联系的Button2Click事件处理函数的代码,你会发现与框架相联系的事件处理函数引进了一个很有趣的技术。具体的说, 由于Self是框架而不是包含框架的窗体,因此不能在函数中调用Close方法来关闭窗体。当你在代码中使用没有限定的方法时,编译器将认为你要使用 Self的方法。因为TFrame对象没有Close方法,编译器将产生一个错误。

        因为在本例中框架被设计为内置在一个窗体中,事件处理函数用GetParentComponent方法向上找TCustomForm实例(它要么是 TForm的后代,要么是基于TCustomForm的定制窗体),如果找到了,就调用窗体的Close方法。

重载包含对象的事件处理函数

        如果你对VFI中的事件重载比较熟悉,你会回忆起Delphi在后代窗体的重载的事件处理函数中内置继承的事件处理函数。你可以改变生成的代码,在调用继 承函数之前或之后添加附加的代码,或是有条件的调用继承的事件处理函数,或是干脆省略对继承的事件处理函数的调用。

        框架的后代当使用父框架中对象的事件处理函数时,不使用继承的函数,而直接调用祖先框架的方法。例如,你把TwoButtonFrame放到一个窗体中然 后双击,Delphi将产生如下的代码:

procedure TForm1.TwoButtonFrame1Button2Click( Sender: Object); 
begin 
TwoButtonFrame1.Button2Click(Sender); 
end; 
   
在产生的代码中,TwoButtonFrame1是TTwoButtonFrame(最初的框架类)的后代。Button2Click,如你在先前的代码 段中所看到的,是Done按钮的事件处理函数。结果是,这一代码调用最初的事件处理函数,将框架实例中传给按钮的Sender传给它。

这意味着事件处理函数引进了另一个有趣的特性。具体的说,在这种情况下,Sender一般不是Self对象的成员。实际上,Sender一般是窗体对象的 成员,而Self是框架对象。

        在这里,原来的行为被“注释掉了”,这样新行为就完全替代了原来对Done按钮 定义的行为。

procedure TForm1.TwoButtonFrame1Button2Click( Sender: TObject); 
begin 
with TForm2.Create(Self) do begin 
ShowModal; 
Release; 
end; 
     // 下面是原来自动生成的代码
//  TwoButtonFrame1.Button2Click(Sender);
 
end; 
 

框架节省资源

        在声明窗体中有两个框架。我们已经讨论了TwoButtonFrame框架。第二个框架显示公司标志,名为LogoFrame。

LogoFrame在FramDemo的多个窗体中出现。一种替代使用框架的做法是在每个窗体中设置一个Image对象来显示公司标志。但是,用框架可以 显著减少需要编译到EXE文件中的资源,生成一个较小的可执行文件。

        你可以在如下的DFM文件部分找到原因:

inline LogoFrame1: TLogoFrame 
Left = 6 
Top = 6 
Width = 211 
Height = 182 
inherited Image1: TImage 
Width = 211 
Height = 182 
end 
end 
   
如果把一个TImage放在窗体中,窗体的DFM文件将必须包含整个公司标志的二进制数表示。而且,每一个含有图象的窗体都重复保存这一资源。但用框架 时,资源只定义一次。

object LogoFrame: TLogoFrame 
Left = 0 
Top = 0 
Width = 239 
Height = 178 
TabOrder = 0 
object Image1: TImage 
Left = 0 
Top = 0 
Width = 239 
Height = 178 
Align = alClient 
Picture.Data = { 
07544269746D6170D6540000424DD654000000000000760000... 
   

简化框架的使用

        在一单个、小的工程中,使用组件面板Standard页上的框架组件是相当简单的。但是对更大的、或是要在多个程序中使用同一个框架的情况下,你需要使操 作更简单。幸运的是,Delphi允许你将单个框架放到组件面板,使这些框架不需要另外的步骤而简单的重复使用。框架也可放到对象库 (Object Repository)中,使它可以简单的拷贝。这两个技术都将在下面叙述。


把框架添加到组件面板

        把一个框架添加到组件模板,你可以使放置这一框架变得与其它组件一样简单。与之相比,用组件模板的Standard页中的框架组件需要四步,而且限制你仅 能放置在你的工程中已经定义的框架。将一特定框架添加到组件模板中,需要以下四步:

1>  保存框架。如果你要在多个程序中使用一个框架,我非常建议你将框架保存到升级Delphi时不会被删除的目录中。例如,建立一个名为 c:\Program Files\Borland\DelphiFrames的目录来保存你的框架。
2>  选择框架并在上面点鼠标右键,选择Add to Palette,Delphi会显示Component Template Information对话 框。
3>  在Component name栏定义框架组件的名称,在Palette page栏填写你想让框架在组件模板内出现的页。如果你已为框架建立了一个 24 x 24象素、16色的图标,点击Change按钮来选择这个BMP文件。当你完成后,点击OK按钮。   


从组件模板使用框架

        要使用一个已添加到组件面板的框架,在组件面板中选择你保存框架的页,选择框架图标并在你要框架后代出现的窗体上拖出该框架。这个过程仅需这两步。

将框架添加到对象库

        把框架添加到对象库,你可以使拷贝该框架到一个新工程的过程变得简单。尤其重要的是对象库提供放置继承的框架到新的工程的能力,它使框架和它的祖先之间的 关系得以保持。要将框架添加到对象库,需要以下步骤:

1>  保存框架。除了保存框架到Delphi的OBJREPOS目录或是共享目录,你还可以使用你保存添加到组件模板中的框架的目录。如果你使用共享库,将框架 保存到共享目录特别好,它允许多个开发者共享框架。
2>  在框架上面点鼠标右键,选择Add To Repository,Delphi会显示Add To Repository对话框。
3>  就像你添加其它模板到Object Repository一样填写Add To Repository对话框。完成后点击OK按钮。


从对象库中使用框架

按照下面步骤来从对象库中使用框架: 

1>  选择 File | New. 
2>  选择你在Object Repository保存框架模板的页。 
3>  选择代表框架的图标,然后选择Inherit单选按钮。
4>  点击OK按钮,添加框架的继承版本到你的工程   

        如果你选择Copy单选按钮而不是Inherit单选按钮,添加进的框架将是原框架的一个拷贝。当你需要创建一个新的框架,但又不想保持它与原框架的关系 时是很有用的。


总结

        把需要重复使用的框架添加到组件模板与添加到对象库有不同的效果吗?答案是:"Yes!"。在 大多数情况,你要把你频繁使用的框架添加到组件面板中。这样当你放置框架时,你得到的是框架的一个实例。你然后可以容易的修改这一实例 的属性和事件处理函数,就象本文先前介绍的一样。与之相比,从对象库放置一个框架会产生一个新的类,而不是一个实例。这 个类要么是原来的拷贝要么是原来的继承,取决于你在Object Repository对话框中选择了哪一个单选按钮。如果你要在工程中 使用框架,添加一个框架实例比定义一个框架新类有意义的多。如果是这一目的,将框架保存到组件面板是最好的方法。

有一种情况你要使用对象库:当你需要专门创建一框架层次,并且每一个框架后代引进了附加的对象、方法或事件处理函数。这时,对象库提 供的继承性使创建后代变得简单。但是,当你定义好了需要经常使用框架的后代,我建议你将它们添加到组件面板以简化它们的使用。

(转自:http://www.itqun.net/content-detail/138582_2.html

2012年9月2日星期日

转:Delphi托盘区程序

Delphi托盘区程序

delphi托盘程序

Delphi的托盘编程   。现在很多程序都用这个,比如傲游,迅雷等,主要代码如下:

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, ShellAPI, AppEvnts, StdCtrls, Menus;

const WM_NID = WM_User + 1000; //声明一个常量

private

    { Private declarations } // 定义两个函数

    procedure SysCommand(var SysMsg: TMessage); message WM_SYSCOMMAND;

    procedure WMNID(var msg:TMessage); message WM_NID;

public

end;

var

Form1: TForm1;

NotifyIcon: TNotifyIconData; // 全局变量

implementation

{$R *.dfm}

procedure TForm1.WMNID(var msg:TMessage);

var

mousepos: TPoint;

begin

GetCursorPos(mousepos); //获取鼠标位置

case msg.LParam of

    WM_LBUTTONUP: // 在托盘区点击左键后

    begin

      Form1.Visible := not Form1.Visible; // 显示主窗体与否

      Shell_NotifyIcon(NIM_DELETE, @NotifyIcon); // 显示主窗体后删除托盘区的图标

      SetWindowPos(Application.Handle, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW); // 在任务栏显示程序

    end;

   

    WM_RBUTTONUP: PopupMenu1.Popup(mousepos.X, mousepos.Y); // 弹出菜单

end;

end;

procedure TForm1.FormDestroy(Sender: TObject);

begin

Shell_NotifyIcon(NIM_DELETE, @NotifyIcon); // 删除托盘图标

end;

procedure TForm1.SysCommand(var SysMsg: TMessage);

begin

case SysMsg.WParam of

    SC_MINIMIZE: // 当最小化时

    begin

      SetWindowPos(Application.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_HIDEWINDOW);

      Hide; // 在任务栏隐藏程序

      // 在托盘区显示图标

      with NotifyIcon do

      begin

        cbSize := SizeOf(TNotifyIconData);

        Wnd := Handle;

        uID := 1;

        uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;

        uCallBackMessage := WM_NID;

        hIcon := Application.Icon.Handle;

        szTip := '托盘程序';

      end;

      Shell_NotifyIcon(NIM_ADD, @NotifyIcon); // 在托盘区显示图标

    end;

else

    inherited;

end;

end;

{以下三个函数为托盘右键菜单,可自行添加功能}

procedure TForm1.N1Click(Sender: TObject);

begin

ShowMessage('Delphi托盘小程序!');

end;

procedure TForm1.N2Click(Sender: TObject);

begin

Form1.Visible := true; // 显示窗体

SetWindowPos(Application.Handle, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW);

Shell_NotifyIcon(NIM_DELETE, @NotifyIcon); // 删除托盘图标

end;

procedure TForm1.N3Click(Sender: TObject);

begin

Shell_NotifyIcon(NIM_DELETE, @NotifyIcon);

Application.Terminate;

end;

end.

摘自:http://www.cnblogs.com/goalone1985/articles/2125090.html