Xiaobo Sun

          Eclipse-Unix http://umlfact.berlios.de/~s_xsun/

          2008年5月13日

          Java annotation

          版權(quán)聲明:本文可以自由轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明
          作者:cleverpig(作者的Blog:http://blog.matrix.org.cn/page/cleverpig)
          原文:http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html
          關(guān)鍵字:Java,annotation,標(biāo)注


          摘要:
          本文針對(duì)java初學(xué)者或者annotation初次使用者全面地說(shuō)明了annotation的使用方法、定義方式、分類(lèi)。初學(xué)者可以通過(guò)以上的說(shuō)明制作 簡(jiǎn)單的annotation程序,但是對(duì)于一些高級(jí)的annotation應(yīng)用(例如使用自定義annotation生成javabean映射xml文 件)還需要進(jìn)一步的研究和探討。涉及到深入annotation的內(nèi)容,作者將在后文《Java Annotation高級(jí)應(yīng)用》中談到。

          同時(shí),annotation運(yùn)行存在兩種方式:運(yùn)行時(shí)、編譯時(shí)。上文中討論的都是在運(yùn)行時(shí)的annotation應(yīng)用,但在編譯時(shí)的annotation應(yīng)用還沒(méi)有涉及,

          一、為什么使用Annotation:

          在JAVA應(yīng)用中,我們常遇到一些需要使用模版代碼。例如,為了編寫(xiě)一個(gè)JAX-RPC web service,我們必須提供一對(duì)接口和實(shí)現(xiàn)作為模版代碼。如果使用annotation對(duì)遠(yuǎn)程訪問(wèn)的方法代碼進(jìn)行修飾的話,這個(gè)模版就能夠使用工具自動(dòng)生成。
          另外,一些API需要使用與程序代碼同時(shí)維護(hù)的附屬文件。例如,JavaBeans需要一個(gè)BeanInfo Class與一個(gè)Bean同時(shí)使用/維護(hù),而EJB則同樣需要一個(gè)部署描述符。此時(shí)在程序中使用annotation來(lái)維護(hù)這些附屬文件的信息將十分便利 而且減少了錯(cuò)誤。

          二、Annotation工作方式:

          在5.0版之前的Java平臺(tái)已經(jīng)具有了一些ad hoc annotation機(jī)制。比如,使用transient修飾符來(lái)標(biāo)識(shí)一個(gè)成員變量在序列化子系統(tǒng)中應(yīng)被忽略。而@deprecated這個(gè) javadoc tag也是一個(gè)ad hoc annotation用來(lái)說(shuō)明一個(gè)方法已過(guò)時(shí)。從Java5.0版發(fā)布以來(lái),5.0平臺(tái)提供了一個(gè)正式的annotation功能:允許開(kāi)發(fā)者定義、使用 自己的annoatation類(lèi)型。此功能由一個(gè)定義annotation類(lèi)型的語(yǔ)法和一個(gè)描述annotation聲明的語(yǔ)法,讀取annotaion 的API,一個(gè)使用annotation修飾的class文件,一個(gè)annotation處理工具(apt)組成。
          annotation并不直接影響代碼語(yǔ)義,但是它能夠工作的方式被看作類(lèi)似程序的工具或者類(lèi)庫(kù),它會(huì)反過(guò)來(lái)對(duì)正在運(yùn)行的程序語(yǔ)義有所影響。annotation可以從源文件、class文件或者以在運(yùn)行時(shí)反射的多種方式被讀取。
          當(dāng)然annotation在某種程度上使javadoc tag更加完整。一般情況下,如果這個(gè)標(biāo)記對(duì)java文檔產(chǎn)生影響或者用于生成java文檔的話,它應(yīng)該作為一個(gè)javadoc tag;否則將作為一個(gè)annotation。

          三、Annotation使用方法:

          1。類(lèi)型聲明方式:
          通常,應(yīng)用程序并不是必須定義annotation類(lèi)型,但是定義annotation類(lèi)型并非難事。Annotation類(lèi)型聲明于一般的接口聲明極為類(lèi)似,區(qū)別只在于它在interface關(guān)鍵字前面使用“@”符號(hào)。
          annotation類(lèi)型的每個(gè)方法聲明定義了一個(gè)annotation類(lèi)型成員,但方法聲明不必有參數(shù)或者異常聲明;方法返回值的類(lèi)型被限制在以下的范 圍:primitives、String、Class、enums、annotation和前面類(lèi)型的數(shù)組;方法可以有默認(rèn)值。

          下面是一個(gè)簡(jiǎn)單的annotation類(lèi)型聲明:
          清單1:


               /**

                * Describes the Request-For-Enhancement(RFE) that led

                * to the presence of the annotated API element.

                */

               public @interface RequestForEnhancement {

                   int     id();

                   String synopsis();

                   String engineer() default "[unassigned]";

                   String date();     default "[unimplemented]";

               }


          代碼中只定義了一個(gè)annotation類(lèi)型RequestForEnhancement。

          2。修飾方法的annotation聲明方式:
          annotation是一種修飾符,能夠如其它修飾符(如public、static、final)一般使用。習(xí)慣用法是annotaions用在其它的 修飾符前面。annotations由“@+annotation類(lèi)型+帶有括號(hào)的成員-值列表”組成。這些成員的值必須是編譯時(shí)常量(即在運(yùn)行時(shí)不 變)。

          A:下面是一個(gè)使用了RequestForEnhancement annotation的方法聲明:
          清單2:


               @RequestForEnhancement(

                   id        = 2868724,

                   synopsis = "Enable time-travel",

                   engineer = "Mr. Peabody",

                   date      = "4/1/3007"

               )

               public static void travelThroughTime(Date destination) { ... }



          B:當(dāng)聲明一個(gè)沒(méi)有成員的annotation類(lèi)型聲明時(shí),可使用以下方式:
          清單3:


               /**

                * Indicates that the specification of the annotated API element

                * is preliminary and subject to change.

                */

               public @interface Preliminary { }



          作為上面沒(méi)有成員的annotation類(lèi)型聲明的簡(jiǎn)寫(xiě)方式:
          清單4:


               @Preliminary public class TimeTravel { ... }



          C:如果在annotations中只有唯一一個(gè)成員,則該成員應(yīng)命名為value:
          清單5:


               /**

                * Associates a copyright notice with the annotated API element.

                */

               public @interface Copyright {

                   String value();

               }



          更為方便的是對(duì)于具有唯一成員且成員名為value的annotation(如上文),在其使用時(shí)可以忽略掉成員名和賦值號(hào)(=):
          清單6:


               @Copyright("2002 Yoyodyne Propulsion Systems")

               public class OscillationOverthruster { ... }



          3。一個(gè)使用實(shí)例:
          結(jié)合上面所講的,我們?cè)谶@里建立一個(gè)簡(jiǎn)單的基于annotation測(cè)試框架。首先我們需要一個(gè)annotation類(lèi)型來(lái)表示某個(gè)方法是一個(gè)應(yīng)該被測(cè)試工具運(yùn)行的測(cè)試方法。
          清單7:


               import java.lang.annotation.*;



               /**

                * Indicates that the annotated method is a test method.

                * This annotation should be used only on parameterless static methods.

                */

               @Retention(RetentionPolicy.RUNTIME)

               @Target(ElementType.METHOD)

               public @interface Test { }



          值得注意的是annotaion類(lèi)型聲明是可以標(biāo)注自己的,這樣的annotation被稱(chēng)為“meta-annotations”。

          在上面的代碼中,@Retention(RetentionPolicy.RUNTIME)這個(gè)meta-annotation表示了此類(lèi)型的 annotation將被虛擬機(jī)保留使其能夠在運(yùn)行時(shí)通過(guò)反射被讀取。而@Target(ElementType.METHOD)表示此類(lèi)型的 annotation只能用于修飾方法聲明。

          下面是一個(gè)簡(jiǎn)單的程序,其中部分方法被上面的annotation所標(biāo)注:
          清單8:


               public class Foo {

                   @Test public static void m1() { }

                   public static void m2() { }

                   @Test public static void m3() {

                       throw new RuntimeException("Boom");

                   }

                   public static void m4() { }

                   @Test public static void m5() { }

                   public static void m6() { }

                   @Test public static void m7() {

                       throw new RuntimeException("Crash");

                   }

                   public static void m8() { }

               }



          Here is the testing tool:



               import java.lang.reflect.*;



               public class RunTests {

                  public static void main(String[] args) throws Exception {

                     int passed = 0, failed = 0;

                     for (Method m : Class.forName(args[0]).getMethods()) {

                        if (m.isAnnotationPresent(Test.class)) {

                           try {

                              m.invoke(null);

                              passed++;

                           } catch (Throwable ex) {

                              System.out.printf("Test %s failed: %s %n", m, ex.getCause());

                              failed++;

                           }

                        }

                     }

                     System.out.printf("Passed: %d, Failed %d%n", passed, failed);

                  }

               }



          這個(gè)程序從命令行參數(shù)中取出類(lèi)名,并且遍歷此類(lèi)的所有方法,嘗試調(diào)用其中被上面的測(cè)試annotation類(lèi)型標(biāo)注過(guò)的方法。在此過(guò)程中為了找出哪些方法 被annotation類(lèi)型標(biāo)注過(guò),需要使用反射的方式執(zhí)行此查詢。如果在調(diào)用方法時(shí)拋出異常,此方法被認(rèn)為已經(jīng)失敗,并打印一個(gè)失敗報(bào)告。最后,打印運(yùn) 行通過(guò)/失敗的方法數(shù)量。
          下面文字表示了如何運(yùn)行這個(gè)基于annotation的測(cè)試工具:

          清單9:


               $ java RunTests Foo

               Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom

               Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash

               Passed: 2, Failed 2



          四、Annotation分類(lèi):

          根據(jù)annotation的使用方法和用途主要分為以下幾類(lèi):

          1。內(nèi)建Annotation——Java5.0版在java語(yǔ)法中經(jīng)常用到的內(nèi)建Annotation:
          @Deprecated用于修飾已經(jīng)過(guò)時(shí)的方法;
          @Override用于修飾此方法覆蓋了父類(lèi)的方法(而非重載);
          @SuppressWarnings用于通知java編譯器禁止特定的編譯警告。

          下面代碼展示了內(nèi)建Annotation類(lèi)型的用法:
          清單10:


          package com.bjinfotech.practice.annotation;



          /**

          * 演示如何使用java5內(nèi)建的annotation

          * 參考資料:

          * http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html

          * http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html

          * http://mindprod.com/jgloss/annotations.html

          * @author cleverpig

          *

          */

          import java.util.List;



          public class UsingBuiltInAnnotation {

                   //食物類(lèi)

                   class Food{}

                   //干草類(lèi)

                   class Hay extends Food{}

                   //動(dòng)物類(lèi)

                   class Animal{

                           Food getFood(){

                                   return null;

                           }

                           //使用Annotation聲明Deprecated方法

                           @Deprecated

                           void deprecatedMethod(){

                           }

                   }

                   //馬類(lèi)-繼承動(dòng)物類(lèi)

                   class Horse extends Animal{

                           //使用Annotation聲明覆蓋方法

                           @Override

                           Hay getFood(){

                                   return new Hay();

                           }

                           //使用Annotation聲明禁止警告

                           @SuppressWarnings({"deprecation","unchecked"})

                           void callDeprecatedMethod(List horseGroup){

                                   Animal an=new Animal();

                                   an.deprecatedMethod();

                                   horseGroup.add(an);

                           }

                   }

          }



          2。開(kāi)發(fā)者自定義Annotation:由開(kāi)發(fā)者自定義Annotation類(lèi)型。
          下面是一個(gè)使用annotation進(jìn)行方法測(cè)試的sample:

          AnnotationDefineForTestFunction類(lèi)型定義如下:
          清單11:


          package com.bjinfotech.practice.annotation;



          import java.lang.annotation.*;

          /**

          * 定義annotation

          * @author cleverpig

          *

          */

          //加載在VM中,在運(yùn)行時(shí)進(jìn)行映射

          @Retention(RetentionPolicy.RUNTIME)

          //限定此annotation只能標(biāo)示方法

          @Target(ElementType.METHOD)

          public @interface AnnotationDefineForTestFunction{}



          測(cè)試annotation的代碼如下:

          清單12:


          package com.bjinfotech.practice.annotation;



          import java.lang.reflect.*;



          /**

          * 一個(gè)實(shí)例程序應(yīng)用前面定義的Annotation:AnnotationDefineForTestFunction

          * @author cleverpig

          *

          */

          public class UsingAnnotation {

                   @AnnotationDefineForTestFunction public static void method01(){}

                  

                   public static void method02(){}

                  

                   @AnnotationDefineForTestFunction public static void method03(){

                           throw new RuntimeException("method03");

                   }

                  

                   public static void method04(){

                           throw new RuntimeException("method04");

                   }

                  

                   public static void main(String[] argv) throws Exception{

                           int passed = 0, failed = 0;

                           //被檢測(cè)的類(lèi)名

                           String className="com.bjinfotech.practice.annotation.UsingAnnotation";

                           //逐個(gè)檢查此類(lèi)的方法,當(dāng)其方法使用annotation聲明時(shí)調(diào)用此方法

                       for (Method m : Class.forName(className).getMethods()) {

                          if (m.isAnnotationPresent(AnnotationDefineForTestFunction.class)) {

                             try {

                                m.invoke(null);

                                passed++;

                             } catch (Throwable ex) {

                                System.out.printf("測(cè)試 %s 失敗: %s %n", m, ex.getCause());

                                failed++;

                             }

                          }

                       }

                       System.out.printf("測(cè)試結(jié)果: 通過(guò): %d, 失敗: %d%n", passed, failed);

                   }

          }



          3。使用第三方開(kāi)發(fā)的Annotation類(lèi)型
          這也是開(kāi)發(fā)人員所常常用到的一種方式。比如我們?cè)谑褂肏ibernate3.0時(shí)就可以利用Annotation生成數(shù)據(jù)表映射配置文件,而不必使用Xdoclet。

          五、總結(jié):

          1。前面的文字說(shuō)明了annotation的使用方法、定義方式、分類(lèi)。初學(xué)者可以通過(guò)以上的說(shuō)明制作簡(jiǎn)單的annotation程序,但是對(duì)于一些高級(jí) 的annotation應(yīng)用(例如使用自定義annotation生成javabean映射xml文件)還需要進(jìn)一步的研究和探討。

          2。同時(shí),annotation運(yùn)行存在兩種方式:運(yùn)行時(shí)、編譯時(shí)。上文中討論的都是在運(yùn)行時(shí)的annotation應(yīng)用,但在編譯時(shí)的 annotation應(yīng)用還沒(méi)有涉及,因?yàn)榫幾g時(shí)的annotation要使用annotation processing tool。

          涉及以上2方面的深入內(nèi)容,作者將在后文《Java Annotation高級(jí)應(yīng)用》中談到。

          posted @ 2009-05-14 13:04 Xiaobo Sun 閱讀(218) | 評(píng)論 (0)編輯 收藏

          google tips

          =========================================================
          GOOGLE不支持通配符,如“*”、“?”等,只能做精確查詢,關(guān)鍵字后面的“*”或者“?”會(huì)被忽略掉。

          GOOGLE對(duì)英文字符大小寫(xiě)不敏感,“GOD”和“god”搜索的結(jié)果是一樣的。

          GOOGLE的關(guān)鍵字可以是詞組(中間沒(méi)有空格),也可以是句子(中間有空格),但是,用句子做關(guān)鍵字,必須加英文引號(hào)。

          示例:搜索包含“long, long ago”字串的頁(yè)面。
          搜索:“"long, long ago"”
          結(jié)果:已向英特網(wǎng)搜索"long, long ago". 共約有28,300項(xiàng)查詢結(jié)果,這是第1-10項(xiàng)。搜索用時(shí)0.28秒。

          注意:和搜索英文關(guān)鍵字串不同的是,GOOGLE對(duì)中文字串的處理并不十分完善。比如,搜索“"啊,我的太陽(yáng)"”,我們希望結(jié)果中含有這個(gè)句子,事實(shí)并非 如此。查詢的很多結(jié)果,“啊”、“我的”、“太陽(yáng)”等詞語(yǔ)是完全分開(kāi)的,但又不是“啊 我的 太陽(yáng)”這樣的與查詢。顯然,GOOGLE對(duì)中文的支持尚有欠缺之處。

          GOOGLE對(duì)一些網(wǎng)路上出現(xiàn)頻率極高的詞(主要是英文單詞),如“i”、“com”,以及一些符號(hào)如“*”、“.”等,作忽略處理,如果用戶必須要求關(guān)鍵字中包含這些常用詞,就要用強(qiáng)制語(yǔ)法“+”。

          示例:搜索包含“Who am I ?”的網(wǎng)頁(yè)。如果用“"who am i ?"”,“Who”、“I”、“?”會(huì)被省略掉,搜索將只用“am”作關(guān)鍵字,所以應(yīng)該用強(qiáng)制搜索。
          搜索:“"+who +am +i"”
          結(jié)果:已向英特網(wǎng)搜索"+who +am +i". 共約有362,000項(xiàng)查詢結(jié)果,這是第1-10項(xiàng)。搜索用時(shí)0.30秒。

          注意:英文符號(hào)(如問(wèn)號(hào),句號(hào),逗號(hào)等)無(wú)法成為搜索關(guān)鍵字,加強(qiáng)制也不行。

          ==============================================================
          inurl語(yǔ)法返回的網(wǎng)頁(yè)鏈接中包含第一個(gè)關(guān)鍵字,后面的關(guān)鍵字則出現(xiàn)在鏈接中或者網(wǎng)頁(yè)文檔中。有很多網(wǎng)站把某一類(lèi)具有相同屬性的資源名稱(chēng)顯示在目錄名稱(chēng) 或者網(wǎng)頁(yè)名稱(chēng)中,比如“MP3”、“GALLARY”等,于是,就可以用INURL語(yǔ)法找到這些相關(guān)資源鏈接,然后,用第二個(gè)關(guān)鍵詞確定是否有某項(xiàng)具體資 料。INURL語(yǔ)法和基本搜索語(yǔ)法的最大區(qū)別在于,前者通常能提供非常精確的專(zhuān)題資料。

          示例:查找MIDI曲“滄海一聲笑”。
          搜索:“inurl:midi 滄海一聲笑”
          結(jié)果:已搜索有關(guān)inurl:midi 滄海一聲笑的中文(簡(jiǎn)體)網(wǎng)頁(yè)。共約有14項(xiàng)查詢結(jié)果,這是第1-10項(xiàng)。搜索用時(shí)0.01秒。

          示例:查找微軟網(wǎng)站上關(guān)于windows2000的安全課題資料。
          搜索:“inurl:security windows2000 site:microsoft.com”
          結(jié)果:已在microsoft.com內(nèi)搜索有關(guān) inurl:security windows2000的網(wǎng)頁(yè)。共約有198項(xiàng)查詢結(jié)果,這是第1-10項(xiàng)。搜索用時(shí)0.37秒。

          注意:“inurl:”后面不能有空格,GOOGLE也不對(duì)URL符號(hào)如“/”進(jìn)行搜索。GOOGLE對(duì)“cgi-bin/phf”中的“/”當(dāng)成空格處理。

          posted @ 2009-05-14 12:41 Xiaobo Sun 閱讀(217) | 評(píng)論 (0)編輯 收藏

          MySQL

          1。啟動(dòng):mysqld --console
          2。調(diào)試:mysql -u root

          posted @ 2009-05-06 17:16 Xiaobo Sun 閱讀(202) | 評(píng)論 (0)編輯 收藏

          void* (like Object in Java)

          void   *從本質(zhì)上講是一種指針的類(lèi)型,就像   (char   *)、(int   *)類(lèi)型一樣.但是其又具有  
            特殊性,它可以存放其他任何類(lèi)型的指針類(lèi)型:例如:  
                                                  char   *array="I   am   the   pointer   of   string";  
                                                  void   *   temp;                   //temp可以存放其他任何類(lèi)型的指針(地址)  
                                                  temp=array;                       //   temp   的指針類(lèi)型  
                                                  cout<<array<<endl;  
                                                  cout<<temp<<endl;  
                                                  cout<<(char   *)temp<<endl;  
            運(yùn)行結(jié)果:  
                                                I   am   the   pointer   of   string  
                                                0x0042510C   (這個(gè)值就是array指針變量所存儲(chǔ)的值)  
                                                I   am   the   pointer   of   string  
             
             
             
            2.但是不能將void*類(lèi)型的值賦給其他既定的類(lèi)型,除非經(jīng)過(guò)顯示轉(zhuǎn)換:   例如:  
                                                                              int   a=20;  
                                                                              int   *   pr=&a;  
                                                                                void   *p;  
                                                                                pr=p               //error,不能將空的類(lèi)型賦給int   *  
           
                                                                                pr=(int   *)p;     //ok,經(jīng)過(guò)轉(zhuǎn)換 

          posted @ 2009-02-05 14:07 Xiaobo Sun 閱讀(280) | 評(píng)論 (0)編輯 收藏

          Servlet Lifecycle

          begin with first request : web.xml - init
          end when container is hsut down: web.xml - destroy

          By default setting: each Servlet has a Threadpool to support multithreads.

          posted @ 2009-01-09 23:41 Xiaobo Sun 閱讀(253) | 評(píng)論 (0)編輯 收藏

          Java Class Loader

           Class loader priority is bootstrap >extension >application (or system)

          1. bootstrap: 主要是負(fù)責(zé)裝載jre/lib下的jar文件,當(dāng)然,你也可以通過(guò)-Xbootclasspath參數(shù)定義。該ClassLoader不能被Java代碼實(shí)例化,因?yàn)樗荍VM本身的一部分
          2. extension: 該ClassLoader是Bootstrap classLoader的子class loader。它主要負(fù)責(zé)加載jre/lib/ext/下的所有jar文件。只要jar包放置這個(gè)位置,就會(huì)被虛擬機(jī)加載。一個(gè)常見(jiàn)的、類(lèi)似的問(wèn)題是,你 將mysql的低版本驅(qū)動(dòng)不小心放置在這兒,但你的Web應(yīng)用程序的lib下有一個(gè)新的jdbc驅(qū)動(dòng),但怎么都報(bào)錯(cuò),譬如不支持JDBC2.0的 DataSource,這時(shí)你就要當(dāng)心你的新jdbc可能并沒(méi)有被加載。這就是ClassLoader的delegate現(xiàn)象。常見(jiàn)的有l(wèi)og4j、 common-log、dbcp會(huì)出現(xiàn)問(wèn)題,因?yàn)樗鼈兒苋菀妆蝗巳竭@個(gè)ext目錄,或是Tomcat下的common/lib目錄。
          3. application loader: 也稱(chēng)為System ClassLoaer。它負(fù)責(zé)加載CLASSPATH環(huán)境變量下的classes。缺省情況下,它是用戶創(chuàng)建的任何ClassLoader的父 ClassLoader,我們創(chuàng)建的standalone應(yīng)用的main class缺省情況下也是由它加載(通過(guò)Thread.currentThread().getContextClassLoader()查看)。

          我們實(shí)際開(kāi)發(fā)中,用ClassLoader更多時(shí)候是用其加載classpath下的資源,特別是配置文件,如ClassLoader.getResource(),比FileInputStream直接。

          ClassLoader是一種分級(jí)(hierarchy)的代理(delegation)模型。
          Delegation:其實(shí)是Parent Delegation,當(dāng)需要加載一個(gè)class時(shí),當(dāng)前線程的ClassLoader首先會(huì)將請(qǐng)求代理到其父classLoader,遞歸向上,如果該 class已經(jīng)被父classLoader加載,那么直接拿來(lái)用,譬如典型的ArrayList,它最終由Bootstrap ClassLoader加載。并且,每個(gè)ClassLoader只有一個(gè)父ClassLoader。
          Class查找的位置和順序依次是:Cache、parent、self。
          Hierarchy: 上面的delegation已經(jīng)暗示了一種分級(jí)結(jié)構(gòu),同時(shí)它也說(shuō)明:一個(gè)ClassLoader只能看到被它自己加載的 classes,或是看到其父(parent) ClassLoader或祖先(ancestor) ClassLoader加載的Classes。
          在一個(gè)單虛擬機(jī)環(huán)境下,標(biāo)識(shí)一個(gè)類(lèi)有兩個(gè)因素:class的全路徑名、該類(lèi)的ClassLoader。

          ===================Tomcat Class Loading==========================================


          posted @ 2008-12-21 12:23 Xiaobo Sun 閱讀(240) | 評(píng)論 (0)編輯 收藏

          Design Pattern: delegation

           class A {
               void f() { System.out.println("A: doing f()"); }
               void g() { System.out.println("A: doing g()"); }
          }

          class C {
               // delegation
               A a = new A();

               void f() { a.f(); }
               void g() { a.g(); }

               // normal attributes
               X x = new X();
               void y() { /* do stuff */ }
          }

          public class Main {
               public static void main(String[] args) {
                   C c = new C();
                   c.f();
                   c.g();
               }
          }

          posted @ 2008-12-14 09:34 Xiaobo Sun 閱讀(290) | 評(píng)論 (0)編輯 收藏

          Design Pattern: Proxy, dynamic Proxy

          代理模式

           Proxy Pattern's 3 roles:

          1.  (abstract common)Subject:common interface

          2.  ProxySubject:含有the reference to the RealSubject //delegation

          3.  RealSubject:實(shí)現(xiàn)邏輯的類(lèi)

          類(lèi)圖如下:

          圖1

          Java 動(dòng)態(tài)代理

          從JDK1.3開(kāi)始,Java就引入了動(dòng)態(tài)代理的概念。動(dòng)態(tài)代理(Dynamic Proxy)可以幫助你減少代碼行數(shù),真正提高代碼的可復(fù)用度。

           類(lèi)圖如下:

          圖2 

          動(dòng)態(tài)代理和普通的代理模式的區(qū)別,就是動(dòng)態(tài)代理中的代理類(lèi)是由java.lang.reflect.Proxy類(lèi)在運(yùn)行期時(shí)根據(jù)接口定義,采用Java反射功能動(dòng)態(tài)生成的(圖2的匿名實(shí)現(xiàn)類(lèi))。和java.lang.reflect.InvocationHandler結(jié)合,可以加強(qiáng)現(xiàn)有類(lèi)的方法實(shí)現(xiàn)。如圖2,圖中的自定義Handler實(shí)現(xiàn)InvocationHandler接口,自定義Handler實(shí)例化時(shí),將實(shí)現(xiàn)類(lèi)傳入自定義Handler對(duì)象。自定義Handler需要實(shí)現(xiàn)invoke方法,該方法可以使用Java反射調(diào)用實(shí)現(xiàn)類(lèi)的實(shí)現(xiàn)的方法,同時(shí)當(dāng)然可以實(shí)現(xiàn)其他功能,例如在調(diào)用實(shí)現(xiàn)類(lèi)方法前后加入Log。而Proxy類(lèi)根據(jù)Handler和需要代理的接口動(dòng)態(tài)生成一個(gè)接口實(shí)現(xiàn)類(lèi)的對(duì)象。當(dāng)用戶調(diào)用這個(gè)動(dòng)態(tài)生成的實(shí)現(xiàn)類(lèi)時(shí),實(shí)際上是調(diào)用了自定義Handler的invoke方法。

          下面是使用動(dòng)態(tài)代理的步驟:

          1.  Client向Proxy請(qǐng)求一個(gè)具有某個(gè)功能的實(shí)例;

          2.  Proxy根據(jù)Subject,以自定義Handler創(chuàng)建一個(gè)匿名內(nèi)部類(lèi),并返回給Client;

          3.  Client獲取該匿名內(nèi)部類(lèi)的引用,調(diào)用在Subject接口種定義的方法;

          4.  匿名內(nèi)部類(lèi)將對(duì)方法的調(diào)用轉(zhuǎn)換為對(duì)自定義Handler中invoke方法的調(diào)用

          5. invoke方法根據(jù)一些規(guī)則做處理,如記錄log,然后調(diào)用SubjectImpl中的方法

           

          Examples

           

          Here is a simple example that prints out a message before and after a method invocation on an object that implements an arbitrary list of interfaces:

          public interface Foo {
          Object bar(Object obj) throws BazException;
          }
          public class FooImpl implements Foo {
          Object bar(Object obj) throws BazException {
          // ...
          }
          }
          public class DebugProxy implements java.lang.reflect.InvocationHandler {
          private Object obj;
          public static Object newInstance(Object obj) {
          return java.lang.reflect.Proxy.newProxyInstance(
          obj.getClass().getClassLoader(),
          obj.getClass().getInterfaces(),
          new DebugProxy(obj));
          }
          private DebugProxy(Object obj) {
          this.obj = obj;
          }
          public Object invoke(Object proxy, Method m, Object[] args)
          throws Throwable
          {
          Object result;
          try {
          System.out.println("before method " + m.getName());
          result = m.invoke(obj, args);
          } catch (InvocationTargetException e) {
          throw e.getTargetException();
          } catch (Exception e) {
          throw new RuntimeException("unexpected invocation exception: " +
          e.getMessage());
          } finally {
          System.out.println("after method " + m.getName());
          }
          return result;
          }
          }
          

          To construct a DebugProxy for an implementation of the Foo interface and call one of its methods:

              Foo foo = (Foo) DebugProxy.newInstance(new FooImpl());
          foo.bar(null);
          


           

          posted @ 2008-12-14 09:21 Xiaobo Sun 閱讀(398) | 評(píng)論 (0)編輯 收藏

          Linux 啟動(dòng)

          前言
          linux有自己一套完整的啟動(dòng)體系,抓住了linux啟動(dòng)的脈絡(luò),linux的啟動(dòng)過(guò)程將不再神秘。
          閱讀之前建議先看一下附圖。

          本文中假設(shè)inittab中設(shè)置的init tree為:
          /etc/rc.d/rc0.d
          /etc/rc.d/rc1.d
          /etc/rc.d/rc2.d
          /etc/rc.d/rc3.d
          /etc/rc.d/rc4.d
          /etc/rc.d/rc5.d
          /etc/rc.d/rc6.d
          /etc/rc.d/init.d

          目錄
          1. 關(guān)于linux的啟動(dòng)
          2. 關(guān)于rc.d
          3. 啟動(dòng)腳本示例
          4. 關(guān)于rc.local
          5. 關(guān)于bash啟動(dòng)腳本
          6. 關(guān)于開(kāi)機(jī)程序的自動(dòng)啟動(dòng)




          1. 關(guān)于linux的啟動(dòng)
          init是所有進(jìn)程之父
          init讀取/etc/inittab,執(zhí)行rc.sysinit腳本
          (注意文件名是不一定的,有些unix甚至?xí)⒄Z(yǔ)句直接寫(xiě)在inittab中)
          rc.sysinit腳本作了很多工作:

          init $PATH
          config network
          start swap function
          set hostname
          check root file system, repair if needed
          check root space
          ....

          rc.sysinit根據(jù)inittab執(zhí)行rc?.d腳本
          linux是多用戶系統(tǒng),getty是多用戶與單用戶的分水嶺
          在getty之前運(yùn)行的是系統(tǒng)腳本

          2. 關(guān)于rc.d
          所有啟動(dòng)腳本放置在 /etc/rc.d/init.d下
          rc?.d中放置的是init.d中腳本的鏈接,命名格式是:
          S{number}{name}
          K{number}{name}
          S開(kāi)始的文件向腳本傳遞start參數(shù)
          K開(kāi)始的文件向腳本傳遞stop參數(shù)
          number決定執(zhí)行的順序

          3. 啟動(dòng)腳本示例

          這是一個(gè)用來(lái)啟動(dòng)httpd的 /etc/rc.d/init.d/apache 腳本:

          代碼:
          #!/bin/bash

          source /etc/sysconfig/rc
          source $rc_functions

          case "$1" in
                  start)
                          echo "Starting Apache daemon..."
                          /usr/local/apache2/bin/apachectl -k start
                          evaluate_retval
                          ;;

                  stop)
                          echo "Stopping Apache daemon..."
                          /usr/local/apache2/bin/apachectl -k stop
                          evaluate_retval
                          ;;

                  restart)
                          echo "Restarting Apache daemon..."
                          /usr/local/apache2/bin/apachectl -k restart
                          evaluate_retval
                          ;;

                  status)
                          statusproc /usr/local/apache2/bin/httpd
                          ;;
                          
                  *)
                          echo "Usage: $0 {start|stop|restart|status}"
                          exit 1
                          ;;
          esac
          可以看出他接受start,stop,restart,status參數(shù)

          然后可以這樣建立rc?.d的鏈接:

          代碼:
          cd /etc/rc.d/init.d &&
          ln -sf ../init.d/apache ../rc0.d/K28apache &&
          ln -sf ../init.d/apache ../rc1.d/K28apache &&
          ln -sf ../init.d/apache ../rc2.d/K28apache &&
          ln -sf ../init.d/apache ../rc3.d/S32apache &&
          ln -sf ../init.d/apache ../rc4.d/S32apache &&
          ln -sf ../init.d/apache ../rc5.d/S32apache &&
          ln -sf ../init.d/apache ../rc6.d/K28apache

          4. 關(guān)于rc.local

          經(jīng)常使用的 rc.local 則完全是習(xí)慣問(wèn)題,不是標(biāo)準(zhǔn)。
          各個(gè)發(fā)行版有不同的實(shí)現(xiàn)方法,可以這樣實(shí)現(xiàn):

          代碼:
          touch /etc/rc.d/rc.local
          chmod +x /etc/rc.d/rc.local
          ln -sf /etc/rc.d/rc.local /etc/rc.d/rc1.d/S999rc.local &&
          ln -sf /etc/rc.d/rc.local /etc/rc.d/rc2.d/S999rc.local &&
          ln -sf /etc/rc.d/rc.local /etc/rc.d/rc3.d/S999rc.local &&
          ln -sf /etc/rc.d/rc.local /etc/rc.d/rc4.d/S999rc.local &&
          ln -sf /etc/rc.d/rc.local /etc/rc.d/rc5.d/S999rc.local &&
          ln -sf /etc/rc.d/rc.local /etc/rc.d/rc6.d/S999rc.local

          5. 關(guān)于bash啟動(dòng)腳本

          /etc/profile
          /etc/bashrc
          ~/.bash_profile
          ~/.bashrc
          是bash的啟動(dòng)腳本

          一般用來(lái)設(shè)置單用戶的啟動(dòng)環(huán)境,也可以實(shí)現(xiàn)開(kāi)機(jī)單用戶的程序,但要明確他們都是屬于bash范疇而不是系統(tǒng)范疇。

          他們的具體作用介紹如下:

          /bin/bash這個(gè)命令解釋程序(后面簡(jiǎn)稱(chēng)shell)使用了一系列啟動(dòng)文件來(lái)建立一個(gè)運(yùn)行環(huán)境:

          /etc/profile
          /etc/bashrc
          ~/.bash_profile
          ~/.bashrc
          ~/.bash_logout
          每一個(gè)文件都有特殊的功用并對(duì)登陸和交互環(huán)境有不同的影響。
          /etc/profile 和 ~/.bash_profile 是在啟動(dòng)一個(gè)交互登陸shell的時(shí)候被調(diào)用。
          /etc/bashrc 和 ~/.bashrc 是在一個(gè)交互的非登陸shell啟動(dòng)的時(shí)候被調(diào)用。
          ~/.bash_logout 在用戶注銷(xiāo)登陸的時(shí)候被讀取

          一個(gè)交互的登陸shell會(huì)在 /bin/login 成功登陸之后運(yùn)行。一個(gè)交互的非登陸shell是通過(guò)命令行來(lái)運(yùn)行的,如 [prompt]$/bin/bash。一般一個(gè)非交互的shell出現(xiàn)在運(yùn)行shell腳本的時(shí)候。之所以叫非交互的shell,是因?yàn)樗辉诿钚猩? 等待輸入而只是執(zhí)行腳本程序。
          =====================================================================================================
          本文以RedHat9.0和i386平臺(tái)為例,剖析了從用戶打開(kāi)電源直到屏幕出現(xiàn)命令行提示符的整個(gè)Linux啟動(dòng)過(guò)程。并且介紹了啟動(dòng)中涉及到的各種文件。

            閱讀Linux源代碼,無(wú)疑是深入學(xué)習(xí)Linux的最好方法。在本文對(duì)Linux啟動(dòng)過(guò)程的介紹中,我們也嘗試從源代碼的視角來(lái)更深入的剖析Linux的啟動(dòng)過(guò)程,所以其中也簡(jiǎn)單涉及到部分相關(guān)的Linux源代碼,Linux啟動(dòng)這部分的源碼主要使用的是C語(yǔ)言,也涉及到了少量的匯編。而啟動(dòng)過(guò)程中也執(zhí)行了大量的shell(主要是bash shell)所寫(xiě)腳本。為了方便讀者閱讀,筆者將整個(gè)Linux啟動(dòng)過(guò)程分成以下幾個(gè)部分逐一介紹,大家可以參考下圖:

            當(dāng)用戶打開(kāi)PC的電源,BIOS開(kāi)機(jī)自檢,按BIOS中設(shè)置的啟動(dòng)設(shè)備(通常是硬盤(pán))啟動(dòng),接著啟動(dòng)設(shè)備上安裝的引導(dǎo)程序lilo 或grub開(kāi)始引導(dǎo)Linux,Linux首先進(jìn)行內(nèi)核的引導(dǎo),接下來(lái)執(zhí)行init程序,init程序調(diào)用了rc.sysinit和rc等程 序,rc.sysinit和rc當(dāng)完成系統(tǒng)初始化和運(yùn)行服務(wù)的任務(wù)后,返回init;init啟動(dòng)了mingetty后,打開(kāi)了終端供用戶登錄系統(tǒng),用戶 登錄成功后進(jìn)入了Shell,這樣就完成了從開(kāi)機(jī)到登錄的整個(gè)啟動(dòng)過(guò)程。

          下面就將逐一介紹其中幾個(gè)關(guān)鍵的部分:

            第一部分:內(nèi)核的引導(dǎo)(核內(nèi)引導(dǎo))

            Red Hat9.0可以使用lilo或grub等引導(dǎo)程序開(kāi) 始引導(dǎo)Linux系統(tǒng),當(dāng)引導(dǎo)程序成功完成引導(dǎo)任務(wù)后,Linux從它們手中接管了CPU的控制權(quán),然后CPU就開(kāi)始執(zhí)行Linux的核心映象代碼,開(kāi)始 了Linux啟動(dòng)過(guò)程。這里使用了幾個(gè)匯編程序來(lái)引導(dǎo)Linux,這一步泛及到Linux源代碼樹(shù)中的“arch/i386/boot”下的這幾個(gè)文 件:bootsect.S、setup.S、video.S等。

            其中bootsect.S是生成引導(dǎo)扇區(qū)的匯編源碼,它完成加載動(dòng)作后直接跳轉(zhuǎn)到setup.S的程序入口。setup.S的主要功能就是將系 統(tǒng)參數(shù)(包括內(nèi)存、磁盤(pán)等,由BIOS返回)拷貝到特別內(nèi)存中,以便以后這些參數(shù)被保護(hù)模式下的代碼來(lái)讀取。此外,setup.S還將video.S中的 代碼包含進(jìn)來(lái),檢測(cè)和設(shè)置顯示器和顯示模式。最后,setup.S將系統(tǒng)轉(zhuǎn)換到保護(hù)模式,并跳轉(zhuǎn)到 0x100000。

            那么0x100000這個(gè)內(nèi)存地址中存放的是什么代碼?而這些代碼又是從何而來(lái)的呢?

            0x100000這個(gè)內(nèi)存地址存放的是解壓后的內(nèi)核,因?yàn)镽ed Hat提供的內(nèi)核包含了眾多驅(qū)動(dòng)和 功能而顯得比較大,所以在內(nèi)核編譯中使用了“makebzImage”方式,從而生成壓縮過(guò)的內(nèi)核,在RedHat中內(nèi)核常常被命名為vmlinuz,在 Linux的最初引導(dǎo)過(guò)程中,是通過(guò)"arch/i386/boot/compressed/"中的head.S利用misc.c中定義的 decompress_kernel()函數(shù),將內(nèi)核vmlinuz解壓到0x100000的。

            當(dāng)CPU跳到0x100000時(shí),將執(zhí)行"arch/i386/kernel/head.S"中的startup_32,它也是vmlinux 的入口,然后就跳轉(zhuǎn)到start_kernel()中去了。start_kernel()是"init/main.c"中的定義的函 數(shù),start_kernel()中調(diào)用了一系列初始化函數(shù),以完成kernel本身的設(shè)置。start_kernel()函數(shù)中,做了大量的工作來(lái)建立 基本的Linux核心環(huán)境。如果順利執(zhí)行完start_kernel(),則基本的Linux核心環(huán)境已經(jīng)建立起來(lái)了。

            在start_kernel()的最后,通過(guò)調(diào)用init()函數(shù),系統(tǒng)創(chuàng)建第一個(gè)核心線程,啟動(dòng)了init過(guò)程。而核心線程init()主要 是來(lái)進(jìn)行一些外設(shè)初始化的工作的,包括調(diào)用do_basic_setup()完成外設(shè)及其驅(qū)動(dòng)程序的加載和初始化。并完成文件系統(tǒng)初始化和root文件系 統(tǒng)的安裝。

            當(dāng)do_basic_setup()函數(shù)返回init(),init()又打開(kāi)了/dev/console設(shè)備,重定向三個(gè)標(biāo)準(zhǔn)的輸入輸出文件 stdin、stdout和stderr到控制臺(tái),最后,搜索文件系統(tǒng)中的init程序(或者由init=命令行參數(shù)指定的程序),并使用 execve()系統(tǒng)調(diào)用加載執(zhí)行init程序。到此init()函數(shù)結(jié)束,內(nèi)核的引導(dǎo)部分也到此結(jié)束了,

          第二部分:運(yùn)行init

            init的進(jìn)程號(hào)是1,從這一點(diǎn)就能看出,init進(jìn)程是系統(tǒng)所有進(jìn)程的起點(diǎn),Linux在完成核內(nèi)引導(dǎo)以后,就開(kāi)始運(yùn)行init程序,。init程序需要讀取配置文件/etc/inittab。inittab是一個(gè)不可執(zhí)行的文本文件,它有若干行指令所組成。在Redhat系統(tǒng)中,inittab的內(nèi)容如下所示(以“###"開(kāi)始的中注釋為筆者增加的):

            #
          # inittab       This file describes how the INIT process should set up
          #               the system in a certain run-level.
          #
          # Author:       Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
          #               Modified for RHS Linux by Marc Ewing and Donnie Barnes
          #

            # Default runlevel. The runlevels used by RHS are:
          #   0 - halt (Do NOT set initdefault to this)
          #   1 - Single user mode
          #   2 - Multiuser, without NFS (The same as 3, if you do not havenetworking)
          #   3 - Full multiuser mode
          #   4 - unused
          #   5 - X11
          #   6 - reboot (Do NOT set initdefault to this)
          #
          ###表示當(dāng)前缺省運(yùn)行級(jí)別為5(initdefault);
          id:5:initdefault:

            ###啟動(dòng)時(shí)自動(dòng)執(zhí)行/etc/rc.d/rc.sysinit腳本(sysinit)
          # System initialization.
          si::sysinit:/etc/rc.d/rc.sysinit

            l0:0:wait:/etc/rc.d/rc 0
          l1:1:wait:/etc/rc.d/rc 1
          l2:2:wait:/etc/rc.d/rc 2
          l3:3:wait:/etc/rc.d/rc 3
          l4:4:wait:/etc/rc.d/rc 4
          ###當(dāng)運(yùn)行級(jí)別為5時(shí),以5為參數(shù)運(yùn)行/etc/rc.d/rc腳本,init將等待其返回(wait)
          l5:5:wait:/etc/rc.d/rc 5
          l6:6:wait:/etc/rc.d/rc 6

            ###在啟動(dòng)過(guò)程中允許按CTRL-ALT-DELETE重啟系統(tǒng)
          # Trap CTRL-ALT-DELETE
          ca::ctrlaltdel:/sbin/shutdown -t3 -r now

            # When our UPS tells us power has failed, assume we have a few minutes
          # of power left.  Schedule a shutdown for 2 minutes from now.
          # This does, of course, assume you have powerd installed and your
          # UPS connected and working correctly.
          pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

            # If power was restored before the shutdown kicked in, cancel it.
          pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"

            ###在2、3、4、5級(jí)別上以ttyX為參數(shù)執(zhí)行/sbin/mingetty程序,打開(kāi)ttyX終端用于用戶登錄,
          ###如果進(jìn)程退出則再次運(yùn)行mingetty程序(respawn)
          # Run gettys in standard runlevels
          1:2345:respawn:/sbin/mingetty tty1
          2:2345:respawn:/sbin/mingetty tty2
          3:2345:respawn:/sbin/mingetty tty3
          4:2345:respawn:/sbin/mingetty tty4
          5:2345:respawn:/sbin/mingetty tty5
          6:2345:respawn:/sbin/mingetty tty6

            ###在5級(jí)別上運(yùn)行xdm程序,提供xdm圖形方式登錄界面,并在退出時(shí)重新執(zhí)行(respawn)
          # Run xdm in runlevel 5
          x:5:respawn:/etc/X11/prefdm -nodaemon

          以上面的inittab文件為例,來(lái)說(shuō)明一下inittab的格式。其中以#開(kāi)始的行是注釋行,除了注釋行之外,每一行都有以下格式:

            id:runlevel:action:process

            對(duì)上面各項(xiàng)的詳細(xì)解釋如下:

            1. id

            id是指入口標(biāo)識(shí)符,它是一個(gè)字符串,對(duì)于getty或mingetty等其他login程序項(xiàng),要求id與tty的編號(hào)相同,否則getty程序?qū)⒉荒苷9ぷ鳌?/p>

            2. runlevel

            runlevel是init所處于的運(yùn)行級(jí)別的標(biāo)識(shí),一般使用0-6以及S或s。0、1、6運(yùn)行級(jí)別被系統(tǒng)保留:其中0作為shutdown動(dòng) 作,1作為重啟至單用戶模式,6為重啟;S和s意義相同,表示單用戶模式,且無(wú)需inittab文件,因此也不在inittab中出現(xiàn),實(shí)際上,進(jìn)入單用 戶模式時(shí),init直接在控制臺(tái)(/dev/console)上運(yùn)行/sbin/sulogin。在一般的系統(tǒng)實(shí)現(xiàn)中,都使用了2、3、4、5幾個(gè)級(jí)別, 在Redhat系統(tǒng)中,2表示無(wú)NFS支持的多用戶模式,3表示完全多用戶模式(也是最常用的級(jí)別),4保留給用戶自定義,5表示XDM圖形登錄方式。 7-9級(jí)別也是可以使用的,傳統(tǒng)的Unix系統(tǒng)沒(méi)有定義這幾個(gè)級(jí)別。runlevel可以是并列的多個(gè)值,以匹配多個(gè)運(yùn)行級(jí)別,對(duì)大多數(shù)action來(lái) 說(shuō),僅當(dāng)runlevel與當(dāng)前運(yùn)行級(jí)別匹配成功才會(huì)執(zhí)行。

            3. action

            action是描述其后的process的運(yùn)行方式的。action可取的值包括:initdefault、sysinit、boot、bootwait等:

            initdefault是一個(gè)特殊的action值,用于標(biāo)識(shí)缺省的啟動(dòng)級(jí)別;當(dāng)init由核心激活以后,它將讀取inittab中的 initdefault項(xiàng),取得其中的runlevel,并作為當(dāng)前的運(yùn)行級(jí)別。如果沒(méi)有inittab文件,或者其中沒(méi)有initdefault 項(xiàng),init將在控制臺(tái)上請(qǐng)求輸入runlevel。

            sysinit、boot、bootwait等action將在系統(tǒng)啟動(dòng)時(shí)無(wú)條件運(yùn)行,而忽略其中的runlevel。

            其余的action(不含initdefault)都與某個(gè)runlevel相關(guān)。各個(gè)action的定義在inittab的man手冊(cè)中有詳細(xì)的描述。

            4. process

            process為具體的執(zhí)行程序。程序后面可以帶參數(shù)。

            第三部分:系統(tǒng)初始化

            在init的配置文件中有這么一行:

            si::sysinit:/etc/rc.d/rc.sysinit

            它調(diào)用執(zhí)行了/etc/rc.d/rc.sysinit,而rc.sysinit是一個(gè)bash shell的腳本,它主要是完成一些系統(tǒng)初始化的工作,rc.sysinit是每一個(gè)運(yùn)行級(jí)別都要首先運(yùn)行的重要腳本。它主要完成的工作有:激活交換分區(qū),檢查磁盤(pán),加載硬件模塊以及其它一些需要優(yōu)先執(zhí)行任務(wù)。

            rc.sysinit約有850多行,但是每個(gè)單一的功能還是比較簡(jiǎn)單,而且?guī)в凶⑨專(zhuān)ㄗh有興趣的用戶可以自行閱讀自己機(jī)器上的該文件,以了解系統(tǒng)初始化所詳細(xì)情況。由于此文件較長(zhǎng),所以不在本文中列出來(lái),也不做具體的介紹。

            當(dāng)rc.sysinit程序執(zhí)行完畢后,將返回init繼續(xù)下一步。

          第四部分:?jiǎn)?dòng)對(duì)應(yīng)運(yùn)行級(jí)別的守護(hù)進(jìn)程

            在rc.sysinit執(zhí)行后,將返回init繼續(xù)其它的動(dòng)作,通常接下來(lái)會(huì)執(zhí)行到/etc/rc.d/rc程序。以運(yùn)行級(jí)別3為例,init將執(zhí)行配置文件inittab中的以下這行:

            l5:5:wait:/etc/rc.d/rc 5

            這一行表示以5為參數(shù)運(yùn)行/etc/rc.d/rc,/etc/rc.d/rc是一個(gè)Shell腳本,它接受5作為參數(shù),去執(zhí)行/etc /rc.d/rc5.d/目錄下的所有的rc啟動(dòng)腳本,/etc/rc.d/rc5.d/目錄中的這些啟動(dòng)腳本實(shí)際上都是一些鏈接文件,而不是真正的rc 啟動(dòng)腳本,真正的rc啟動(dòng)腳本實(shí)際上都是放在/etc/rc.d/init.d/目錄下。而這些rc啟動(dòng)腳本有著類(lèi)似的用法,它們一般能接受start、 stop、restart、status等參數(shù)。

            /etc/rc.d/rc5.d/中的rc啟動(dòng)腳本通常是K或S開(kāi)頭的鏈接文件,對(duì)于以以S開(kāi)頭的啟動(dòng)腳本,將以start參數(shù)來(lái)運(yùn)行。而如果 發(fā)現(xiàn)存在相應(yīng)的腳本也存在K打頭的鏈接,而且已經(jīng)處于運(yùn)行態(tài)了(以/var/lock/subsys/下的文件作為標(biāo)志),則將首先以stop為參數(shù)停止 這些已經(jīng)啟動(dòng)了的守護(hù)進(jìn)程,然后再重新運(yùn)行。這樣做是為了保證是當(dāng)init改變運(yùn)行級(jí)別時(shí),所有相關(guān)的守護(hù)進(jìn)程都將重啟。

            至于在每個(gè)運(yùn)行級(jí)中將運(yùn)行哪些守護(hù)進(jìn)程,用戶可以通過(guò)chkconfig或setup中的"System Services"來(lái)自行設(shè)定。常見(jiàn)的守護(hù)進(jìn)程有:

            amd:自動(dòng)安裝NFS守護(hù)進(jìn)程
          apmd:高級(jí)電源管理守護(hù)進(jìn)程
          arpwatch:記錄日志并構(gòu)建一個(gè)在LAN接口上看到的以太網(wǎng)地址和IP地址對(duì)數(shù)據(jù)庫(kù)
          autofs:自動(dòng)安裝管理進(jìn)程automount,與NFS相關(guān),依賴(lài)于NIS
          crond:Linux下的計(jì)劃任務(wù)的守護(hù)進(jìn)程
          named:DNS服務(wù)器
          netfs:安裝NFS、Samba和NetWare網(wǎng)絡(luò)文件系統(tǒng)
          network:激活已配置網(wǎng)絡(luò)接口的腳本程序
          nfs:打開(kāi)NFS服務(wù)
          portmap:RPC portmap管理器,它管理基于RPC服務(wù)的連接
          sendmail:郵件服務(wù)器sendmail
          smb:Samba文件共享/打印服務(wù)
          syslog:一個(gè)讓系統(tǒng)引導(dǎo)時(shí)起動(dòng)syslog和klogd系統(tǒng)日志守候進(jìn)程的腳本
          xfs:X Window字型服務(wù)器,為本地和遠(yuǎn)程X服務(wù)器提供字型集
          Xinetd:支持多種網(wǎng)絡(luò)服務(wù)的核心守護(hù)進(jìn)程,可以管理wuftp、sshd、telnet等服務(wù)

            這些守護(hù)進(jìn)程也啟動(dòng)完成了,rc程序也就執(zhí)行完了,然后又將返回init繼續(xù)下一步。

          第五部分:建立終端

            rc執(zhí)行完畢后,返回init。這時(shí)基本系統(tǒng)環(huán)境已經(jīng)設(shè)置好了,各種守護(hù)進(jìn)程也已經(jīng)啟動(dòng)了。init接下來(lái)會(huì)打開(kāi)6個(gè)終端,以便用戶登錄系統(tǒng)。通過(guò)按Alt+Fn(n對(duì)應(yīng)1-6)可以在這6個(gè)終端中切換。在inittab中的以下6行就是定義了6個(gè)終端:

            1:2345:respawn:/sbin/mingetty tty1
          2:2345:respawn:/sbin/mingetty tty2
          3:2345:respawn:/sbin/mingetty tty3
          4:2345:respawn:/sbin/mingetty tty4
          5:2345:respawn:/sbin/mingetty tty5
          6:2345:respawn:/sbin/mingetty tty6

            從上面可以看出在2、3、4、5的運(yùn)行級(jí)別中都將以respawn方式運(yùn)行mingetty程序,mingetty程序能打開(kāi)終端、設(shè)置模式。同時(shí)它會(huì)顯示一個(gè)文本登錄界面,這個(gè)界面就是我們經(jīng)常看到的登錄界面,在這個(gè)登錄界面中會(huì)提示用戶輸入用戶名,而用戶輸入的用戶將作為參數(shù)傳給login程序來(lái)驗(yàn)證用戶的身份。

            第六部分:登錄系統(tǒng),啟動(dòng)完成

            對(duì)于運(yùn)行級(jí)別為5的圖形方式用戶來(lái)說(shuō),他們的登錄是通過(guò)一個(gè)圖形化的登錄界面。登錄成功后可以直接進(jìn)入KDE、Gnome等窗口管理器。而本文主要講的還是文本方式登錄的情況:

            當(dāng)我們看到mingetty的登錄界面時(shí),我們就可以輸入用戶名和密碼來(lái)登錄系統(tǒng)了。

          Linux的賬號(hào)驗(yàn)證程序是 login,login會(huì)接收mingetty傳來(lái)的用戶名作為用戶名參數(shù)。然后login會(huì)對(duì)用戶名進(jìn)行分析:如果用戶名不是root,且存在/etc /nologin文件,login將輸出nologin文件的內(nèi)容,然后退出。這通常用來(lái)系統(tǒng)維護(hù)時(shí)防止非root用戶登錄。只有/etc /securetty中登記了的終端才允許root用戶登錄,如果不存在這個(gè)文件,則root可以在任何終端上登錄。/etc/usertty文件用于對(duì) 用戶作出附加訪問(wèn)限制,如果不存在這個(gè)文件,則沒(méi)有其他限制。

            在分析完用戶名后,login將搜索/etc/passwd以及/etc/shadow來(lái)驗(yàn)證密碼以及設(shè)置賬戶的其它信息,比如:主目錄是什么、使用何種shell。如果沒(méi)有指定主目錄,將默認(rèn)為根目錄;如果沒(méi)有指定shell,將默認(rèn)為/bin/bash。

            login程序成功后,會(huì)向?qū)?yīng)的終端在輸出最近一次登錄的信息(在/var/log/lastlog中有記錄),并檢查用戶是否有新郵件(在 /usr/spool/mail/的對(duì)應(yīng)用戶名目錄下)。然后開(kāi)始設(shè)置各種環(huán)境變量:對(duì)于bash來(lái)說(shuō),系統(tǒng)首先尋找/etc/profile腳本文件, 并執(zhí)行它;然后如果用戶的主目錄中存在.bash_profile文件,就執(zhí)行它,在這些文件中又可能調(diào)用了其它配置文件,所有的配置文件執(zhí)行后后,各種 環(huán)境變量也設(shè)好了,這時(shí)會(huì)出現(xiàn)大家熟悉的命令行提示符,到此整個(gè)啟動(dòng)過(guò)程就結(jié)束了。

            希望通過(guò)上面對(duì)Linux啟動(dòng)過(guò)程的剖析能幫助那些想深入學(xué)習(xí)Linux用戶建立一個(gè)相關(guān)Linux啟動(dòng)過(guò)程的清晰概念,進(jìn)而可以進(jìn)一步研究Linux接下來(lái)是如何工作的。



          posted @ 2008-12-10 18:23 Xiaobo Sun 閱讀(597) | 評(píng)論 (1)編輯 收藏

          Tomcat remote debugging with Eclipse (JPDA debugging)

          ===============Tomcat setting -- enable JPDA debugging================================
          >cd %CATALINA_HOME%\bin
          >SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5888
          >catalina start
          ================Eclipse Setting===================================================
          Debug Configuration->Remote Java Application->new
          --Connect--
          Name: Debug Tomcat
          Project: jpetstore (which project is copied to the tomcat)
          Host: localhost
          Port: 5888
          --Source--
          all libs and src (
          此時(shí)可以看到程序會(huì)停在本機(jī)設(shè)的斷點(diǎn)上,要提醒的是我們程序?qū)嶋H是跑在服務(wù)器上的,卻能使用本機(jī)的斷點(diǎn),挺奇妙的!)

          posted @ 2008-12-10 17:09 Xiaobo Sun 閱讀(590) | 評(píng)論 (0)編輯 收藏

          spring mvc

          spring mvc 這部機(jī)器 說(shuō)白了其實(shí)很簡(jiǎn)單,DispatcherServlet 把 HandlerMapping Controller ViewResolver 3個(gè)組件 組裝在一起就完成了整個(gè)處理過(guò)程。

          想起來(lái)就像人吃飯一樣。把飯放入嘴巴,經(jīng)過(guò)喉嚨,然后到胃里,處理一下,再接著往下傳,到腸子 最后把處理的結(jié)果 排泄出來(lái)。呵呵,惡心一把  
          當(dāng)然還吸收了一些,這就類(lèi)似存了一些數(shù)據(jù)到數(shù)據(jù)庫(kù)。說(shuō)白了還真這么回事。

          posted @ 2008-12-09 18:03 Xiaobo Sun 閱讀(153) | 評(píng)論 (0)編輯 收藏

          Ctrl-Z,bg,jobs,fg

          Linux/Unix 區(qū)別于微軟平臺(tái)最大的優(yōu)點(diǎn)就是真正的多用戶,多任務(wù)。因此在任務(wù)管理上也有別具特色的管理思想。
          我們知道,在 Windows 上面,我們要么讓一個(gè)程序作為服務(wù)在后臺(tái)一直運(yùn)行,要么停止這個(gè)服務(wù)。而不能讓程序在前臺(tái)后臺(tái)之間切換。而 Linux 提供了 fg 和 bg 命令,讓你輕松調(diào)度正在運(yùn)行的任務(wù)。

          假設(shè)你發(fā)現(xiàn)前臺(tái)運(yùn)行的一個(gè)程序需要很長(zhǎng)的時(shí)間,但是需要干其他的事情,你就可以用 Ctrl-Z ,終止這個(gè)程序,然后可以看到系統(tǒng)提示:
          [1]+ Stopped /root/bin/rsync.sh
          然后我們可以把程序調(diào)度到后臺(tái)執(zhí)行:(bg 后面的數(shù)字為作業(yè)號(hào))
          #bg 1
          [1]+ /root/bin/rsync.sh &
          用 jobs 命令查看正在運(yùn)行的任務(wù):
          #jobs
          [1]+ Running /root/bin/rsync.sh &
          如果想把它調(diào)回到前臺(tái)運(yùn)行,可以用
          #fg 1
          /root/bin/rsync.sh
          這樣,你在控制臺(tái)上就只能等待這個(gè)任務(wù)完成了。

          posted @ 2008-12-02 15:33 Xiaobo Sun 閱讀(308) | 評(píng)論 (0)編輯 收藏

          Vi: Search and Replace

          Vi: Search and Replace

          Change to normal mode with <ESC>.

          Search (Wraped around at end of file):

          Search STRING forward : / STRING.

          Search STRING backward: ? STRING.

          Repeat search: n

          Repeat search in opposite direction: N (SHIFT-n

          Replace: Same as with sed, Replace OLD with NEW:

          First occurrence on current line: :s/OLD/NEW

          Globally (all) on current line: :s/OLD/NEW/g

          Between two lines #,#: :#,#s/OLD/NEW/g

          Every occurrence in file: :%s/OLD/NEW/g 



          posted @ 2008-11-06 17:18 Xiaobo Sun 閱讀(1063) | 評(píng)論 (0)編輯 收藏

          extern

          1 基本解釋

          extern可以置于變量或者函數(shù)前,以標(biāo)示變量或者函數(shù)的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時(shí)在其他模塊中尋找其定義。

          另外,extern也可用來(lái)進(jìn)行鏈接指定。
          2 問(wèn)題:extern 變量

          在一個(gè)源文件里定義了一個(gè)數(shù)組:

          char a[6];

          在另外一個(gè)文件里用下列語(yǔ)句進(jìn)行了聲明:

          extern char *a;

          請(qǐng)問(wèn),這樣可以嗎?

          答案與分析:

          1)、不可以,程序運(yùn)行時(shí)會(huì)告訴你非法訪問(wèn)。原因在于,指向類(lèi)型T的指針并不等價(jià)于類(lèi)型T的數(shù)組。extern char *a聲明的是一個(gè)指針變量而不是字符數(shù)組,因此與實(shí)際的定義不同,從而造成運(yùn)行時(shí)非法訪問(wèn)。應(yīng)該將聲明改為extern char a[ ]。

          2)、例子分析如下,如果a[] = "abcd",則外部變量a=0x61626364 (abcd的ASCII碼值),*a顯然沒(méi)有意義,如下圖:


          顯然a指向的空間(0x61626364)沒(méi)有意義,易出現(xiàn)非法內(nèi)存訪問(wèn)。

          3)、這提示我們,在使用extern時(shí)候要嚴(yán)格對(duì)應(yīng)聲明時(shí)的格式,在實(shí)際編程中,這樣的錯(cuò)誤屢見(jiàn)不鮮。

          4)、extern用在變量聲明中常常有這樣一個(gè)作用,你在*.c文件中聲明了一個(gè)全局的變量,這個(gè)全局的變量如果要被引用,就放在*.h中并用extern來(lái)聲明。

          3 問(wèn)題:extern 函數(shù)1

          常常見(jiàn)extern放在函數(shù)的前面成為函數(shù)聲明的一部分,那么,C語(yǔ)言的關(guān)鍵字extern在函數(shù)的聲明中起什么作用?

          答案與分析:

          如果函數(shù)的聲明中帶有關(guān)鍵字extern,僅僅是暗示這個(gè)函數(shù)可能在別的源文件里定義,沒(méi)有其它作用。即下述兩個(gè)函數(shù)聲明沒(méi)有明顯的區(qū)別:

          extern int f(); 和int f();

          當(dāng)然,這樣的用處還是有的,就是在程序中取代include “*.h”來(lái)聲明函數(shù),在一些復(fù)雜的項(xiàng)目中,我比較習(xí)慣在所有的函數(shù)聲明前添加extern修飾。

          4 問(wèn)題:extern 函數(shù)2
           
          當(dāng)函數(shù)提供方單方面修改函數(shù)原型時(shí),如果使用方不知情繼續(xù)沿用原來(lái)的extern申明,這樣編譯時(shí)編譯器不會(huì)報(bào)錯(cuò)。但是在運(yùn)行過(guò)程中,因?yàn)樯倭嘶蛘叨嗔溯斎雲(yún)?shù),往往會(huì)照成系統(tǒng)錯(cuò)誤,這種情況應(yīng)該如何解決?

          答案與分析:

          目前業(yè)界針對(duì)這種情況的處理沒(méi)有一個(gè)很完美的方案,通常的做法是提供方在自己的xxx_pub.h中提供對(duì)外部接口的聲明,然后調(diào)用方include該頭文件,從而省去extern這一步。以避免這種錯(cuò)誤。

          寶劍有雙鋒,對(duì)extern的應(yīng)用,不同的場(chǎng)合應(yīng)該選擇不同的做法。
          ===============================================================================
          4.extern "C"的慣用法

          (1)在C++中引用C語(yǔ)言中的函數(shù)和變量,在包含C語(yǔ)言頭文件(假設(shè)為cExample.h)時(shí),需進(jìn)行下列處理:

          extern "C"
          {
          #include "cExample.h"
          }


          而在C語(yǔ)言的頭文件中,對(duì)其外部函數(shù)只能指定為extern類(lèi)型,C語(yǔ)言中不支持extern "C"聲明,在.c文件中包含了extern "C"時(shí)會(huì)出現(xiàn)編譯語(yǔ)法錯(cuò)誤。

          筆者編寫(xiě)的C++引用C函數(shù)例子工程中包含的三個(gè)文件的源代碼如下:
          C/C++ code


          /* c語(yǔ)言頭文件:cExample.h */

          #ifndef C_EXAMPLE_H

          #define C_EXAMPLE_H

          extern int add(int x,int y);

          #endif

          /* c語(yǔ)言實(shí)現(xiàn)文件:cExample.c */

          #include
          "cExample.h"

          int add( int x, int y )

          {

          return x + y;

          }

          // c++實(shí)現(xiàn)文件,調(diào)用add:cppFile.cpp

          extern "C"

          {

          #include
          "cExample.h"

          }

          int main(int argc, char* argv[])

          {

          add(
          2,3);

          return 0;

          }





          如果C
          ++調(diào)用一個(gè)C語(yǔ)言編寫(xiě)的.DLL時(shí),當(dāng)包括.DLL的頭文件或聲明接口函數(shù)時(shí),應(yīng)加extern "C" { }。



          2)在C中引用C++語(yǔ)言中的函數(shù)和變量時(shí),C++的頭文件需添加extern "C",但是在C語(yǔ)言中不能直接引用聲明了extern "C"的該頭文件,應(yīng)該僅將C文件中將C++中定義的extern "C"函數(shù)聲明為extern類(lèi)型。

          筆者編寫(xiě)的C引用C
          ++函數(shù)例子工程中包含的三個(gè)文件的源代碼如下:



          //C++頭文件 cppExample.h

          #ifndef CPP_EXAMPLE_H

          #define CPP_EXAMPLE_H

          extern "C" int add( int x, int y );

          #endif

          //C++實(shí)現(xiàn)文件 cppExample.cpp

          #include "cppExample.h"

          int add( int x, int y )

          {

          return x + y;

          }

          /* C實(shí)現(xiàn)文件 cFile.c

          /* 這樣會(huì)編譯出錯(cuò):#include "cExample.h"
          */

          extern int add( int x, int y );

          int main( int argc, char* argv[] )

          {

          add(
          2, 3 );

          return 0;

          }





          posted @ 2008-10-30 13:36 Xiaobo Sun 閱讀(338) | 評(píng)論 (0)編輯 收藏

          Windows&Linux copy&paste

          Linux : "highlighted" means "copy", "middle mouse" means "paste"

          To make Xming's clipboard work
          change /etc/init.d/custom.conf

              in [daemon]
                  KillInitClients=false

          posted @ 2008-10-30 12:07 Xiaobo Sun 閱讀(285) | 評(píng)論 (0)編輯 收藏

          Ref as function param

          常引用

          常引用聲明方式:const 類(lèi)型標(biāo)識(shí)符 &引用名=目標(biāo)變量名;
          用這種方式聲明的引用,不能通過(guò)引用對(duì)目標(biāo)變量的值進(jìn)行修改,從而使引用的目標(biāo)成為
          const,達(dá)到了引用的安全性。
          【例3】:
          int a ;
          const int &ra=a;
          ra=1; //錯(cuò)誤
          a=1; //正確
          這不光是讓代碼更健壯,也有些其它方面的需要。
          【例4】:假設(shè)有如下函數(shù)聲明:
          string foo( );
          void bar(string & s);
          那么下面的表達(dá)式將是非法的:
          bar(foo( ));
          bar("hello world");
          原因在于foo( )和"hello world"串都會(huì)產(chǎn)生一個(gè)臨時(shí)對(duì)象,而在C++中,這些臨時(shí)對(duì)象都是
          const 類(lèi)型的。因此上面的表達(dá)式就是試圖將一個(gè)const 類(lèi)型的對(duì)象轉(zhuǎn)換為非const 類(lèi)型,
          這是非法的。
          引用型參數(shù)應(yīng)該在能被定義為const 的情況下,盡量定義為const 。

          posted @ 2008-10-23 12:15 Xiaobo Sun 閱讀(157) | 評(píng)論 (0)編輯 收藏

          shell技巧




          1.test測(cè)試命令
          test命令用于檢查某個(gè)條件是否成立,它可以進(jìn)行數(shù)值、字符和文件三個(gè)方面的測(cè)試,
          其測(cè)試符和相應(yīng)的功能分別如下:
          (1)數(shù)值測(cè)試:
          -eq:等于則為真
          -ne:不等于則為真
          -gt:大于則為真
          -ge:大于等于則為真
          -lt:小于則為真
          -le:小于等于則為真
          (2)字符串測(cè)試:
          =:等于則為真
          !=:不相等則為真
          -z 字符串:字符串長(zhǎng)度偽則為真
          -n 字符串:字符串長(zhǎng)度不偽則為真
          (3)文件測(cè)試:
          -e 文件名:如果文件存在則為真
          -r 文件名:如果文件存在且可讀則為真
          -w 文件名:如果文件存在且可寫(xiě)則為真
          -x 文件名:如果文件存在且可執(zhí)行則為真
          -s 文件名:如果文件存在且至少有一個(gè)字符則為真
          -d 文件名:如果文件存在且為目錄則為真
          -f 文件名:如果文件存在且為普通文件則為真
          -c 文件名:如果文件存在且為字符型特殊文件則為真
          -b 文件名:如果文件存在且為塊特殊文件則為真
          另外,Linux還提供了與(“!”)、或(“-o)、非(“-a”)三個(gè)邏輯操作符用于將測(cè)試條件連接起來(lái),
          其優(yōu)先級(jí)為:“!”最高,“-a”次之,“-o”最低。
          同時(shí),bash也能完成簡(jiǎn)單的算術(shù)運(yùn)算,格式如下:
          $[expression]
          例如:var1=2
          var2=$[var1*10+1]
          則:var2的值為21。

          2.if條件語(yǔ)句
          if [ -x /sbin/quotaon ]; then
          echo "Turning on Quota for root filesystem"
          /sbin/quotaon /
          elif [ -x /sbin/quotaon ]; then
          /usr/bin/bash
          else
          echo "ok"
          fi

          3.for 循環(huán)
          #!/bin/sh
          WORD="a b c d e f g h i j l m n o p q r s t u v w x y z"
          for i in $WORD ; do
          echo $i
          done

          #!/bin/sh
          FILES=`ls /txt/*.txt`
          for txt in $FILES ; do
          doc=`echo $txt | sed "s/.txt/.doc/"`
          mv $txt $doc
          done

          4.while和until 循環(huán)
          #!/bin/sh
          while [ -f /var/run/ppp0.pid ] ; do
          killall pppd
          done

          #!/bin/sh
          until [ -f /var/run/ppp0.pid ] ; do
          sleep 1
          done

          Shell還提供了true和false兩條命令用于建立無(wú)限循環(huán)結(jié)構(gòu)的需要,
          它們的返回狀態(tài)分別是總為0或總為非0

          5.case 條件選擇
          #!/bin/sh
          case $1 in
          start | begin)
          echo "start something"
          ;;
          stop | end)
          echo "stop something"
          ;;
          *)
          echo "Ignorant"
          ;;
          esac
          case表達(dá)式中也可以使用shell的通配符(“*”、“?”、“[ ]”)。

          6.無(wú)條件控制語(yǔ)句break和continue
          break 用于立即終止當(dāng)前循環(huán)的執(zhí)行,而contiune用于不執(zhí)行循環(huán)中后面的語(yǔ)句
          而立即開(kāi)始下一個(gè)循環(huán)的執(zhí)行。這兩個(gè)語(yǔ)句只有放在do和done之間才有效。

          7.函數(shù)定義
          在shell中還可以定義函數(shù)。函數(shù)實(shí)際上也是由若干條shell命令組成的,
          因此它與shell程序形式上是相似的,不同的是它不是一個(gè)單獨(dú)的進(jìn)程,
          而是shell程序的一部分。函數(shù)定義的基本格式為:
          functionname
          {
          若干命令行
          }
          調(diào)用函數(shù)的格式為:
          functionname param1 param2 ……
          shell函數(shù)可以完成某些例行的工作,而且還可以有自己的退出狀態(tài),
          因此函數(shù)也可以作為if、while等控制結(jié)構(gòu)的條件。
          在函數(shù)定義時(shí)不用帶參數(shù)說(shuō)明,但在調(diào)用函數(shù)時(shí)可以帶有參數(shù),此時(shí)
          shell將把這些參數(shù)分別賦予相應(yīng)的位置參數(shù)$1、$2、...及$*。

          8.命令分組
          在shell中有兩種命令分組的方法:“()”和“{}”,前者當(dāng)shell執(zhí)行()
          中的命令時(shí)將再創(chuàng)建一個(gè)新的子進(jìn)程,然后這個(gè)子進(jìn)程去執(zhí)行圓括弧中的命令。
          當(dāng)用戶在執(zhí)行某個(gè)命令時(shí)不想讓命令運(yùn)行時(shí)對(duì)狀態(tài)集合(如位置參數(shù)、環(huán)境變量、
          當(dāng)前工作目錄等)的改變影響到下面語(yǔ)句的執(zhí)行時(shí),就應(yīng)該把這些命令放在圓括
          弧中,這樣就能保證所有的改變只對(duì)子進(jìn)程產(chǎn)生影響,而父進(jìn)程不受任何干擾;
          {}用于將順序執(zhí)行的命令的輸出結(jié)果用于另一個(gè)命令的輸入(管道方式)。當(dāng)我們
          要真正使用圓括弧和花括弧時(shí)(如計(jì)算表達(dá)式的優(yōu)先級(jí)),則需要在其前面加上轉(zhuǎn)
          義符(\)以便讓shell知道它們不是用于命令執(zhí)行的控制所用。

          9.信號(hào)
          trap命令用于在shell程序中捕捉到信號(hào),之后可以有三種反應(yīng)方式:
          (1)執(zhí)行一段程序來(lái)處理這一信號(hào)
          (2)接受信號(hào)的默認(rèn)操作
          (3)忽視這一信號(hào)
          trap對(duì)上面三種方式提供了三種基本形式:
          第一種形式的trap命令在shell接收到signal list清單中數(shù)值相同的信號(hào)時(shí),
          將執(zhí)行雙引號(hào)中的命令串。
          trap 'commands' signal-list
          trap "commands" signal-list
          為了恢復(fù)信號(hào)的默認(rèn)操作,使用第二種形式的trap命令:
          trap signal-list
          第三種形式的trap命令允許忽視信號(hào):
          trap " " signal-list
          注意:
          (1)對(duì)信號(hào)11(段違例)不能捕捉,因?yàn)閟hell本身需要捕捉該信號(hào)去進(jìn)行內(nèi)存的轉(zhuǎn)儲(chǔ)。
          (2)在trap中可以定義對(duì)信號(hào)0的處理(實(shí)際上沒(méi)有這個(gè)信號(hào)),shell程序在其終止
          (如執(zhí)行exit語(yǔ)句)時(shí)發(fā)出該信號(hào)。
          (3)在捕捉到signal-list中指定的信號(hào)并執(zhí)行完相應(yīng)的命令之后,如果這些命令沒(méi)有將
          shell程序終止的話,shell程序?qū)⒗^續(xù)執(zhí)行收到信號(hào)時(shí)所執(zhí)行的命令后面的命令,這樣
          將很容易導(dǎo)致shell程序無(wú)法終止。
          另外,在trap語(yǔ)句中,單引號(hào)和雙引號(hào)是不同的,當(dāng)shell程序第一次碰到trap語(yǔ)句時(shí),
          將把commands中的命令掃描一遍。此時(shí)若commands是用單引號(hào)括起來(lái)的話,那么shell
          不會(huì)對(duì)commands中的變量和命令進(jìn)行替換,否則commands中的變量和命令將用當(dāng)時(shí)具體
          的值來(lái)替換。

          10. 運(yùn)行shell程序的方法
          執(zhí)行shell程序的方法有三種:
          (1)sh shell程序文件名
          格式為:
          bash shell 程序文件名
          這實(shí)際上是調(diào)用一個(gè)新的bash命令解釋程序,而把shell程序文件名作為參數(shù)傳遞給它。
          新啟動(dòng)的shell將去讀指定的文件,執(zhí)行文件中列出的命令,當(dāng)所有的命令都執(zhí)行完結(jié)束。
          該方法的優(yōu)點(diǎn)是可以利用shell調(diào)試功能。
          (2)sh<shell程序文件名
          格式為:
          bash<shell 程序文件名
          這種方式就是利用輸入重定向,使shell命令解釋程序的輸入取自指定的程序文件。
          (3)用chmod命令使shell程序成為可執(zhí)行的

          11. bash程序的調(diào)試
          bash -選擇項(xiàng) shell程序文件名
          幾個(gè)常用的選擇項(xiàng)是:
          -e:如果一個(gè)命令失敗就立即退出
          -n:讀入命令但是不執(zhí)行它們
          -u:置換時(shí)把未設(shè)置的變量看作出錯(cuò)
          -v:當(dāng)讀入shell輸入行時(shí)把它們顯示出來(lái)
          -x:執(zhí)行命令時(shí)把命令和它們的參數(shù)顯示出來(lái)
          上面的所有選項(xiàng)也可以在shell程序內(nèi)部用“set -選擇項(xiàng)”的形式引用,而“set +選擇項(xiàng)”則
          將禁止該選擇項(xiàng)起作用。如果只想對(duì)程序的某一部分使用某些選擇項(xiàng)時(shí),則可以將該部分用
          上面兩個(gè)語(yǔ)句包圍起來(lái)。
          1.未置變量退出和立即退出
          未置變量退出特性允許用戶對(duì)所有變量進(jìn)行檢查,如果引用了一個(gè)未賦值的變量就終止shell
          程序的執(zhí)行。shell通常允許未置變量的使用,在這種情況下,變量的值為空。如果設(shè)置了未
          置變量退出選擇項(xiàng),則一旦使用了未置變量就顯示錯(cuò)誤信息,并終止程序的運(yùn)行。未置變量退
          出選擇項(xiàng)為“-u”。
          當(dāng)shell運(yùn)行時(shí),若遇到不存在或不可執(zhí)行的命令、重定向失敗或命令非正常結(jié)束等情況時(shí),如
          果未經(jīng)重新定向,該出錯(cuò)信息會(huì)打印在終端屏幕上,而shell程序仍將繼續(xù)執(zhí)行。要想在錯(cuò)誤發(fā)
          生時(shí)迫使shell程序立即結(jié)束,可以使用“-e”選項(xiàng)將shell程序的執(zhí)行立即終止。
          2.shell程序的跟蹤
          調(diào)試shell程序的主要方法是利用shell命令解釋程序的“-v”或“-x”選項(xiàng)來(lái)跟蹤程序的執(zhí)行。“-v”
          選擇項(xiàng)使shell在執(zhí)行程序的過(guò)程中,把它讀入的每一個(gè)命令行都顯示出來(lái),而“-x”選擇項(xiàng)使shell
          在執(zhí)行程序的過(guò)程中把它執(zhí)行的每一個(gè)命令在行首用一個(gè)“+”加上命令名顯示出來(lái)。并把每一個(gè)變量
          和該變量所取的值也顯示出來(lái),因此,它們的主要區(qū)別在于:在執(zhí)行命令行之前無(wú)“-v”則打印出命
          令行的原始內(nèi)容,而有“-v”則打印出經(jīng)過(guò)替換后的命令行的內(nèi)容。
          除了使用shell的“-v”和“-x”選擇項(xiàng)以外,還可以在shell程序內(nèi)部采取一些輔助調(diào)試的措施。
          例如,可以在shell程序的一些關(guān)鍵地方使用echo命令把必要的信息顯示出來(lái),它的作用相當(dāng)于C語(yǔ)
          言中的printf語(yǔ)句,這樣就可以知道程序運(yùn)行到什么地方及程序目前的狀態(tài)。

          12. bash的內(nèi)部命令
          bash命令解釋程序包含了一些內(nèi)部命令。內(nèi)部命令在目錄列表時(shí)是看不見(jiàn)的,它們由shell本身提供。
          常用的內(nèi)部命令有:echo、eval、exec、export、readonly、read、shift、wait和點(diǎn)(.)。
          下面簡(jiǎn)單介紹其命令格式和功能。
          1.echo
          命令格式:echo arg
          功能:在屏幕上打印出由arg指定的字符串。
          2.eval
          命令格式:eval args
          功能:當(dāng)shell程序執(zhí)行到eval語(yǔ)句時(shí),shell讀入?yún)?shù)args,并將它們組合成一個(gè)新的命令,然后
          執(zhí)行。
          3.exec
          命令格式:exec 命令 命令參數(shù)
          功能:當(dāng)shell執(zhí)行到exec語(yǔ)句時(shí),不會(huì)去創(chuàng)建新的子進(jìn)程,而是轉(zhuǎn)去執(zhí)行指定的命令,
          當(dāng)指定的命令執(zhí)行完時(shí),該進(jìn)程,也就是最初的shell就終止了,所以shell程序中exec
          后面的語(yǔ)句將不再被執(zhí)行。
          4.export
          命令格式:export 變量名 或:export 變量名=變量值
          功能:shell可以用export把它的變量向下帶入子shell從而讓子進(jìn)程繼承父進(jìn)程中的環(huán)境變量。
          但子shell不能用export把它的變量向上帶入父shell。
          注意:不帶任何變量名的export語(yǔ)句將顯示出當(dāng)前所有的export變量。
          5.readonly
          命令格式:readonly 變量名
          功能:將一個(gè)用戶定義的shell變量標(biāo)識(shí)為不可變的。不帶任何參數(shù)的readonly命令將顯示出
          所有只讀的shell變量。
          6.read
          命令格式:
          read變量名表
          功能:從標(biāo)準(zhǔn)輸入設(shè)備讀入一行,分解成若干字,賦值給shell程序內(nèi)部定義的變量。
          7.shift語(yǔ)句
          功能:shift語(yǔ)句按如下方式重新命名所有的位置參數(shù)變量:$2成為$1,$3成為$2……在程序中
          每使用一次shift語(yǔ)句,都使所有的位置參數(shù)依次向左移動(dòng)一個(gè)位置,并使位置參數(shù)“$#”減一,
          直到減到0。
          8.wait
          功能:是shell等待在后臺(tái)啟動(dòng)的所有子進(jìn)程結(jié)束。Wait的返回值總是真。
          9.exit
          功能:退出shell程序。在exit之后可有選擇地指定一個(gè)數(shù)字作為返回狀態(tài)。
          10.“.”(點(diǎn))
          命令格式:. Shell程序文件名
          功能:使shell讀入指定的shell程序文件并依次執(zhí)行文件中的所有語(yǔ)句。

          13. 特殊參數(shù):
          1. $*: 代表所有參數(shù),其間隔為IFS內(nèi)定參數(shù)的第一個(gè)字元
          2. $@: 與*星號(hào)類(lèi)同。不同之處在於不參照IFS
          3. $#: 代表參數(shù)數(shù)量
          4. $?: 執(zhí)行上一個(gè)指令的返回值
          5. $-: 最近執(zhí)行的foreground pipeline的選項(xiàng)參數(shù)
          6. $$: 本身的Process ID
          7. $!: 執(zhí)行上一個(gè)背景指令的PID
          8. $_: 顯示出最後一個(gè)執(zhí)行的命令

          posted @ 2008-10-15 13:13 Xiaobo Sun 閱讀(168) | 評(píng)論 (0)編輯 收藏

          pkg-config學(xué)習(xí)


           首先說(shuō)下/etc/ld.so.conf:

          這個(gè)文件記錄了編譯時(shí)使用的動(dòng)態(tài)鏈接庫(kù)的路徑。
          默認(rèn)情況下,編譯器只會(huì)使用/lib和/usr/lib這兩個(gè)目錄下的庫(kù)文件
          如果你安裝了某些庫(kù),比如在安裝gtk+-2.4.13時(shí)它會(huì)需要glib-2.0 >= 2.4.0,辛苦的安裝好glib后
          沒(méi)有指定 —prefix=/usr 這樣glib庫(kù)就裝到了/usr/local下,而又沒(méi)有在/etc/ld.so.conf中添加/usr/local/lib這個(gè)搜索路徑,所以編譯gtk+-2.4.13就會(huì)出錯(cuò)了 對(duì)于這種情況有兩種方法解決:
          一:在編譯glib-2.4.x時(shí),指定安裝到/usr下,這樣庫(kù)文件就會(huì)放在/usr/lib中,gtk就不會(huì)找不到需要的庫(kù)文件了 對(duì)于安裝庫(kù)文件來(lái)說(shuō),這是個(gè)好辦法,這樣也不用設(shè)置PKG_CONFIG_PATH了

          二:將/usr/local/lib加入到/etc/ld.so.conf中,這樣安裝gtk時(shí)就會(huì)去搜索/usr/local/lib,同樣可以找到需要的庫(kù)
          將/usr/local/lib加入到/etc/ld.so.conf也是必須的,這樣以后安裝東東到local下,就不會(huì)出現(xiàn)這樣的問(wèn)題了。
          將自己可能存放庫(kù)文件的路徑都加入到/etc/ld.so.conf中是明智的選擇
          添加方法也極其簡(jiǎn)單,將庫(kù)文件的絕對(duì)路徑直接寫(xiě)進(jìn)去就OK了,一行一個(gè)。例如:
          /usr/X11R6/lib
          /usr/local/lib
          /opt/lib

          再來(lái)看看ldconfig :

          它是一個(gè)程序,通常它位于/sbin下,是root用戶使用的。具體作用及用法可以man ldconfig查到
          簡(jiǎn)單的說(shuō),它的作用就是將/etc/ld.so.conf列出的路徑下的庫(kù)文件 緩存到/etc/ld.so.cache 以供使用
          因此當(dāng)安裝完一些庫(kù)文件,(例如剛安裝好glib),或者修改ld.so.conf增加新的庫(kù)路徑后,需要運(yùn)行一下/sbin/ldconfig
          使所有的庫(kù)文件都被緩存到ld.so.cache中,如果沒(méi)做,即使庫(kù)文件明明就在/usr/lib下的,也是不會(huì)被使用的,結(jié)果編譯過(guò)程中報(bào)錯(cuò),缺少xxx庫(kù)
          我曾經(jīng)編譯KDE時(shí)就犯過(guò)這個(gè)錯(cuò)誤,(它需要每編譯好一個(gè)東東,都要運(yùn)行一遍),所以切記改動(dòng)庫(kù)文件后一定要運(yùn)行一下ldconfig,在任何目錄下運(yùn)行都可以。

          再來(lái)說(shuō)說(shuō) PKG_CONFIG_PATH這個(gè)變量吧:

          經(jīng)常在論壇上看到有人問(wèn)”為什么我已經(jīng)安裝了glib-2.4.x,但是編譯gtk+-2.4.x 還是提示glib版本太低阿?
          為什么我安裝了glib-2.4.x,還是提示找不到阿?。。。。。。”都是這個(gè)變量搞的鬼。
          先說(shuō)說(shuō)它是哪冒出來(lái)的,當(dāng)安裝了pkgconfig-x.x.x這個(gè)包后,就多出了pkg-config,它就是需要PKG_CONFIG_PATH的東東
          pkgconfig-x.x.x又是做什么的? 來(lái)看一段說(shuō)明:

          The pkgconfig package contains tools for passing the include path and/or library paths to build tools during the make file execution.

          pkg-config is a function that returns meta information for the specified library.

          The default setting for PKG_CONFIG_PATH is /usr/lib/pkgconfig because of the prefix we use to install pkgconfig. You may add to PKG_CONFIG_PATH by exporting additional paths on your system where pkgconfig files are installed. Note that PKG_CONFIG_PATH is only needed when compiling packages, not during run-time.

          其實(shí)pkg-config就是向configure程序提供系統(tǒng)信息的程序,比如軟件的版本啦,庫(kù)的版本啦,庫(kù)的路徑啦,等等
          這些信息只是在編譯其間使用。你可以 ls /usr/lib/pkgconfig 下,會(huì)看到許多的*.pc,用文本編輯器打開(kāi)
          會(huì)發(fā)現(xiàn)類(lèi)似下面的信息:

          prefix=/usr
          exec_prefix=${prefix}
          libdir=${exec_prefix}/lib
          includedir=${prefix}/include

          glib_genmarshal=glib-genmarshal
          gobject_query=gobject-query
          glib_mkenums=glib-mkenums

          Name: GLib
          Description: C Utility Library
          Version: 2.4.7
          Libs: -L${libdir} -lglib-2.0
          Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include

          明白了吧,configure就是靠這些信息判斷你的軟件版本是否符合要求。并且得到這些東東所在的位置,要不去哪里找呀。
          不用我說(shuō)你也知道為什么會(huì)出現(xiàn)上面那些問(wèn)題了吧。

          解決的辦法很簡(jiǎn)單,設(shè)定正確的PKG_CONFIG_PATH,假如將glib-2.x.x裝到了/usr/local/下,那么glib-2.0.pc就會(huì)在
          /usr/local/lib/pkgconfig下,將這個(gè)路徑添加到PKG_CONFIG_PATH下就可以啦。并且確保configure找到的是正確的
          glib-2.0.pc,就是將其他的lib/pkgconfig目錄glib-2.0.pc干掉就是啦。(如果有的話 ^-^)
          設(shè)定好后可以加入到~/.bashrc中,例如:
          PKG_CONFIG_PATH=/opt/kde-3.3.0/lib/pkgconfig:/usr/lib/pkgconfig:/usr/local/pkgconfig:
          /usr/X11R6/lib/pkgconfig
          [root@NEWLFS ~]#echo $PKG_CONFIG_PATH
          /opt/kde-3.3.0/lib/pkgconfig:/usr/lib/pkgconfig:/usr/local/pkgconfig:/usr/X11R6/lib/pkgconfig

          從上面可以看出,安裝庫(kù)文件時(shí),指定安裝到/usr,是很有好處的,無(wú)論是/etc/ld.so.conf還是PKG_CONFIG_PATH
          默認(rèn)都會(huì)去搜索/usr/lib的,可以省下許多麻煩,不過(guò)從源碼包管理上來(lái)說(shuō),都裝在/usr下
          管理是個(gè)問(wèn)題,不如裝在/usr/local下方便管理
          其實(shí)只要設(shè)置好ld.so.conf,PKG_CONFIG_PATH路徑后,就OK啦

          posted @ 2008-10-15 12:12 Xiaobo Sun 閱讀(3335) | 評(píng)論 (1)編輯 收藏

          wc - print newline, word, and byte counts for each file

          wc

          posted @ 2008-10-09 16:11 Xiaobo Sun 閱讀(306) | 評(píng)論 (0)編輯 收藏

          refresh >tail -f /var/log/messages

           refresh  tail -f /var/log/messages

          posted @ 2008-10-09 16:08 Xiaobo Sun 閱讀(283) | 評(píng)論 (0)編輯 收藏

          tar -xvf foo.tar, tar -xzvf foo.tar.gz

          tar -xvf foo.tar, tar -xzvf foo.tar.gz

          posted @ 2008-10-09 16:07 Xiaobo Sun 閱讀(388) | 評(píng)論 (0)編輯 收藏

          ps -aux | grep "lct*"

          ps -aux | grep "lct*"

          posted @ 2008-10-09 16:07 Xiaobo Sun 閱讀(204) | 評(píng)論 (0)編輯 收藏

          umlenkung >> , 2>

          umlenkung >> , 2>

          posted @ 2008-10-09 16:06 Xiaobo Sun 閱讀(177) | 評(píng)論 (0)編輯 收藏

          linux kernel version >uname -r

          linux kernel  version
           uname -r

          posted @ 2008-10-09 16:04 Xiaobo Sun 閱讀(288) | 評(píng)論 (0)編輯 收藏

          Dir size >du -k (kilo byte)

          Dir size      du -k (kilo byte)

          posted @ 2008-10-09 16:03 Xiaobo Sun 閱讀(193) | 評(píng)論 (0)編輯 收藏

          cd

          cd ~ : go to your home directory
          cd
          - : go to the last directory you were in
          cd
          .. : go up a directory

          posted @ 2008-10-09 15:28 Xiaobo Sun 閱讀(215) | 評(píng)論 (0)編輯 收藏

          Makefile example

          #libxml2 and glibmm are not neccessary to compile the main.cpp
          #macro
          libxml2:=../../libxml2
          libxml++:=..
          glibmm:=../../glibmm
          #adds include directives
          CC:=g++
          CCINCLUDE:= -I$(libxml++)/include/libxml++-2.6 -I$(libxml++)/lib/libxml++-2.6/include "
                  -I$(libxml2)/include -I$(glibmm)/include
          #linking
          LD:=g++
          LDSTDLIBS:= -L$(libxml++)/lib -L$(libxml2)/lib -L$(glibmm)/lib
          LDLIBS:= -lxml++-2.6
          LDLIBFLAGS:= -shared $(LDLIBS) $(LDSTDLIBS)
          LDEXEFLAGS:= $(LDSTDLIBS) $(LDLIBS)
          #extending library path
          #export VAR:=... means make it effective in the subprocess(Makefile)
          #export LD_LIBRARY_PATH:=... doesn't work because it's only effective in the subprocesses, not parentprocess(shell)
          #therefore the LD_RUN_PATH which allocates dynamic libs to the exe file must be set and export to take effect in the ld cmd
          LD_LIBRARY_PATH:=$(libxml++)/lib:$(LD_LIBRARY_PATH)
          export LD_RUN_PATH:=$(LD_LIBRARY_PATH)
          #list of source files for building the target
          SRC:= main.cpp
          OBJ:=$(patsubst %.cpp,%.o,$(filter %.cpp,$(SRC)))
          #targets
          # $^ everyone behinds the : , and $< first one behinds the :
          # $(OBJ): %.o: %.cpp is another common implicit rule is for the construction of .o files out of .cpp
          .PHONY: all clean
          all: $(OBJ)
                  $(LD) $(LDEXEFLAGS) $^ -o $@

          $(OBJ): %.o: %.cpp
                  $(CC) $(CCINCLUDE) -c $< -o $@
          clean:
                  rm -f $(OBJ) all *~ \.*.swp

          posted @ 2008-10-09 13:55 Xiaobo Sun 閱讀(990) | 評(píng)論 (3)編輯 收藏

          umask

          1) 文件的最大權(quán)限r(nóng)wx rwx rwx (777)
          2 ) u m a s k值為0 2 2 - - - -w- -w-
          3) 目錄權(quán)限r(nóng)wx r-x r-x (755) 這就是目錄創(chuàng)建缺省權(quán)限
          4) 文件權(quán)限r(nóng)w- r-- r-- (644) 這就是文件創(chuàng)建缺省權(quán)限

          posted @ 2008-08-08 11:41 Xiaobo Sun 閱讀(169) | 評(píng)論 (0)編輯 收藏

          TCP: SYN ACK FIN RST PSH URG

          三次握手Three-way Handshake

          一個(gè)虛擬連接的建立是通過(guò)三次握手來(lái)實(shí)現(xiàn)的

          1. (B) --> [SYN] --> (A)

          假如服務(wù)器A和客戶機(jī)B通訊. 當(dāng)A要和B通信時(shí),B首先向A發(fā)一個(gè)SYN (Synchronize) 標(biāo)記的包,告訴A請(qǐng)求建立連接.

          注意: 一個(gè) SYN包就是僅SYN標(biāo)記設(shè)為1的TCP包(參見(jiàn)TCP包頭Resources). 認(rèn)識(shí)到這點(diǎn)很重要,只有當(dāng)A受到B發(fā)來(lái)的SYN包,才可建立連接,除此之外別無(wú)他法。因此,如果你的防火墻丟棄所有的發(fā)往外網(wǎng)接口的SYN包,那么你將不 能讓外部任何主機(jī)主動(dòng)建立連接。

          2. (B) <-- [SYN/ACK] <--(A)

          接著,A收到后會(huì)發(fā)一個(gè)對(duì)SYN包的確認(rèn)包(SYN/ACK)回去,表示對(duì)第一個(gè)SYN包的確認(rèn),并繼續(xù)握手操作.

          注意: SYN/ACK包是僅SYN 和 ACK 標(biāo)記為1的包.

          3. (B) --> [ACK] --> (A)

          B收到SYN/ACK 包,B發(fā)一個(gè)確認(rèn)包(ACK),通知A連接已建立。至此,三次握手完成,一個(gè)TCP連接完成

          Note: ACK包就是僅ACK 標(biāo)記設(shè)為1的TCP包. 需要注意的是當(dāng)三此握手完成、連接建立以后,TCP連接的每個(gè)包都會(huì)設(shè)置ACK位

          這就是為何連接跟蹤很重要的原因了. 沒(méi)有連接跟蹤,防火墻將無(wú)法判斷收到的ACK包是否屬于一個(gè)已經(jīng)建立的連接.一般的包過(guò)濾(Ipchains)收到ACK包時(shí),會(huì)讓它通過(guò)(這絕對(duì)不是個(gè) 好主意). 而當(dāng)狀態(tài)型防火墻收到此種包時(shí),它會(huì)先在連接表中查找是否屬于哪個(gè)已建連接,否則丟棄該包

          四次握手Four-way Handshake

          四次握手用來(lái)關(guān)閉已建立的TCP連接

          1. (B) --> ACK/FIN --> (A)

          2. (B) <-- ACK <-- (A)

          3. (B) <-- ACK/FIN <-- (A)

          4. (B) --> ACK --> (A)

          注意: 由于TCP連接是雙向連接, 因此關(guān)閉連接需要在兩個(gè)方向上做。ACK/FIN 包(ACK 和FIN 標(biāo)記設(shè)為1)通常被認(rèn)為是FIN(終結(jié))包.然而, 由于連接還沒(méi)有關(guān)閉, FIN包總是打上ACK標(biāo)記. 沒(méi)有ACK標(biāo)記而僅有FIN標(biāo)記的包不是合法的包,并且通常被認(rèn)為是惡意的

          連接復(fù)位Resetting a connection

          四次握手不是關(guān)閉TCP連接的唯一方法. 有時(shí),如果主機(jī)需要盡快關(guān)閉連接(或連接超時(shí),端口或主機(jī)不可達(dá)),RST (Reset)包將被發(fā)送. 注意在,由于RST包不是TCP連接中的必須部分, 可以只發(fā)送RST包(即不帶ACK標(biāo)記). 但在正常的TCP連接中RST包可以帶ACK確認(rèn)標(biāo)記

          請(qǐng)注意RST包是可以不要收到方確認(rèn)的?

          無(wú)效的TCP標(biāo)記Invalid TCP Flags

          到目前為止,你已經(jīng)看到了 SYN, ACK, FIN, 和RST 標(biāo)記. 另外,還有PSH (Push) 和URG (Urgent)標(biāo)記.

          最常見(jiàn)的非法組合是SYN/FIN 包. 注意:由于 SYN包是用來(lái)初始化連接的, 它不可能和 FIN和RST標(biāo)記一起出現(xiàn). 這也是一個(gè)惡意攻擊.

          由于現(xiàn)在大多數(shù)防火墻已知 SYN/FIN 包, 別的一些組合,例如SYN/FIN/PSH, SYN/FIN/RST, SYN/FIN/RST/PSH。很明顯,當(dāng)網(wǎng)絡(luò)中出現(xiàn)這種包時(shí),很你的網(wǎng)絡(luò)肯定受到攻擊了。

          別的已知的非法包有FIN (無(wú)ACK標(biāo)記)和"NULL"包。如同早先討論的,由于ACK/FIN包的出現(xiàn)是為了關(guān)閉一個(gè)TCP連接,那么正常的FIN包總是帶有 ACK 標(biāo)記。"NULL"包就是沒(méi)有任何TCP標(biāo)記的包(URG,ACK,PSH,RST,SYN,FIN都為0)。

          到目前為止,正常的網(wǎng)絡(luò)活動(dòng)下,TCP協(xié)議棧不可能產(chǎn)生帶有上面提到的任何一種標(biāo)記組合的TCP包。當(dāng)你發(fā)現(xiàn)這些不正常的包時(shí),肯定有人對(duì)你的網(wǎng)絡(luò)不懷好意。

          UDP (用戶數(shù)據(jù)包協(xié)議User Datagram Protocol)
          TCP是面向連接的,而UDP是非連接的協(xié)議。UDP沒(méi)有對(duì)接受進(jìn)行確認(rèn)的標(biāo)記和確認(rèn)機(jī)制。對(duì)丟包的處理是在應(yīng)用層來(lái)完成的。(or accidental arrival).

          此處需要重點(diǎn)注意的事情是:在正常情況下,當(dāng)UDP包到達(dá)一個(gè)關(guān)閉的端口時(shí),會(huì)返回一個(gè)UDP復(fù)位包。由于UDP是非面向連接的, 因此沒(méi)有任何確認(rèn)信息來(lái)確認(rèn)包是否正確到達(dá)目的地。因此如果你的防火墻丟棄UDP包,它會(huì)開(kāi)放所有的UDP端口(?)。

          由于Internet上正常情況下一些包將被丟棄,甚至某些發(fā)往已關(guān)閉端口(非防火墻的)的UDP包將不會(huì)到達(dá)目的,它們將返回一個(gè)復(fù)位UDP包。

          因?yàn)檫@個(gè)原因,UDP端口掃描總是不精確、不可靠的。

          看起來(lái)大UDP包的碎片是常見(jiàn)的DOS (Denial of Service)攻擊的常見(jiàn)形式 (這里有個(gè)DOS攻擊的例子,http://grc.com/dos/grcdos.htm ).

          ICMP (網(wǎng)間控制消息協(xié)議Internet Control Message Protocol)
          如同名字一樣, ICMP用來(lái)在主機(jī)/路由器之間傳遞控制信息的協(xié)議。 ICMP包可以包含診斷信息(ping, traceroute - 注意目前unix系統(tǒng)中的traceroute用UDP包而不是ICMP),錯(cuò)誤信息(網(wǎng)絡(luò)/主機(jī)/端口 不可達(dá) network/host/port unreachable), 信息(時(shí)間戳timestamp, 地址掩碼address mask request, etc.),或控制信息 (source quench, redirect, etc.) 。

          你可以在http://www.iana.org/assignments/icmp-parameters中找到ICMP包的類(lèi)型。

          盡管ICMP通常是無(wú)害的,還是有些類(lèi)型的ICMP信息需要丟棄。

          Redirect (5), Alternate Host Address (6), Router Advertisement (9) 能用來(lái)轉(zhuǎn)發(fā)通訊。

          Echo (8), Timestamp (13) and Address Mask Request (17) 能用來(lái)分別判斷主機(jī)是否起來(lái),本地時(shí)間 和地址掩碼。注意它們是和返回的信息類(lèi)別有關(guān)的。 它們自己本身是不能被利用的,但它們泄露出的信息對(duì)攻擊者是有用的。

          ICMP消息有時(shí)也被用來(lái)作為DOS攻擊的一部分(例如:洪水ping flood ping,死 ping ?呵呵,有趣 ping of death)?/p>

          包碎片注意A Note About Packet Fragmentation

          如果一個(gè)包的大小超過(guò)了TCP的最大段長(zhǎng)度MSS (Maximum Segment Size) 或MTU (Maximum Transmission Unit),能夠把此包發(fā)往目的的唯一方法是把此包分片。由于包分片是正常的,它可以被利用來(lái)做惡意的攻擊。

          因?yàn)榉制陌牡谝粋€(gè)分片包含一個(gè)包頭,若沒(méi)有包分片的重組功能,包過(guò)濾器不可能檢測(cè)附加的包分片。典型的攻擊Typical attacks involve in overlapping the packet data in which packet header is 典型的攻擊Typical attacks involve in overlapping the packet data in which packet header isnormal until is it overwritten with different destination IP (or port) thereby bypassing firewall rules。包分片能作為 DOS 攻擊的一部分,它可以crash older IP stacks 或漲死CPU連接能力。

          Netfilter/Iptables中的連接跟蹤代碼能自動(dòng)做分片重組。它仍有弱點(diǎn),可能受到飽和連接攻擊,可以把CPU資源耗光。

          posted @ 2008-08-07 09:20 Xiaobo Sun 閱讀(9685) | 評(píng)論 (4)編輯 收藏

          gdb

          >gdb ./sysprocess
          (gdb)set args -id 0 -taskcfg ub900proc
          (gdb)r //run
          Starting program: ../sysprocess -id 0 -taskcfg ub900proc
          ..
          Program received signal SIGSEGV, Segmentation fault.
          (gdb)backtrace //打印當(dāng)前的函數(shù)調(diào)用棧的所有信息。
          (gdb)frame 7 //查看信息,n是一個(gè)從0開(kāi)始的整數(shù),是棧中的層編號(hào)
          (gdb)up
          (gdb)down
          (gdb)quit

          posted @ 2008-08-05 15:42 Xiaobo Sun 閱讀(179) | 評(píng)論 (0)編輯 收藏

          #find ./ -type f -name "*.swp"|xargs rm -rf #find . -name "*.cpp" -exec grep "SoapEvMessage" \; -print

           #find ... -exec rm {} \;
           #find ... | xargs rm -rf

          兩者都可以把find命令查找到的結(jié)果刪除,其區(qū)別簡(jiǎn)單的說(shuō)是前者是把find發(fā)現(xiàn)的結(jié)果一次性傳給exec選項(xiàng),這樣當(dāng)文件數(shù)量較多的時(shí)候,就 可能會(huì)出現(xiàn)“參數(shù)太多”之類(lèi)的錯(cuò)誤,相比較而言,后者就可以避免這個(gè)錯(cuò)誤,因?yàn)閤args命令會(huì)分批次的處理結(jié)果。這樣看來(lái),“find ... | xargs rm -rf”是更通用的方法,推薦使用!

          rm不接受標(biāo)準(zhǔn)輸入,所以不能用find / -name "tmpfile" |rm

          -exec   必須由一個(gè)   ;   結(jié)束,而因?yàn)橥ǔ?  shell   都會(huì)對(duì)   ;   進(jìn)行處理,所以用   \;   防止這種情況。  
            {}   可能需要寫(xiě)做   '{}',也是為了避免被   shell   過(guò)濾

          find ./ -type f -exec grep iceskysl {} /dev/null \;
          ./表示從當(dāng)前目錄找
          -type f,表示只找file,文件類(lèi)型的,目錄和其他字節(jié)啥的不要
          -exec 把find到的文件名作為參數(shù)傳遞給后面的命令行,代替{}的部分
          -exec后便跟的命令行,必須用“ \;”結(jié)束

          #find ./ -type f -name "*.cpp"|xargs grep "test" -n
          #find . -name "*cpp" -exec grep "test" {} \; -print

          posted @ 2008-07-29 14:27 Xiaobo Sun 閱讀(3061) | 評(píng)論 (0)編輯 收藏

          Vim cut, copy and paste

          posted @ 2008-07-11 08:53 Xiaobo Sun 閱讀(366) | 評(píng)論 (0)編輯 收藏

          GridLayout

          Each SWT widget has a (possible) containing area as known as the cell.

          horizontalAlignment, verticalAlignment is used to set the widget position
          grabExcessHorizontalSpace, grabExcessVerticalSpace is used to set the cell.

          posted @ 2008-06-26 11:22 Xiaobo Sun 閱讀(273) | 評(píng)論 (0)編輯 收藏

          View the Listening port under linux: #netstat -nl | grep 3141

          netstat -nl | grep 3141

          =========================

          nmap -sT -O localhost

          cat /etc/services | grep 3141

          netstat -anp | grep 3141

          lsof -i | grep 3141

          posted @ 2008-06-18 08:48 Xiaobo Sun 閱讀(334) | 評(píng)論 (0)編輯 收藏

          LD_LIBRARY_PATH

          vim /etc/ld.so.conf
          ====================
          LD_LIBRARY_PATH: defines the path of dynamic libraries used at the run time
          LD_RUN_PATH: at compile time tells the exe file what is path of dynamic libraries used at the run time
          ======================
          ldd exe // show the used dynamic libs

          posted @ 2008-06-16 13:21 Xiaobo Sun 閱讀(413) | 評(píng)論 (0)編輯 收藏

          Linux cmd : #du -k, #uname -r,# >> 2> , #tail -f, #tar -xzvf

           Dir size
           du -k (kilo byte)
           linux kernel  version
           uname -r
           umlenkung
           >> , 2>
             ps -aux | grep "lct*"
             tar -xvf foo.tar, tar -xzvf foo.tar
           refresh  tail -f /var/log/messages


          posted @ 2008-06-15 13:46 Xiaobo Sun 閱讀(314) | 評(píng)論 (0)編輯 收藏

          mysql.exe -u root -p

          mysql.exe -u root -p

          posted @ 2008-06-08 12:19 Xiaobo Sun 閱讀(333) | 評(píng)論 (0)編輯 收藏

          JSP Scope

          There are 4 scopes application, session, request and page in the order of thier significance. 
           
          Application represent the ServletContext. The scope is accesible throught out the application. 
           
          session represents HTTPSession object. This is valid till the user requests the application. 
           
          Request represent the HTTPServletRequest and valdi to a particular request. A request may span a single JSP page or multiple depending upon teh situations. 
           
          Page is the least valid scope. It is valid to the particular JSP page only This is some thing like private variable 

          posted @ 2008-06-03 16:01 Xiaobo Sun 閱讀(372) | 評(píng)論 (0)編輯 收藏

          wget : #wget -r -np -nd http://example.com/packages/

          1. $ wget -r -np -nd http://example.com/packages/

            這條命令可以下載 http://example.com 網(wǎng)站上 packages 目錄中的所有文件。其中,-np 的作用是不遍歷父目錄,-nd 表示不在本機(jī)重新創(chuàng)建目錄結(jié)構(gòu)。

          2. $ wget -r -np -nd --accept=iso http://example.com/centos-5/i386/

            與上一條命令相似,但多加了一個(gè) --accept=iso 選項(xiàng),這指示 wget 僅下載 i386 目錄中所有擴(kuò)展名為 iso 的文件。你也可以指定多個(gè)擴(kuò)展名,只需用逗號(hào)分隔即可。

          3. $ wget -i filename.txt

            此命令常用于批量下載的情形,把所有需要下載文件的地址放到 filename.txt 中,然后 wget 就會(huì)自動(dòng)為你下載所有文件了。

          4. $ wget -c http://example.com/really-big-file.iso

            這里所指定的 -c 選項(xiàng)的作用為斷點(diǎn)續(xù)傳。

          5. $ wget -m -k (-H) http://www.example.com/

            該命令可用來(lái)鏡像一個(gè)網(wǎng)站,wget 將對(duì)鏈接進(jìn)行轉(zhuǎn)換。如果網(wǎng)站中的圖像是放在另外的站點(diǎn),那么可以使用 -H 選項(xiàng)。

          posted @ 2008-06-02 17:28 Xiaobo Sun 閱讀(680) | 評(píng)論 (0)編輯 收藏

          Java Stream

          stream應(yīng)該是水龍頭里的水資源,
          InputStream:是一個(gè)出水龍頭(把水封裝在里頭)的一個(gè)實(shí)物對(duì)象,該對(duì)象的read方法呢,就想成這
          個(gè)"出水龍頭"這一機(jī)制對(duì)象的開(kāi)關(guān)鈕,你read或openStream(其他對(duì)象包容InputStream對(duì)象的對(duì)象方法)
          一下呢,就等于打開(kāi)了出水龍頭的按鈕,水就出來(lái)了,里頭封裝的水是什么性質(zhì)的呢,
          你就用相應(yīng)的容器來(lái)裝,如string或byte[].....
          OutputStream:你就在InputStream基礎(chǔ)上反著想就ok了
          =====================================================================================
          當(dāng)然,我們可以在Inputstream和OutputStream數(shù)據(jù)源的基礎(chǔ)上,從實(shí)際需要觸發(fā),
                來(lái)重新封裝出不同性能機(jī)制的輸入、輸出流了,java.io包中提供了很豐富的輸入、輸出流對(duì)象,如:
               基于字節(jié)流的stream:
                DataOutputStream----DataInputStream:
                   FileOutputStream-----FileInputStream:
          File->inputstream->...
          ...->outputstream->File

                  .............等,可以用InputStream和OutputStream從JDK文檔查閱
               基于字符流的stream(典型的以write 和reader來(lái)標(biāo)識(shí)的):
                FileWriter---FileReader:
                   StringWriter---StringReader:
                    .........等,你自己可以用Writer和Reader從JDK文檔里頭查看說(shuō)明
          ======================================================================================

          InputStreamReader r = new InputStreamReader(System. in ); // InputStream from console
          BufferedReader in = new BufferedReader ( r );
          String line ;
          while (( line = in . readLine ()) != null) {
            System. out . println ( "> "+line );
          }

          FileReader r = new FileReader ( args [0]); // InputStream from file
          BufferedReader in = new BufferedReader ( r );
          String line ;
          while (( line = in . readLine ()) != null) {
            System. out . println ( "> "+line );
          }

          FileWriter w = new FileWriter ( args [0]); //OutputStream to file
          BufferedWriter bw = new BufferedWriter (w);
          PrintWriter out = new PrintWriter (bw);
          out . println ( "dies" );
          out . println ( " ... ist ein Log!" );
          out . println ( "Ciao!" );
          out . close (); // schliessen nicht vergessen !
          ===================================================================
          FileInputStream是InputStream的子類(lèi),由名稱(chēng)上就可以知道, FileInputStream主要就是從指定的File中讀取資料至目的地。

          FileOutputStream是OutputStream的子類(lèi),顧名思義,F(xiàn)ileOutputStream主要就是從來(lái)源地寫(xiě)入資料至指定的File中。

          標(biāo)準(zhǔn)輸入輸出串流物件在程式一開(kāi)始就會(huì)開(kāi)啟,但只有當(dāng)您建立一個(gè)FileInputStream或FileOutputStream的實(shí)例時(shí),實(shí)際的串流才會(huì)開(kāi)啟,而不使用串流時(shí),也必須自行關(guān)閉串流,以釋放與串流相依的系統(tǒng)資源。

          下面這個(gè)程式可以復(fù)制檔案,程式先從來(lái)源檔案讀取資料至一個(gè)位元緩沖區(qū)中,然后再將位元陣列的資料寫(xiě)入目的檔案:

          • FileStreamDemo.java
          package onlyfun.caterpillar;

          import java.io.*;

          public class FileStreamDemo {
          public static void main(String[] args) {
          try {
          byte[] buffer = new byte[1024];

          FileInputStream fileInputStream =
          new FileInputStream(new File(args[0]));
          FileOutputStream fileOutputStream =
          new FileOutputStream(new File(args[1]));

          System.out.println("復(fù)制檔案:" +
          fileInputStream.available() + "位元組");
          while(true) { // 從來(lái)源檔案讀取資料至緩沖區(qū)
          if(fileInputStream.available() < 1024) {
          int remain;
          while((remain = fileInputStream.read())
          != -1) {
          fileOutputStream.write(remain);
          }
          break;
          }
          else {
          fileInputStream.read(buffer);
          // 將陣列資料寫(xiě)入目的檔案
          fileOutputStream.write(buffer);
          }
          }

          // 關(guān)閉串流
          fileInputStream.close();
          fileOutputStream.close();

          System.out.println("復(fù)制完成");
          }
          catch(ArrayIndexOutOfBoundsException e) {
          System.out.println(
          "using: java FileStreamDemo src des");
          e.printStackTrace();
          }
          catch(IOException e) {
          e.printStackTrace();
          }
          }
          }

          這個(gè)程式示范了兩個(gè) read() 方法,一個(gè)可以讀入指定長(zhǎng)度的資料至陣列,一個(gè)一次可以讀入一個(gè)位元組,每次讀取之后,讀取的指標(biāo)都會(huì)往前進(jìn),您使用available()方法獲得還有多少位元組可以讀取;除了使用File來(lái)建立FileInputStream、FileOutputStream的實(shí)例之外,您也可以直接使用字串指定路徑來(lái)建立。

          不使用串流時(shí),記得使用close()方法自行關(guān)閉串流,以釋放與串流相依的系統(tǒng)資源。

          posted @ 2008-05-19 15:21 Xiaobo Sun 閱讀(958) | 評(píng)論 (1)編輯 收藏

          VM shared folder

          Shared Folders是Vmware4 的一個(gè)新功能,更加方便了在Host,Guest操作系統(tǒng)間共享文件。它是把Host機(jī)器上的一個(gè)目錄共享給Guest機(jī)器使用。點(diǎn)擊Edit- >;Virtual machine settigns->;Option->;Shared Folders->;Add,選定要共享的文件夾并給這個(gè)文件夾命名,下一步。選定“Enable this share”,還有只讀和重啟后失效的選項(xiàng),根據(jù)需要選擇。
          確定以后,vmware會(huì)把這個(gè)文件夾自動(dòng)mount到/mnt/hgfs目錄下

          posted @ 2008-05-18 10:10 Xiaobo Sun 閱讀(584) | 評(píng)論 (0)編輯 收藏

          虛擬語(yǔ)氣

          1. 德語(yǔ)
          1)非現(xiàn)實(shí)
          Wenn das Wetter doch schoen waere!
          Wenn wir jetzt Ferien haetten!

          Wenn ich Zeit haette, kaeme ich gerne zur einer Party.
          Wenn ich Zeit haette, wuerde ich gerne zur einer Party kommen.
          2) 客氣
          Haettest du Lust zu einer Party?
          Koennten Sie...
          Duerfte ich...

          2.英語(yǔ)
          1)條件從句:If I were you, I would(should,could,might) study hard.
          2) wish賓語(yǔ):I wish I were as young as you.
          3) suggest, advise, ask, decide..賓語(yǔ):I advise that we (should) stay and wait here.

          posted @ 2008-05-13 14:10 Xiaobo Sun 閱讀(179) | 評(píng)論 (0)編輯 收藏

          <2008年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(3)

          隨筆分類(lèi)

          隨筆檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 汉沽区| 蓬安县| 通河县| 临武县| 仁化县| 乐昌市| 兴和县| 渭源县| 准格尔旗| 界首市| 平果县| 革吉县| 冀州市| 巴塘县| 潮州市| 福安市| 临汾市| 景宁| 那曲县| 洪湖市| 兴安盟| 建水县| 凭祥市| 英山县| 建平县| 阿克| 赤峰市| 碌曲县| 乌兰察布市| 忻城县| 靖宇县| 三亚市| 车致| 靖安县| 乡城县| 沧州市| 涡阳县| 湖口县| 永康市| 赣州市| 于都县|