Look into it ~

          present
          隨筆 - 32, 文章 - 0, 評論 - 3, 引用 - 0
          數據加載中……

          2008年9月24日

          android軟件

              只有注冊用戶登錄后才能閱讀該文。閱讀全文

          posted @ 2008-11-20 16:24 LukeW 閱讀(36) | 評論 (0)編輯 收藏

          linux設備模型

          Linux 2.6內核的一個重要特色是提供了統一的內核設備模型。隨著技術的不斷進步,系統的拓撲結構越來越復雜,對智能電源管理、熱插拔以及plug and play的支持要求也越來越高,2.4內核已經難以滿足這些需求。為適應這種形勢的需要,2.6內核開發了全新的設備模型。
          1. Sysfs文件系統
          Sysfs文件系統是一個類似于proc文件系統的特殊文件系統,用于將系統中的設備組織成層次結構,并向用戶模式程序提供詳細的內核數據結構信息。其頂層目錄主要有:
          Block目錄:包含所有的塊設備
          Devices目錄:包含系統所有的設備,并根據設備掛接的總線類型組織成層次結構
          Bus目錄:包含系統中所有的總線類型
          Drivers目錄:包括內核中所有已注冊的設備驅動程序
          Class目錄:系統中的設備類型(如網卡設備,聲卡設備等)
          2. 內核對象機制關鍵數據結構
          2.1 kobject內核對象
          Kobject 是Linux 2.6引入的新的設備管理機制,在內核中由struct kobject表示。通過這個數據結構使所有設備在底層都具有統一的接口,kobject提供基本的對象管理,是構成Linux 2.6設備模型的核心結構,它與sysfs文件系統緊密關聯,每個在內核中注冊的kobject對象都對應于sysfs文件系統中的一個目錄。
          Kobject結構定義為:
          struct kobject {
          char * k_name;    // 指向設備名稱的指針
          char name[KOBJ_NAME_LEN];   // 設備名稱
          struct kref kref;    // 對象引用計數
          struct list_head entry;   // 掛接到所在kset中去的單元
          struct kobject * parent; // 指向父對象的指針
          struct kset * kset;    // 所屬kset的指針
          struct kobj_type * ktype;   // 指向其對象類型描述符的指針
          struct dentry * dentry; // sysfs文件系統中與該對象對應的文件節點路徑指針
          };

          其中的kref域表示該對象引用的計數,內核通過kref實現對象引用計數管理,內核提供兩個函數kobject_get()、kobject_put()分別用于增加和減少引用計數,當引用計數為0時,所有該對象使用的資源將被釋放。
          Ktype 域是一個指向kobj_type結構的指針,表示該對象的類型。Kobj_type數據結構包含三個域:一個release方法用于釋放kobject占 用的資源;一個sysfs_ops指針指向sysfs操作表和一個sysfs文件系統缺省屬性列表。Sysfs操作表包括兩個函數store()和 show()。當用戶態讀取屬性時,show()函數被調用,該函數編碼指定屬性值存入buffer中返回給用戶態;而store()函數用于存儲用戶態 傳入的屬性值。
          2.2 kset內核對象集合
          Kobject通常通過kset組織成層次化的結構,kset是具有相同類型的kobject的集合,在內核中用kset數據結構表示,定義為:
          struct kset {
          struct subsystem * subsys;   // 所在的subsystem的指針
          struct kobj_type * ktype;   // 指向該kset對象類型描述符的指針
          struct list_head list;      // 用于連接該kset中所有kobject的鏈表頭
          struct kobject kobj;    // 嵌入的kobject
          struct kset_hotplug_ops * hotplug_ops; // 指向熱插拔操作表的指針
          };

          包 含在kset中的所有kobject被組織成一個雙向循環鏈表,list域正是該鏈表的頭。Ktype域指向一個kobj_type結構,被該 kset中的所有kobject共享,表示這些對象的類型。Kset數據結構還內嵌了一個kobject對象(由kobj域表示),所有屬于這個kset 的kobject對象的parent域均指向這個內嵌的對象。此外,kset還依賴于kobj維護引用計數:kset的引用計數實際上就是內嵌的 kobject對象的引用計數。
          2.3 subsystem內核對象子系統
          Subsystem是一系列kset的集合,描述系統中某一 類設備子系統,如block_subsys表示所有的塊設備,對應于sysfs文件系統中的block目錄。類似的,devices_subsys對應于 sysfs中的devices目錄,描述系統中所有的設備。Subsystem由struct subsystem數據結構描述,定義為:
          struct subsystem {
          struct kset kset;       // 內嵌的kset對象
          struct rw_semaphore rwsem; // 互斥訪問信號量
          };

          每 個kset必須屬于某個subsystem,通過設置kset結構中的subsys域指向指定的subsystem可以將一個kset加入到該 subsystem。所有掛接到同一subsystem的kset共享同一個rwsem信號量,用于同步訪問kset中的鏈表。

          3. 內核對象機制主要相關函數
          針對內核對象不同層次的數據結構,linux 2.6內核定義了一系列操作函數,定義于lib/kobject.c文件中。
          3.1 kobject相關函數
          void kobject_init(struct kobject * kobj);// kobject初始化函數。設置kobject引用計數為1,entry域指向自身,其所屬kset引用計數加1

          int kobject_set_name(struct kobject *kobj, const char *format, );// 設置指定kobject的名稱。

          void kobject_cleanup(struct kobject * kobj);
          void kobject_release(struct kref *kref);// kobject清除函數。當其引用計數為0時,釋放對象占用的資源。

          struct kobject *kobject_get(struct kobject *kobj);// 將kobj 對象的引用計數加1,同時返回該對象的指針。

          void kobject_put(struct kobject * kobj);// 將kobj對象的引用計數減1,如果引用計數降為0,則調用kobject_release()釋放該kobject對象。

          int kobject_add(struct kobject * kobj);// 將kobj對象加入Linux設備層次。掛接該kobject對象到kset的list鏈中,增加父目錄各級kobject的引用計數,在其parent指向的目錄下創建文件節點,并啟動該類型內核對象的hotplug函數。

          int kobject_register(struct kobject * kobj);// kobject注冊函數。通過調用kobject_init()初始化kobj,再調用kobject_add()完成該內核對象的注冊。

          void kobject_del(struct kobject * kobj);// 從Linux設備層次(hierarchy)中刪除kobj對象。

          void kobject_unregister(struct kobject * kobj);// kobject注銷函數。與kobject_register()相反,它首先調用kobject_del從設備層次中刪除該對象,再調用kobject_put()減少該對象的引用計數,如果引用計數降為0,則釋放該kobject對象。

          3.2 kset相關函數
          與kobject 相似,kset_init()完成指定kset的初始化,kset_get()和kset_put()分別增加和減少kset對象的引用計數。 Kset_add()和kset_del()函數分別實現將指定keset對象加入設備層次和從其中刪除;kset_register()函數完成 kset的注冊而kset_unregister()函數則完成kset的注銷。
          3.3 subsystem相關函數
          subsystem有一組完成類似的函數,分別是:
          void subsystem_init(struct subsystem *subsys);
          int subsystem_register(struct subsystem *subsys);
          void subsystem_unregister(struct subsystem *subsys);
          struct subsystem *subsys_get(struct subsystem *subsys)
          void subsys_put(struct subsystem *subsys);

          4. 設備模型組件
          在上述內核對象機制的基礎上,Linux的設備模型建立在幾個關鍵組件的基礎上,下面我們詳細闡述這些組件。
          4.1 devices
          系統中的任一設備在設備模型中都由一個device對象描述,其對應的數據結構struct device定義為:
          struct device {
          struct list_head g_list;
          struct list_head node;
              
          struct list_head bus_list;
              
          struct list_head driver_list;
              
          struct list_head children;
              
          struct device *parent;
              
          struct kobject kobj;
              
          char bus_id[BUS_ID_SIZE];
              
          struct bus_type *bus;
              
          struct device_driver *driver;
              
          void *driver_data;
              
          /* Several fields omitted */
          };

          g_list 將該device對象掛接到全局設備鏈表中,所有的device對象都包含在devices_subsys中,并組織成層次結構。Node域將該對象掛接 到其兄弟對象的鏈表中,而bus_list則用于將連接到相同總線上的設備組織成鏈表,driver_list則將同一驅動程序管理的所有設備組織為鏈 表。此外,children域指向該device對象子對象鏈表頭,parent域則指向父對象。Device對象還內嵌一個kobject對象,用于引 用計數管理并通過它實現設備層次結構。Driver域指向管理該設備的驅動程序對象,而driver_data則是提供給驅動程序的數據。Bus域描述設 備所連接的總線類型。
          內核提供了相應的函數用于操作device對象。其中Device_register()函數將一個新的device對象插 入設備模型,并自動在/sys/devices下創建一個對應的目錄。Device_unregister()完成相反的操作,注銷設備對象。 Get_device()和put_device()分別增加與減少設備對象的引用計數。通常device結構不單獨使用,而是包含在更大的結構中作為一 個子結構使用,比如描述PCI設備的struct pci_dev,其中的dev域就是一個device對象。
          4.2 drivers
          系統中的每個驅動程序由一個device_driver對象描述,對應的數據結構定義為:
          struct device_driver {
              
          char *name;   // 設備驅動程序的名稱
              struct bus_type *bus; // 該驅動所管理的設備掛接的總線類型
              struct kobject kobj;    // 內嵌kobject對象
              struct list_head devices;  // 該驅動所管理的設備鏈表頭
              int (*probe)(struct device *dev); // 指向設備探測函數,用于探測設備是否可以被該驅動程序管理
          int (*remove)(struct device *dev); // 用于刪除設備的函數
          /*
           some fields omitted*/
          };

          與device 結構類似,device_driver對象依靠內嵌的kobject對象實現引用計數管理和層次結構組織。內核提供類似的函數用于操作 device_driver對象,如get_driver()增加引用計數,driver_register()用于向設備模型插入新的driver對 象,同時在sysfs文件系統中創建對應的目錄。Device_driver()結構還包括幾個函數,用于處理熱拔插、即插即用和電源管理事件。
          4.3   buses
          系統中總線由struct bus_type描述,定義為:
          struct bus_type {
          char   * name; // 總線類型的名稱
          struct subsystem subsys; // 與該總線相關的subsystem
          struct kset drivers; // 所有與該總線相關的驅動程序集合
          struct kset devices; // 所有掛接在該總線上的設備集合
          struct bus_attribute * bus_attrs; // 總線屬性
          struct device_attribute * dev_attrs; // 設備屬性
          struct driver_attribute * drv_attrs;   // 驅動程序屬性
          int (*match)(struct device * dev, struct device_driver * drv);
          int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
          int (*suspend)(struct device * dev, u32 state);
          int (*resume)(struct device * dev);
          };

          每 個bus_type對象都內嵌一個subsystem對象,bus_subsys對象管理系統中所有總線類型的subsystem對象。每個 bus_type對象都對應/sys/bus目錄下的一個子目錄,如PCI總線類型對應于/sys/bus/pci。在每個這樣的目錄下都存在兩個子目 錄:devices和drivers(分別對應于bus_type結構中的devices和drivers域)。其中devices子目錄描述連接在該總 線上的所有設備,而drivers目錄則描述與該總線關聯的所有驅動程序。與device_driver對象類似,bus_type結構還包含幾個函數 (match()、hotplug()等)處理相應的熱插拔、即插即拔和電源管理事件。
          4.4 classes
          系統中的設備類由 struct class描述,表示某一類設備。所有的class對象都屬于class_subsys子系統,對應于sysfs文件系統中的/sys/class目錄。 每個class對象包括一個class_device鏈表,每個class_device對象表示一個邏輯設備,并通過struct class_device中的dev域(一個指向struct device的指針)關聯一個物理設備。這樣,一個邏輯設備總是對應于一個物理設備,但是一個物理設備卻可能對應于多個邏輯設備。此外,class結構中 還包括用于處理熱插拔、即插即拔和電源管理事件的函數,這與device對象和driver對象相似。

          posted @ 2008-11-12 23:14 LukeW 閱讀(189) | 評論 (0)編輯 收藏

          位運算

          C中的位運算
          能夠運用到任何整形的數據類型上(包括char, int), 無論有沒有short, long, unsigned這樣的限定詞.


          位運算的應用
          // 交換指針變量x,y所指向的存儲位置處存放的值
          // 優勢是不需要第三個位置來臨時存儲另一個值
          // 但是這個方法并沒有明顯的性能優勢,只是一個智力上的消遣
          void inplace_swap(int *x, int *y)
          {
           
          *= *^ *y;
           
          *= *^ *y;
           
          *= *^ *y;
          }

          位運算常見用法:
          實現掩碼運算



          -----------------------------------
          Java中的位運算


          posted @ 2008-11-12 13:53 LukeW 閱讀(135) | 評論 (0)編輯 收藏

          大端小端 -- 各系統及機器的信息表示

          因為現行的計算機都是以八位一個字節為存儲單位,那么一個16位的整數,也就是C語言中的short,在內存中可能有兩種存儲順序big-

          endian和litte-endian.考慮一個short整數0x3132(0x32是低位,0x31是高位),把它賦值給一個short變量,那么它在內存中的存儲可

          能有如下兩種情況:
          大端字節(Big-endian):

          short變量地址
                 0x1000                  0x1001
          ___________________________________
          |                 |
          |         0x31    |       0x32
          |________________ | ________________
          高位字節在低位字節的前面,也就是高位在內存地址低的一端.可以這樣記住(大端->高位->在前->正常的邏輯順序)
           
          小端字節(little-endian):

          short變量地址
                 0x1000                  0x1001
          _____________________________________
          |                 |
          |         0x32    |       0x31
          |________________ | __________________
          低位字節在高位字節的前面,也就是低位在內存地址低的一端.可以這樣記住(小端->低位->在前->與正常邏輯順序相反)
           
          可以做個實驗
          在windows上下如下程序
          #include <stdio.h>
          #include 
          <assert.h>
           
          void main( void )
          {
                  
          short test;
                  FILE
          * fp;
                  
                  test 
          = 0x3132;  //(31ASIIC碼的’1’,32ASIIC碼的’2’)
                  if ((fp = fopen ("c:""test.txt""wb")) == NULL)
                        assert(
          0);
                  fwrite(
          &test, sizeof(short), 1, fp);
                  fclose(fp);
          }

              然后在C盤下打開test.txt文件,可以看見內容是21,而test等于0x3132,可以明顯的看出來x86的字節順序是低位在前.如果我們
          把這段同樣的代碼放到(big-endian)的機器上執行,那么打出來的文件就是12.這在本機中使用是沒有問題的.但當你把這個文件從一
          個big- endian機器復制到一個little-endian機器上時就出現問題了.

              如上述例子,我們在big-endian的機器上創建了這個test文件,把其復制到little-endian的機器上再用fread讀到一個 short里
          面,我們得到的就不再是0x3132而是0x3231了,這樣讀到的數據就是錯誤的,所以在兩個字節順序不一樣的機器上傳輸數據時需要特別
          小心字節順序,理解了字節順序在可以幫助我們寫出移植行更高的代碼.

          正因為有字節順序的差別,所以在網絡傳輸的時候定義了所有字節順序相關的數據都使用big-endian,BSD的代碼中定義了四個宏來處
          理:
          #define ntohs(n)     //網絡字節順序到主機字節順序 n代表net, h代表host, s代表short
          #define htons(n)     //主機字節順序到網絡字節順序 n代表net, h代表host, s代表short
          #define ntohl(n)      //網絡字節順序到主機字節順序 n代表net, h代表host, s代表 long
          #define htonl(n)      //主機字節順序到網絡字節順序 n代表net, h代表host, s代表 long

          舉例說明下這其中一個宏的實現:
           #define sw16(x) "
              ((
          short)( "
                  (((short)(x) & (short)0x00ffU<< 8| "
                  (((short)(x) & (short)0xff00U>> 8) ))

          這里實現的是一個交換兩個字節順序.其他幾個宏類似.

          我們改寫一下上面的程序
          #include <stdio.h>
          #include 
          <assert.h>

          #define sw16(x) "
              ((
          short)( "
                  (((short)(x) & (short)0x00ffU<< 8| "
                  (((short)(x) & (short)0xff00U>> 8) ))

          // 因為x86下面是低位在前,需要交換一下變成網絡字節順序
          #define htons(x) sw16(x)
           
          void main( void )
          {
                  
          short test;
                  FILE
          * fp;
                  
                  test 
          = htons(0x3132); //(31ASIIC碼的’1’,32ASIIC碼的’2’)
                  if ((fp = fopen ("c:""test.txt""wb")) == NULL)
                        assert(
          0);
                  fwrite(
          &test, sizeof(short), 1, fp);
                  fclose(fp);
          }

           
              如果在高字節在前的機器上,由于與網絡字節順序一致,所以我們什么都不干就可以了,只需要把#define htons(x) sw16(x)宏替

          換為 #define htons(x) (x).
              一開始我在理解這個問題時,總在想為什么其他數據不用交換字節順序?比如說我們write一塊buffer到文件,最后終于想明白了,

          因為都是unsigned char類型一個字節一個字節的寫進去,這個順序是固定的,不存在字節順序的問題.

          【用函數判斷系統是Big Endian還是Little Endian】


          bool IsBig_Endian()
          //如果字節序為big-endian,返回true;
          //反之為   little-endian,返回false
          {
              unsigned 
          short test = 0x1122;
              
          if(*( (unsigned char*&test ) == 0x11)
                 
          return TRUE;
          else
              
          return FALSE;

          }
          //IsBig_Endian()

          【打印程序對象的字節表示】
          // 可在不同平臺與硬件架構的機器中測試運行這段代碼,理解大端表示和小端表示的不同.
          // 這段代碼使用強制類型轉換規避類型系統
          #incluede <stdio.h>

          // 假設每個字節都是非負整數
          typedef unsigned char *byte_pointer;

          void show_bytes(byte_pointer start, int len)
          {
           
          for(int i = 0; i < len; i++)
            printf(
          " %.2x", start[i]);
           printf(
          "\n");
          }

          void show_int(int x)
          {
           show_bytes((byte_pointer) 
          &x, sizeof(int));
          }

          void show_float(float x)
          {
           show_bytes((byte_pointer) 
          &x, sizeof(float));
          }

          // 在使用相同編碼(如ASCII編碼)的系統中,字符串字節表示得到的結果一般是相同的.所以文本數據比二進制數據具有更強的平臺無關性
          void show_string(char *x)
          {
           show_bytes((byte_pointer) x, strlen(x));
          }

          void show_pointer(void *x)
          {
           show_bytes((byte_pointer) 
          &x, sizeof(void *));
          }

          void test_show_bytes(int val)
          {
           
          int ival = val;
           
          float fval = (float)ival;
           
          int *pval = &ival;
           
           show_int(ival); 
          // 各個機器因為大端表示和小端表示的不同,從而只是字節順序不同
           show_float(fval); // 各個機器因為大端表示和小端表示的不同,從而只是字節順序不同
           show_pointer(pval); // 指針值是與機器相關的(linux,sun使用4字節地址, 而alpha使用八字節地址)
          }

          ---------------------------------------------
          對于如數值12345在int型和float型時的編碼表示

          posted @ 2008-11-12 11:58 LukeW 閱讀(658) | 評論 (0)編輯 收藏

          點子

              只有注冊用戶登錄后才能閱讀該文。閱讀全文

          posted @ 2008-11-06 18:17 LukeW 閱讀(44) | 評論 (0)編輯 收藏

          j2me 聯網技術分析總結

          基本點:

          Generic Connections

          In the CLDC Generic Connection framework, all connections are created using the open static method from the Connector class. If successful, this method returns an object that implements one of the generic connection interfaces. Figure 1 shows how these interfaces form an is-a hierarchy. The Connection interface is the base interface such that StreamConnectionNotifier is a Connection and InputConnection is a Connection too.

          fig1.gif
          Figure 1: Connection interface hierarchy
          • The Connection interface is the most basic connection type. It can only be opened and closed.
          • The InputConnection interface represents a device from which data can be read. Its openInputStream method returns an input stream for the connection.
          • The OuputConnection interface represents a device to which data can be written. Its openOutputStream method returns an output stream for the connection.
          • The StreamConnection interface combines the input and output connections.
          • The ContentConnection is a subinterface of StreamConnection. It provides access to some of the basic meta data information provided by HTTP connections.
          • The StreamConnectionNotified waits for a connection to be established. It returns a StreamConnection on which a communication link has ben established.
          • The DatagramConnection represents a datagram endpoint.

          The open method of the Connector class has the following syntax, where the String parameter has the format "protocol:address;parameters".

          Connector.open(String);

          Here are a few examples:

          HTTP Connection

          Connector.open("http://java.sun.com/developer");

          Datagram Connection

          Connector.open("datagram://address:port#");

          Communicate with a Port

          Connector.open("comm:0;baudrate=9600');

          Open Files

          Connector.open("file:/myFile.txt");


          The HttpConnection Interface:

          The HTTP protocol is a request-response application protocol in which the parameters of the request must be set before the request is sent. The connection could be in one of the three following states:
          • Setup: No connection yet
          • Connected: Connection has been made, the request has been sent, and some response is expected
          • Closed: Connection is closed

          In the setup state the following methods can be invoked:

          • setRequestMethod
          • setRequestProperty

          For example, suppose you have this connection:

          HttpConnection c = (HttpConnection)
          Connector.open(
          "http://java.sun.com/developer");

          Then, you can set the request method to be of type POST as follows:

          c.setRequestMethod(HttpConnection.POST);

          And likewise, you can set some of the HTTP properties. For example, you can set the User-Agent as follows:

          c.setRequestProperty("User-Agent","Profile/MIDP-1.0 Configuration/CLDC-1.0");

          If there is a method that requires data to be sent or received from the server, there is a state transition from Setup to Connected. Examples of methods that cause the transition include:

          openInputStream
          openOutputStream
          openDataInputStream
          openDataOutputStream
          getLength
          getType
          getDate
          getExpiration

          And while the connection is open, some of these methods that may be invoked:

          getURL
          getProtocol
          getHost
          getPort


          ------------------------------------------------------------
          要注意的問題:
          開發中遇到個很頭疼的問題, 與服務器通信write()數據時報java.io.IOException: Couldn't write to socket.
          但是服務器抓不到任何包. 一開始懷疑是連建立連接出的問題, 實際上服務器抓不到包也有可能是流在沒有close的時候就已經報錯了.
          如:
          conn.open("url");
          out = conn.openDataOutputStream();//此時將進行與服務器的三次握手;
                                            //但是如果在out.close()之前出現異常服務器是抓不到任何包的
          out.write(byte[] bb);

          關于這個的解釋應該是流的緩沖機制.
          所以正確的寫法應該是捕捉到異常之后在catch塊中把流close掉.
          服務器端開發人員一般會說收不到包所以連接有問題,會把責任推給客戶端,抓住這個證據在跟服務器端的同事扯皮時將處于有利的位置,嘎嘎.
          還有就是要多做小實驗, 注意代碼要規范嚴格.

          發現的幾個問題:

          1. java.io.IOException: Couldn't write to socket

          2. java.io.IOException: Couldn't read from socket

          CMNET聯網方案:

          CMWAP聯網方案:

          移動資費頁的處理:

          一個通用的HTTP連接封裝:

          posted @ 2008-11-04 16:22 LukeW 閱讀(379) | 評論 (0)編輯 收藏

          VIM設置

          vim簡介
           
          Vim(Vi Improved) 是一個類似于vi 的文本編輯器,在Vi的基礎上增加了很多新的特性和功能。Vim以其強大的功能和可定制能力

          ,成為Linux/Unix環境下開源的最重要的編輯器之一(另一個是 Emacs),被眾多開發者所喜愛。筆者此時所用的是最新的7.1版本


          與大部分其它編輯器不同,進入 Vim 后,缺省狀態下鍵入的字符并不會插入到所編輯的文件之中。Vim 的模式(mode,可以簡單地

          理解為“狀態”)概念非常重要。需要知道,Vim 有以下幾個模式:
          1)   正常(normal)模式,缺省的編輯模式;下面如果不加特殊說明,提到的命令都直接在正常模式下輸入;任何其它模式中都

          可以通過鍵盤上的 Esc 鍵回到正常模式。
          2)   命令(command)模式,用于執行較長、較復雜的命令;在正常模式下輸入“:”(一般命令)、“/”(正向搜索)或“?”

          (反向搜索)即可進入該模式;命令模式下的命令要輸入回車鍵(Enter)才算完成。
          3)   插入(insert)模式,輸入文本時使用;在正常模式下鍵入“i”(insert)或“a”(append)即可進入插入模式(也有另

          外一些命令,如“c”,也可以進入插入模式,但這些命令有其它的作用)。
          4)   可視(visual)模式,用于選定文本塊;可以在正常模式下輸入“v”(小寫)來按字符選定,輸入“V”(大寫)來按行選

          定,或輸入“Ctrl-V”來按方塊選定。
          5)   選擇(select)模式,與普通的 Windows 編輯器較為接近的選擇文本塊的方式;在以可視模式和選擇模式之一選定文本塊之

          后,可以使用“Ctrl-G”切換到另一模式——該模式很少在 Linux 上使用,本文中就不再介紹了。
          ------------------------------------------
          首先 vim ~/.vimrc 打開編輯文件

          [轉]
             1、VI或VIM的配置文件的路徑

              發現/usr/share/vim/vimrc和/etc/vim/vimrc指向是同一個文件,即vimrc,為vi和vim的配置文件,修改這個文件即可。這個路徑在不同的LINUX版本中可能會不同。

              2、配置顏色

              配軒VI和VIM的顏色顯示,使它能夠高亮度顯示一些特別的單詞,這對編寫程序很有用。后來打開文件發現里面其實已經有一行了,只是用引號注釋掉了,只需 將syntax on 所在行前面的引號去掉即可。或者另外獨立添加一行:syntax on 也行,另外編輯/etc/profile 增加一行alias vi="vim"就行了。

              3、設置鼠標

              使用VI編輯文本時,如果想修文件中改離光標較遠的位置,這時候想用鼠標定位,可默認情況下,鼠標是不可用的。如果你想使用鼠標,只需另起一行,寫上:set mouse=a 即可

              4、設置自動縮進

              默認情況下,VI和VIM都沒有縮進的,每換一行,光標均定位在頂格,如果你想自動對齊,請將 set autoindent所在行前面的引號去掉,或者另外添加一行:set autoindent也可。這與配置顏色類似。這樣的設置的結果是按回車后新行與上一行自動對齊。

              5、設置tab的縮進量

              如果用python編寫程序,那么行縮進量是一個極其重要的概念,同一個塊的縮進量必須相同。你可能喜歡在行前加空格來表示縮進,但每次必須敲多次空格 鍵,如果你喜歡用按TAB鍵來表示縮進,你可能覺得寫的文本或程序不太好看,因為默認情況下,VI和VIM的TAB縮進量比較大(至少六,七個字符)。設 置TAB鍵縮進量的方法:set shiftwidth=3 你也可以選一 個你自己喜歡的縮進量,比如2,或4.

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

          首先從視覺方面:

          第一個要做的是縮進,修改你的配置文件_vimrc,在最后加入set cindent,這樣就設置了c風格的縮進,在這里縮進的大小是shiftwidth的值。

          第二個要做的是語法高亮,這個是必須的,在中_vimrc加入syntax enable

          第三個要做的字體的設置,設置一個舒服的字體可以讓你編程的時候舒服好多,用editplus的時候我就用的Consolas,在中我還是用的這種字體,在_vimrc中加入

          if has(”gui_running”)
          set guifont=Consolas:h9
          endif

          表示運行界面的時候就用這種字體。

          第四,設置配色方案,可以到點擊這兒下載,然后放到$"vimfiles"colors這個目錄下,然后在中加入如下配置

          if has(”gui_running”)
          set guifont=Consolas:h9
          ” set color schema
          colorscheme
          colorscheme_name
          endif

          colorscheme_name為你需要設置的配色方案的名稱。

          接下來是在運行程序中用到的:

          第一,使用ctag

          中已經帶了Ctags這個程序。盡管ctags也可以支持其它編輯器,但是它正式支持的只有。Ctags可以幫助程序員很容易地瀏覽源代碼。用下面的命令可以在源代碼的根目錄下創建“tags”文件:

          [/home/brimmer/src]$ ctags -R

          “-R”表示遞歸創建,也就包括源代碼根目錄下的所有子目錄下的源程序。“tags”文件中包括這些對象的列表:

          l        用#define定義的宏

          l        枚舉型變量的值

          l        函數的定義、原型和聲明

          l        名字空間(namespace)

          l        類型定義(typedefs)

          l        變量(包括定義和聲明)

          l        類(class)、結構(struct)、枚舉類型(enum)和聯合(union)

          l        類、結構和聯合中成員變量或函數

          用這個“tags”文件來定位上面這些做了標記的對象,下面介紹一下定位這些對象的方法:

          1)        用命令行。在運行的時候加上“-t”參數,例如:

          [/home/brimmer/src]$   -t  foo_bar

          這個命令將打開定義“foo_bar”(變量或函數或其它)的文件,并把光標定位到這一行。

          2)        在編輯器內用“:ta”命令,例如:

          :ta foo_bar

          3)        最方便的方法是把光標移到變量名或函數名上,然后按下“Ctrl-]”。用“Ctrl-o”退回原來的地方。

          注意:運行的時候,必須在“tags”文件所在的目錄下運行。否則,運行的時候還要用“:set tags=”命令設定“tags”文件的路徑,這樣才能找到“tags”文件。

          你還可以選擇使用taglist這個插件,這個插件可以在右側顯示函數,變量等的列表

          第二,改正程序中的錯誤

          編輯器的環境下用“:make”(make工具的使用已經在我昨天的文章中 提到的云風的幾篇文章中詳細介紹到)就可以編譯程序,當然其前提是在當前目錄下有Makefile文件。運行完“:make”之后,如果程序中有錯誤,就 會顯示出來。這時候,光標會自動指向第一個出現錯誤的地方,而且你還可以看到錯誤的提示。然后,你就可以改正錯誤,而不用手工找到出錯的那一行。記住下面 幾個有用的命令:

          l        “:cl”列出錯誤

          l        “:cn”讓光標指向下一個錯誤

          l        “:cp”讓光標指向上一個錯誤

          l        “:cnew”從頭開始

          你甚至可以讓識別出其它編譯器而不是gcc的錯誤提示。這對一些開發嵌入式系統的程序員這很有用,因為他們很可能用的不是gcc而是其它編譯器。通過設置“errorformat”的值,可以讓識別出編譯器的出錯提示。因為不同的編譯器的出錯提示是不同的,所以如果用的不是gcc就要重新設置。

          errorformat”的值是一個字符串,它的格式和C語言的scanf的字符串格式相識。

          gcc的“errorformat”的值為:%f:%l:"%m。其中“%f”表示文件名,“%l”表示行號,“%m”表示出錯信息。

          用“:h errorformat”查看詳細的幫助信息。

          “:h quickfix”、“:h make”、“:h makeprg”、“:h errorfile”查看其它的信息。

          第三,使用快捷鍵

          下面的這些快捷鍵對程序員很有幫助:
          在函數中移動光標

          [[  轉到上一個位于第一列的“{”

          ]]  轉到下一個位于第一列的“{”

          {   轉到上一個空行

          }   轉到下一個空行

          gd  轉到當前光標所指的局部變量的定義

          *   轉到當前光標所指的單詞下一次出現的地方

          #   轉到當前光標所指的單詞上一次出現的地方
          括號的匹配

          %   用來進行小括號、中括號和大括號的匹配。這要看當前光標指向的是什么符號了。

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

          一個ubuntu 下的vimrc配置例子:

          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 一般設定
          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 設定默認解碼
          set fenc
          =utf-8
          set fencs
          =utf-8,usc-bom,euc-jp,gb18030,gbk,gb2312,cp936

          "設定搜索是的高亮顯示
          set hlsearch

          " 不要使用vi的鍵盤模式,而是vim自己的
          set nocompatible

          " history文件中需要記錄的行數
          set history=100

          " 在處理未保存或只讀文件的時候,彈出確認
          set confirm

          " 與windows共享剪貼板
          set clipboard+=unnamed

          " 偵測文件類型
          filetype on

          " 載入文件類型插件
          filetype plugin on

          " 為特定文件類型載入相關縮進文件
          filetype indent on

          " 保存全局變量
          set viminfo+=!

          " 帶有如下符號的單詞不要被換行分割
          set iskeyword
          +=_,$,@,%,#,-

          " 語法高亮
          syntax on

          " 高亮字符,讓其不受100列限制
          :highlight OverLength ctermbg
          =red ctermfg=white guibg=red guifg=white
          ":match OverLength '"%101v.*'

          " 狀態行顏色
          highlight StatusLine guifg=SlateBlue guibg=Yellow
          highlight StatusLineNC guifg=Gray guibg=White

          "高亮當前行
          set cursorline

          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 文件設置
          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 不要備份文件(根據自己需要取舍)
          set nobackup

          " 不要生成swap文件,當buffer被丟棄的時候隱藏它
          setlocal noswapfile
          set bufhidden=hide

          " 字符間插入的像素行數目
          set linespace
          =0

          " 增強模式中的命令行自動完成操作
          set wildmenu

          " 在狀態行上顯示光標所在位置的行號和列號
          set ruler
          set rulerformat
          =%20(%2*%<%f%=" %m%r" %3l" %c" %p%%%)

          " 命令行(在狀態行下)的高度,默認為1,這里是2
          set cmdheight=2

          " 使回格鍵(backspace)正常處理indent, eol, start等
          set backspace
          =2

          " 允許backspace和光標鍵跨越行邊界
          set whichwrap+=<,>,h,l

          " 可以在buffer的任何地方使用鼠標(類似office中在工作區雙擊鼠標定位)
          set mouse
          =a
          set selection
          =exclusive
          set selectmode
          =mouse,key

          " 啟動的時候不顯示那個援助索馬里兒童的提示
          set shortmess=atI

          " 通過使用: commands命令,告訴我們文件的哪一行被改變過
          set report
          =0

          " 不讓vim發出討厭的滴滴聲
          set noerrorbells

          " 在被分割的窗口間顯示空白,便于閱讀
          set fillchars
          =vert:" ,stl:" ,stlnc:"

          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 搜索和匹配
          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 高亮顯示匹配的括號
          set showmatch

          " 匹配括號高亮的時間(單位是十分之一秒)
          set matchtime
          =5

          " 在搜索的時候不忽略大小寫
          set noignorecase

          " 不要高亮被搜索的句子(phrases)
          "set nohlsearch

          " 在搜索時,輸入的詞句的逐字符高亮(類似firefox的搜索)
          set incsearch

          " 輸入:set list命令是應該顯示些啥?
          set listchars=tab:
          "|" ,trail:.,extends:>,precedes:<,eol:$

          " 光標移動到buffer的頂部和底部時保持3行距離
          set scrolloff
          =3

          " 不要閃爍
          set novisualbell

          " 我的狀態行顯示的內容(包括文件類型和解碼)
          set statusline
          =%F%m%r%h%w" [FORMAT=%{&ff}]" [TYPE=%Y]" [POS=%l,%v][%p%%]" %{strftime(""%d/%m/%y" -" %H:%M"")}

          " 總是顯示狀態行
          set laststatus=2

          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 文本格式和排版
          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 自動格式化
          set formatoptions=tcrqn

          " 繼承前一行的縮進方式,特別適用于多行注釋
          set autoindent

          " 為C程序提供自動縮進
          set smartindent

          " 使用C樣式的縮進
          set cindent

          " 制表符為4
          set tabstop=4

          " 統一縮進為4
          set softtabstop
          =4
          set shiftwidth
          =4

          " 不要用空格代替制表符
          set noexpandtab

          " 不要換行
          "set nowrap

          "設置每行80個字符自動換行
          set textwidth
          =80

          " 在行和段開始處使用制表符
          set smarttab

          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " CTags的設定
          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 按照名稱排序
          let Tlist_Sort_Type = 
          "name"

          " 在右側顯示窗口
          let Tlist_Use_Right_Window 
          = 1

          " 壓縮方式
          let Tlist_Compart_Format = 1

          " 如果只有一個buffer,kill窗口也kill掉buffer
          let Tlist_Exist_OnlyWindow 
          = 1

          " 不要關閉其他文件的tags
          let Tlist_File_Fold_Auto_Close = 0

          " 不要顯示折疊樹
          let Tlist_Enable_Fold_Column 
          = 1

          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " Autocommands
          """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
          " 只在下列文件類型被偵測到的時候顯示行號,普通文本文件不顯示

          if has("autocmd")
             autocmd FileType xml,html,c,cs,java,perl,shell,bash,cpp,python,vim,php,ruby set number
             autocmd FileType xml,html vmap 
          <C-o> <ESC>'<i<!--<ESC>o<ESC>'>o-->
             autocmd FileType java,c,cpp,cs vmap 
          <C-o> <ESC>'<o/*<ESC>'>o*/
             autocmd FileType html,text,php,vim,c,java,xml,bash,shell,perl,python setlocal textwidth
          =80
             autocmd Filetype html,xml,xsl source $VIMRUNTIME
          /plugin/closetag.vim
             autocmd BufReadPost 
          *
                
          " if line("'""") > 0 && line("'""") <= line("$") |
                
          "   exe "normal g`""" |
                
          " endif
          endif 
          " has("autocmd")

          " C/C++的編譯和運行
          map <F5> :call CompileRunGcc()<CR>
          func! CompileRunGcc()
          exec 
          "w"
          exec 
          "!make"
          exec 
          "! ./%<"
          endfunc

          " shell script運行
          map 
          <F6> :call CompileRunSH()<CR>
          func
          ! CompileRunSH()
          exec 
          "w"
          exec 
          "!chmod a+x %"
          exec 
          "!./%"
          endfunc

          " python運行
          map <F7> :call CompileRunPyhton()<CR>
          func! CompileRunPyhton()
          exec 
          "w"
          exec 
          "!chmod a+%"
          exec 
          "!./%"
          endfunc

          " 能夠漂亮地顯示.NFO文件
          set encoding
          =utf-8
          function! SetFileEncodings(encodings)
              let b:myfileencodingsbak
          =&fileencodings
              let 
          &fileencodings=a:encodings
          endfunction
          function! RestoreFileEncodings()
              let 
          &fileencodings=b:myfileencodingsbak
              unlet b:myfileencodingsbak
          endfunction

          au BufReadPre 
          *.nfo call SetFileEncodings('cp437')|set ambiwidth=single
          au BufReadPost 
          *.nfo call RestoreFileEncodings()

          " 高亮顯示普通txt文件(需要txt.vim腳本)
          au BufRead,BufNewFile *  setfiletype txt

          " 用空格鍵來開關折疊
          set foldenable
          set foldlevel
          =0
          set foldmethod
          =indent
          nnoremap 
          <space> @=((foldclosed(line('.')) < 0? 'zc' : 'zo')<CR>

          " minibufexpl插件的一般設置
          let g:miniBufExplMapWindowNavVim = 1
          let g:miniBufExplMapWindowNavArrows = 1
          let g:miniBufExplMapCTabSwitchBufs = 1
          let g:miniBufExplModSelTarget = 1

          ----------------------
          一個相關帖子
          http://forum.ubuntu.org.cn/viewtopic.php?f=68&t=138212&st=0&sk=t&sd=a

           

          posted @ 2008-11-03 13:02 LukeW 閱讀(1636) | 評論 (0)編輯 收藏

          servlet過濾器

          servlet過濾器

          1. Servlet過濾器基礎
          Servlet過濾器是Servlet的一種特殊用法,主要用來完成一些通用的操作。比如編碼的過濾,判斷用戶的登陸狀態等等。Servlet過濾器的適用場合:
          A.認證過濾
          B.登錄和審核過濾
          C.圖像轉換過濾
          D.數據壓縮過濾
          E.加密過濾
          F.令牌過濾
          G.資源訪問觸發事件過濾
          Servlet過濾器接口的構成:
          所有的Servlet過濾器類都必須實現javax.servlet.Filter接口。這個接口含有3個過濾器類必須實現的方法:
          方法 說明
          init(FilterConfig cfg) 這是Servlet過濾器的初始化方法,性質等同與servlet的init方法。
          doFilter(ServletRequest,ServletResponse,FilterChain) 完成實際的過濾操作,當請求訪問過濾器關聯的URL時,Servlet容器將先調用過濾器的doFilter方法。FilterChain參數用于訪問后續過濾器
          destroy() Servlet容器在銷毀過濾器實例前調用該方法,這個方法中可以釋放Servlet過濾器占用的資源。性質等同與servlet的destory()方法。
          Servlet過濾器的創建步驟:
          A.實現javax.servlet.Filter接口的servlet類
          B.實現init方法,讀取過濾器的初始化函數
          C.實現doFilter方法,完成對請求或過濾的響應
          D.調用FilterChain接口對象的doFilter方法,向后續的過濾器傳遞請求或響應
          F.在web.xml中配置Filter
          2.使用過濾器處理中文問題
             當用用戶登陸頁面輸入帳號時,如果輸入是中文,后臺servlet再次輸出這個內容時,可能就會是亂碼,這是因為serlvet中默認是以ISO-8859-1格式編碼的,如果后臺有多個Servlet,多個參數,這樣就不合適,這個問題,我們可以通過一個過濾器統一解決,使后臺的輸出輸出都支持中文!將ISO-8859-1轉碼為GBK的那段代碼!
          3.使用過濾器認證用戶:
          每個過濾器也可以配置初始化參數,可以將不需要過濾的地址配置到這個Filter的配置參數中,過濾時,如果請求地址在配置參數中,則放行,這樣 就避免了在程序中硬編碼。每個Filter中初始化時,都可以得到配置對象,在Filter中配置二個不需要過濾的地址,一個是登陸頁面,一個是執行登陸 認證的servlet;
          4.Servlet監聽器
          類似與Swing界面應用開發,Servlet也可以創建監聽器,以對Servlet容器,或Servlet中以象的事件做出反應。Servlet監聽器主要有以下幾種:
          ServletRequestListener ,ServletRequestAttributeListener,
          HttpSessionActivationListener ,HttpSessionBindingListener ,
          HttpSessionAttributeListener,HttpSessionListener,
          ServletContextListener等等。
          這些監聽器主要用來監聽session,request,application這三個對象里存取數據的變化。
          ----------------------------------------------------------------------------------------------------------------

          servlet API中最重要的一個功能就是能夠為servlet和JSP頁面定義過濾器。過濾器提供了某些早期服務器所支持的非標準“servlet鏈接”的一種功能強大且標準的替代品。
                                                                                                          
               過濾器是一個程序,它先于與之相關的servlet或JSP頁面運行在服務器上。過濾器可附加到一個或多個servlet或JSP頁面上,并且可以檢查進入這些資源的請求信息。在這之后,過濾器可以作如下的選擇:

          1. 以常規的方式調用資源(即,調用servlet或JSP頁面)。

          2.利用修改過的請求信息調用資源。

          3. 調用資源,但在發送響應到客戶機前對其進行修改

          4. 阻止該資源調用,代之以轉到其他的資源,返回一個特定的狀態代碼或生成替換輸出。

          過濾器提供了幾個重要好處 :


                  首先,它以一種模塊化的或可重用的方式封裝公共的行為。你有30個不同的serlvet或JSP頁面,需要壓縮它們的內容以減少下載時間嗎?沒問題:構造一個壓縮過濾器,然后將它應用到30個資源上即可。

          其次,利用它能夠將高級訪問決策與表現代碼相分離。這對于JSP特別有價值,其中一般希望將幾乎整個頁面集中在表現上,而不是集中在業務邏輯上。例如,希 望阻塞來自某些站點的訪問而不用修改各頁面(這些頁面受到訪問限制)嗎?沒問題:建立一個訪問限制過濾器并把它應用到想要限制訪問的頁面上即可。

               最后,過濾器使你能夠對許多不同的資源進行批量性的更改。你有許多現存資源,這些資源除了公司名要更改外其他的保持不變,能辦到么?沒問題:構造一個串替換過濾器,只要合適就使用它。

               但要注意,過濾器只在與servlet規范2.3版兼容的服務器上有作用。如果你的Web應用需要支持舊版服務器,就不能使用過濾器。

          1.   建立基本過濾器

          建立一個過濾器涉及下列五個步驟:
          1)建立一個實現Filter接口的類。這個類需要三個方法,分別是:doFilter、init和destroy。
                 doFilter方法包含主要的過濾代碼(見第2步),init方法建立設置操作,而destroy方法進行清楚。

          2)在doFilter方法中放入過濾行為。doFilter方法的第一個參數為ServletRequest對象。此對象給過濾器提供了對進入的信息 (包括表單數據、cookie和HTTP請求頭)的完全訪問。第二個參數為ServletResponse,通常在簡單的過濾器中忽略此參數。最后一個參 數為FilterChain,如下一步所述,此參數用來調用servlet或JSP頁。

          3)調用FilterChain對象的doFilter方法。Filter接口的doFilter方法取一個FilterChain對象作為它的一個參 數。在調用此對象的doFilter方法時,激活下一個相關的過濾器。如果沒有另一個過濾器與servlet或JSP頁面關聯,則servlet或JSP 頁面被激活。

          4)對相應的servlet和JSP頁面注冊過濾器。在部署描述符文件(web.xml)中使用filter和filter-mapping元素。

          5)禁用激活器servlet。防止用戶利用缺省servlet URL繞過過濾器設置。

          1.1   建立一個實現Filter接口的類
                所有過濾器都必須實現javax.servlet.Filter。這個接口包含三個方法,分別為doFilter、init和destroy。

          public void doFilter(ServletRequset request,
                               ServletResponse response,
                               FilterChain chain)
               thows ServletException, IOException

          每當調用一個過濾器(即,每次請求與此過濾器相關的servlet或JSP頁面)時,就執行其doFilter方法。正是這個方法包含了大部分過濾邏輯。 第一個參數為與傳入請求有關的ServletRequest。對于簡單的過濾器,大多數過濾邏輯是基于這個對象的。如果處理HTTP請求,并且需要訪問諸 如getHeader或getCookies等在ServletRequest中無法得到的方法,就要把此對象構造成 HttpServletRequest。

          第二個參數為ServletResponse。除了在兩個情形下要使用它以外,通常忽略這個參數。首先,如果希望完全阻塞對相關servlet或JSP頁 面的訪問。可調用response.getWriter并直接發送一個響應到客戶機。其次,如果希望修改相關的servlet或JSP頁面的輸出,可把響 應包含在一個收集所有發送到它的輸出的對象中。然后,在調用serlvet或JSP頁面后,過濾器可檢查輸出,如果合適就修改它,之后發送到客戶機。

          DoFilter的最后一個參數為FilterChain對象。對此對象調用doFilter以激活與servlet或JSP頁面相關的下一個過濾器。如果沒有另一個相關的過濾器,則對doFilter的調用激活servlet或JSP本身。

          public void init(FilterConfig config)   thows ServletException

          init方法只在此過濾器第一次初始化時執行,不是每次調用過濾器都執行它。對于簡單的過濾器,可提供此方法的一個空體,但有兩個原因需要使用init。 首先,FilterConfig對象提供對servlet環境及web.xml文件中指派的過濾器名的訪問。因此,普遍的辦法是利用init將 FilterConfig對象存放在一個字段中,以便doFilter方法能夠訪問servlet環境或過濾器名.其次,FilterConfig對象具 有一個getInitParameter方法,它能夠訪問部署描述符文件(web.xml)中分配的過濾器初始化參數。

          public void destroy( )
               大多數過濾器簡單地為此方法提供一個空體,不過,可利用它來完成諸如關閉過濾器使用的文件或數據庫連接池等清除任務。

          1.2   將過濾行為放入doFilter方法

               doFilter方法為大多數過濾器地關鍵部分。每當調用一個過濾器時,都要執行doFilter。對于大多數過濾器來說,doFilter執行的步驟是 基于傳入的信息的。因此,可能要利用作為doFilter的第一個參數提供的ServletRequest。這個對象常常構造為 HttpServletRequest類型,以提供對該類的更特殊方法的訪問。

          1.3   調用FilterChain對象的doFilter方法
               Filter接口的doFilter方法以一個FilterChain對象作為它的第三個參數。在調用該對象的doFilter方法時,激活下一個相關的 過濾器。這個過程一般持續到鏈中最后一個過濾器為止。在最后一個過濾器調用其FilterChain對象的doFilter方法時,激活servlet或 頁面自身。
          但是,鏈中的任意過濾器都可以通過不調用其FilterChain的doFilter方法中斷這個過程。在這樣的情況下,不再調用JSP頁面的serlvet,并且中斷此調用過程的過濾器負責將輸出提供給客戶機。

          1.4   對適當的servlet和JSP頁面注冊過濾器

               部署描述符文件的2.3版本引入了兩個用于過濾器的元素,分別是:filter和filter-mapping。filter元素向系統注冊一個過濾對象,filter-mapping元素指定該過濾對象所應用的URL。

          1.filter元素
          filter元素位于部署描述符文件(web.xml)的前部,所有filter-mapping、servlet或servlet-mapping元素之前。filter元素具有如下六個可能的子元素:

          1、 icon   這是一個可選的元素,它聲明IDE能夠使用的一個圖象文件。
          2、filter-name   這是一個必需的元素,它給過濾器分配一個選定的名字。
          3、display-name   這是一個可選的元素,它給出IDE使用的短名稱。
          4、 description   這也是一個可選的元素,它給出IDE的信息,提供文本文檔。
          5、 filter-class   這是一個必需的元素,它指定過濾器實現類的完全限定名。
          6、 init-param   這是一個可選的元素,它定義可利用FilterConfig的getInitParameter方法讀取的初始化參數。單個過濾器元素可包含多個init-param元素。

          請注意,過濾是在serlvet規范2.3版中初次引入的。因此,web.xml文件必須使用DTD的2.3版本。下面介紹一個簡單的例子:

            <xml version="1.0" encoding="ISO-8859-1"?>
              
          DOCTYPE web-app PUBLIC
                  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                   "http://java.sun.com/dtd/web-app_2_3.dtd"
          >

              
          <web-app>
               
          <filter>
                  
          <filter-name>MyFilterfilter-name>
                  
          <filter-class>myPackage.FilterClassfilter-class>
                
          filter>
                

                
          <filter-mapping>...filter-mapping>
               <
          web-app>


          2.filter-mapping元素

              filter-mapping元素位于web.xml文件中filter元素之后serlvet元素之前。它包含如下三個可能的子元素:

          1、 filter-name   這個必需的元素必須與用filter元素聲明時給予過濾器的名稱相匹配。

          2、 url-pattern   此元素聲明一個以斜杠(/)開始的模式,它指定過濾器應用的URL。所有filter-mapping元素中必須提供url-pattern或 servlet-name。但不能對單個filter-mapping元素提供多個url-pattern元素項。如果希望過濾器適用于多個模式,可重復 整個filter-mapping元素。

          3、 servlet-name   此元素給出一個名稱,此名稱必須與利用servlet元素給予servlet或JSP頁面的名稱相匹配。不能給單個filter-mapping元素提供 多個servlet-name元素項。如果希望過濾器適合于多個servlet名,可重復這個filter-mapping元素。
          下面舉一個例子:

          xml version="1.0" encoding="ISO-8859-1"?>
              
          DOCTYPE web-app PUBLIC
                  
          "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

                  
          "http://java.sun.com/dtd/web-app_2_3.dtd">
              
          <web-app>
                
          <filter>
                  
          <filter-name>MyFilterfilter-name>
                  
          <filter-class>myPackage.FilterClassfilter-class>
                
          filter>
                

                
          <filter-mapping>
                  
          <filter-name>MyFilterfilter-name>
                  
          <url-pattern>/someDirectory/SomePage.jspurl-pattern>
                
          filter-mapping>
              
          web-app>


          1.5   禁用激活器servlet
               在對資源應用過濾器時,可通過指定要應用過濾器的URL模式或servlet名來完成。如果提供servlet名,則此名稱必須與web.xml的 servlet元素中給出的名稱相匹配。如果使用應用到一個serlvet的URL模式,則此模式必須與利用web.xml的元素servlet- mapping指定的模式相匹配。但是,多數服務器使用“激活器servlet”為servlet體統一個缺省的URL:http: //host/WebAppPrefix/servlet/ServletName。需要保證用戶不利用這個URL訪問servlet(這樣會繞過過濾器 設置)。
          例如,假如利用filter和filter-mapping指示名為SomeFilter的過濾器應用到名為SomeServlet的servlet,則如下:

          <filter>
                
          <filter-name>SomeFilterfilter-name>
                
          <filter-class>somePackage.SomeFilterClassfilter-class>
             <
          filter>
              

              
          <filter-mapping>
                
          <filter-name>SomeFilterfilter-name>
                
          <servlet-name>SomeServletservlet-name>
               <
          filter-mapping>



          接著,用servlet和servlet-mapping規定URL   http://host/webAppPrefix/Blah 應該調用SomeSerlvet,如下所示:

          <filter>
                
          <filter-name>SomeFilterfilter-name>
                
          <filter-class>somePackage.SomeFilterClassfilter-class>
              
          filter>
              

              
          <filter-mapping>
                
          <filter-name>SomeFilterfilter-name>
                
          <servlet-name>/Blahservlet-name>
               <
          filter-mapping>



          現在,在客戶機使用URL   http://host/webAppPrefix/Blah 時就會調用過濾器。過濾器不應用到
          http://host/webAppPrefix/servlet/SomePackage.SomeServletClass。
          盡管有關閉激活器的服務器專用方法。但是,可移植最強的方法時重新映射Web應用鐘的/servlet模式,這樣使所有包含此模式的請求被送到相同的 servlet中。為了重新映射此模式,首先應該建立一個簡單的servlet,它打印一條錯誤消息,或重定向用戶到頂層頁。然后,使用servlet和 servlet-mapping元素發送包含/servlet模式的請求到該servlet。程序清單9-1給出了一個簡短的例子。

          程序清單9-1 web.xml(重定向缺省servlet URL的摘錄)

           xml version="1.0" encoding="ISO-8859-1"?>
              
          DOCTYPE web-app PUBLIC
                   "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                   "http://java.sun.com/dtd/web-app_2_3.dtd"
          >

              
          <web-app>
              

              
          <servlet>
                
          <servlet-name>Errorservlet-name>
                
          <servlet-class>somePackage.ErrorServletservlet-class>
              
          servlet>
              

              
          <servlet-mapping>
                
          <servlet-name>Errorservlet-name>
                
          <url-pattern>/servlet/*url-pattern>
              
          servlet-mapping>
              

              <
          web-app>

          -------------------------------------------------------------------------------------------
          解決亂碼

          web.xml加配置

          <!--   過濾器 -->
           <filter>
            <filter-name>Filter</filter-name>
            <filter-class>
             com.util.EncodingFilter<!-- 過濾器類 -->
            </filter-class>
            <init-param>
             <param-name>Encoding</param-name>
             <param-value>gb2312</param-value>
            </init-param>
           </filter>
           <filter-mapping>
            <filter-name>Filter</filter-name>
            <url-pattern>/*</url-pattern>
           </filter-mapping>

          EncodingFilter.java

          package com.hibernate.util;

          import java.io.IOException;

          import javax.servlet.Filter;
          import javax.servlet.FilterChain;
          import javax.servlet.FilterConfig;
          import javax.servlet.ServletException;
          import javax.servlet.ServletRequest;
          import javax.servlet.ServletResponse;

          public class EncodingFilter implements Filter {
           protected FilterConfig config;

           protected String Encoding = null;

           public void init(FilterConfig config) throws ServletException {

            this.config = config;
            this.Encoding = config.getInitParameter("Encoding");

           }

           public void doFilter(ServletRequest request, ServletResponse response,
             FilterChain chain) throws IOException, ServletException {

            if (request.getCharacterEncoding() == null) {
             if (Encoding != null) {
              request.setCharacterEncoding(Encoding);
              response.setCharacterEncoding(Encoding);
             }
            }
            chain.doFilter(request,response);
           }
           public void destroy() {}
          }

          OK!!!

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

          很簡單的過濾器,就是為了記錄一個url的請求時間 filter:
          1. package com.javaeye.wqf;  
          2. import javax.servlet.*;  
          3.   
          4. public class CounterFilter implements Filter {  
          5.     public void doFilter(ServletRequest request, ServletResponse response,  
          6.             FilterChain chain) throws IOException, ServletException {  
          7.         long start = System.currentTimeMillis();  
          8.         System.out.println("Filter start at "+start);  
          9.         chain.doFilter(request, response);  
          10.         long end = System.currentTimeMillis();  
          11.         System.out.println("Filter end at "+end);  
          12.     } 



          1. <filter>  
          2.     <filter-name>test</filter-name>  
          3.     <filter-class>com.javaeye.wqf.CounterFilter</filter-class>  
          4. </filter>  
          5.   
          6. <filter-mapping>  
          7.     <filter-name>test</filter-name>  
          8.     <url-pattern>/*</url-pattern>  
          9. </filter-mapping> 
          一般情況下是沒什么問題,但是當我下載一個稍微大的文件時,跳出確認窗口,如果選擇的是cancel,
          就會發現filter并沒有返回,也就是說
          1. System.out.println("Filter end at "+end); 
          并沒有執行. 原因是:

          chain.doFilter(request, response);  
          執行到這里時會從這里調用剩下的filter和servlet,所以這個調用將會是一個很長的過程。
          在這個調用里,將會完全通過request和resonse去操作連接,取得/發送數據,如果連接出現異常,將直接彈出Exception
          你的代碼里沒有捕獲異常,所以如果出現異常,chain.doFilter后面的就不會執行。
          可以把chain.doFilter放到try finally結構中,保證后續會被執行




          posted @ 2008-10-28 14:58 LukeW 閱讀(348) | 評論 (0)編輯 收藏

          Android應用程序剖析

          Anatomy of an Android Application


          There are four building blocks to an Android application:
          • Activity
          • Intent Receiver
          • Service
          • Content Provider

          Not every application needs to have all four, but your application will be written with some combination of these.

          Once you have decided what components you need for your application, you should list them in a file called AndroidManifest.xml. This is an XML file where you declare the components of your application and what their capabilities and requirements are. See the Android manifest file documentation for complete details.

          Activity
          Activities are the most common of the four Android building blocks. An activity is usually a single screen in your application. Each activity is implemented as a single class that extends the Activity base class. Your class will display a user interface composed of Views and respond to events. Most applications consist of multiple screens. For example, a text messaging application might have one screen that shows a list of contacts to send messages to, a second screen to write the message to the chosen contact, and other screens to review old messages or change settings. Each of these screens would be implemented as an activity. Moving to another screen is accomplished by a starting a new activity. In some cases an activity may return a value to the previous activity -- for example an activity that lets the user pick a photo would return the chosen photo to the caller.

          When a new screen opens, the previous screen is paused and put onto a history stack. The user can navigate backward through previously opened screens in the history. Screens can also choose to be removed from the history stack when it would be inappropriate for them to remain. Android retains history stacks for each application launched from the home screen.

          Intent and Intent Filters
          Android uses a special class called an Intent to move from screen to screen. An intent describes what an application wants done. The two most important parts of the intent data structure are the action and the data to act upon. Typical values for action are MAIN (the front door of the activity), VIEW, PICK, EDIT, etc. The data is expressed as a URI. For example, to view contact information for a person, you would create an intent with the VIEW action and the data set to a URI representing that person.

          There is a related class called an IntentFilter. While an intent is effectively a request to do something, an intent filter is a description of what intents an activity (or intent receiver, see below) is capable of handling. An activity that is able to display contact information for a person would publish an IntentFilter that said that it knows how to handle the action VIEW when applied to data representing a person. Activities publish their IntentFilters in the AndroidManifest.xml file.

          Navigating from screen to screen is accomplished by resolving intents. To navigate forward, an activity calls startActivity(myIntent). The system then looks at the intent filters for all installed applications and picks the activity whose intent filters best matches myIntent. The new activity is informed of the intent, which causes it to be launched. The process of resolving intents happens at run time when startActivity is called, which offers two key benefits:

          * Activities can reuse functionality from other components simply by making a request in the form of an Intent
          * Activities can be replaced at any time by a new Activity with an equivalent IntentFilter


          Intent Receiver
          You can use an IntentReceiver when you want code in your application to execute in reaction to an external event, for example, when the phone rings, or when the data network is available, or when it's midnight. Intent receivers do not display a UI, although they may use the NotificationManager to alert the user if something interesting has happened. Intent receivers are registered in AndroidManifest.xml, but you can also register them from code using Context.registerReceiver(). Your application does not have to be running for its intent receivers to be called; the system will start your application, if necessary, when an intent receiver is triggered. Applications can also send their own intent broadcasts to others with Context.broadcastIntent().
          Service

          A Service is code that is long-lived and runs without a UI. A good example of this is a media player playing songs from a play list. In a media player application, there would probably be one or more activities that allow the user to choose songs and start playing them. However, the music playback itself should not be handled by an activity because the user will expect the music to keep playing even after navigating to a new screen. In this case, the media player activity could start a service using Context.startService() to to run in the background to keep the music going. The system will then keep the music playback service running until it has finished. (You can learn more about the priority given to services in the system by reading Lifecycle of an Android Application.) Note that you can connect to a service (and start it if it's not already running) with the Context.bindService() method. When connected to a service, you can communicate with it through an interface exposed by the service. For the music service, this might allow you to pause, rewind, etc.

          Content Provider
          Applications can store their data in files, an SQLite database, or any other mechanism that makes sense. A content provider, however, is useful if you want your application's data to be shared with other applications. A content provider is a class that implements a standard set of methods to let other applications store and retrieve the type of data that is handled by that content provider.

          To get more details on content providers, see Accessing Content Providers.

          posted @ 2008-10-07 16:22 LukeW 閱讀(274) | 評論 (0)編輯 收藏

          HTTP協議中的Tranfer-Encoding:chunked編碼解析

              當不能預先確定報文體的長度時,不可能在頭中包含Content-Length域來指明報文體長度,此時就需要通過Transfer-Encoding域來確定報文體長度。
              通常情況下,Transfer-Encoding域的值應當為chunked,表明采用chunked編碼方式來進行報文體的傳輸。chunked編碼是HTTP/1.1 RFC里定義的一種編碼方式,因此所有的HTTP/1.1應用都應當支持此方式。
              chunked編碼的基本方法是將大塊數據分解成多塊小數據,每塊都可以自指定長度,其具體格式如下(BNF文法):
              Chunked-Body   = *chunk            //0至多個chunk
                               last-chunk         //最后一個chunk
                               trailer            //尾部
                               CRLF               //結束標記符

             chunk          = chunk-size [ chunk-extension ] CRLF  
                                  chunk-data CRLF
             chunk-size     = 1*HEX
             last-chunk     = 1*("0") [ chunk-extension ] CRLF

             chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
             chunk-ext-name = token
             chunk-ext-val  = token | quoted-string
             chunk-data     = chunk-size(OCTET)
             trailer        = *(entity-header CRLF)     
             
              解釋:
              Chunked-Body表示經過chunked編碼后的報文體。報文體可以分為chunk, last-chunk,trailer和結束符四部分。chunk的數量在報文體中最少可以為0,無上限;每個chunk的長度是自指定的,即,起始的數 據必然是16進制數字的字符串,代表后面chunk-data的長度(字節數)。這個16進制的字符串第一個字符如果是“0”,則表示chunk- size為0,該chunk為last-chunk,無chunk-data部分。可選的chunk-extension由通信雙方自行確定,如果接收者 不理解它的意義,可以忽略。
              trailer是附加的在尾部的額外頭域,通常包含一些元數據(metadata, meta means "about information"),這些頭域可以在解碼后附加在現有頭域之后。
              實例分析:
              下面分析用ethereal抓包使用Firefox與某網站通信的結果(從頭域結束符后開始):
          Address  0..........................  f
          000c0                                31
          000d0    66 66 63 0d 0a ...............   // ASCII碼:1ffc"r"n, chunk-data數據起始地址為000d5
                   很明顯,“1ffc”為第一個chunk的chunk-size,轉換為int為8188.由于1ffc后馬上就是
                   CRLF,因此沒有chunk-extension.chunk-data的起始地址為000d5, 計算可知下一塊chunk的起始
                   地址為000d5+1ffc + 2=020d3,如下:
          020d0    .. 0d 0a 31 66 66 63 0d 0a .... // ASCII碼:"r"n1ffc"r"n
                   前一個0d0a是上一個chunk的結束標記符,后一個0d0a則是chunk-size和chunk-data的分隔符。
                   此塊chunk的長度同樣為8188, 依次類推,直到最后一塊
          100e0                          0d 0a 31
          100f0    65 61 39 0d 0a......            //ASII碼:"r"n"1ea9"r"n
                   此塊長度為0x1ea9 = 7849, 下一塊起始為100f5 + 1ea9 + 2 = 11fa0,如下:
          100a0    30 0d 0a 0d 0a                  //ASCII碼:0"r"n"r"n
                   “0”說明當前chunk為last-chunk, 第一個0d 0a為chunk結束符。第二個0d0a說明沒有trailer部分,整個Chunk-body結束。
              解碼流程:
              對chunked編碼進行解碼的目的是將分塊的chunk-data整合恢復成一塊作為報文體,同時記錄此塊體的長度。
              RFC2616中附帶的解碼流程如下:(偽代碼)
              length := 0         //長度計數器置0
              read chunk-size, chunk-extension (if any) and CRLF      //讀取chunk-size, chunk-extension
                                                                    //和CRLF
              while(chunk-size > 0 )   {            //表明不是last-chunk
                    read chunk-data and CRLF            //讀chunk-size大小的chunk-data,skip CRLF
                    append chunk-data to entity-body     //將此塊chunk-data追加到entity-body后
                    read chunk-size and CRLF          //讀取新chunk的chunk-size 和 CRLF
              }
              read entity-header      //entity-header的格式為name:valueCRLF,如果為空即只有CRLF
              while (entity-header not empty)   //即,不是只有CRLF的空行
              {
                 append entity-header to existing header fields
                 read entity-header
              }
              Content-Length:=length      //將整個解碼流程結束后計算得到的新報文體length
                                           //作為Content-Length域的值寫入報文中
              Remove "chunked" from Transfer-Encoding  //同時從Transfer-Encoding中域值去除chunked這個標記
              length最后的值實際為所有chunk的chunk-size之和,在上面的抓包實例中,一共有八塊chunk-size為0x1ffc(8188)的chunk,剩下一塊為0x1ea9(7849),加起來一共73353字節。
              注:對于上面例子中前幾個chunk的大小都是8188,可能是因為:"1ffc" 4字節,""r"n"2字節,加上塊尾一個""r"n"2字節一共8字節,因此一個chunk整體為8196,正好可能是發送端一次TCP發送的緩存大小。

          posted @ 2008-09-24 18:03 LukeW 閱讀(2960) | 評論 (2)編輯 收藏

          HTTP Connections

          HTTP Connections
          最近初涉網絡編程,分析了下HTTP協議,下面為第一篇關于HTTP連接控制方面的學習日志,主要參考RFC2616,肯定有疏漏之處,還望指出。
          HTTP協議是位于傳輸層之上的應用層協議,其網絡層基礎通常是TCP協議。TCP協議是面向連接和流的,因此連接的狀態和控制對于HTTP協議而言相當重要。同時,HTTP是基于報文的,因此如何確定報文長度也是協議中比較重要的一點。
          Persistent Connections持久連接
          目的
              在使用持久連接前,HTTP協議規定為獲取每個URL資源都需要使用單獨的一個TCP連接,這增加了HTTP服務端的負載,引起互聯網擁塞。例如內嵌圖片以及其他類似數據的使用要求一個客戶端在很短時間內向同一個服務端發起多個請求。
          使用持久連接的優點:
          減少TCP連接數量
          在一個連接上實現HTTP請求和應答的流水,即允許客戶端發出多個請求,而不必在接收到前一請求的應答后才發出下一請求,極大減少時間消耗
          后續請求延遲減少,無需再在TCP握手上耗時
          可以更加優雅地實現HTTP協議,由于持續連接的存在無需報告錯誤后無需關閉連接,因此客戶端可使用最新的協議特性發出請求,如果接收到表示錯誤的應答,則換用更舊的語義。

          總體描述
          HTTP/1.1和之前版本的顯著區別是HTTP/1.1默認使用持久連接。即,除非服務端在應答中明確指出,客戶端應當假定服務端會維持一個持久連接,即使從服務端收到的應答是報告錯誤。
          持 久連接對關閉TCP連接的行為提供信號量機制支持。這個信號量是在HTTP頭中的Connection域設置,注意Client向Proxy發出請求時該 域可能被Proxy-Connection域替換。一旦close信號被表明,客戶端絕不能再通過該連接發送更多的請求。

          協商(Negotiation)
          HTTP/1.1 服務端可以假定HTTP/1.1客戶端會維持持久連接,除非請求中Connection域的值是"close".同樣的,如果服務端打算在送出應答后立即 關閉連接,它應當在應答中包含同樣的Connection域。(TCP連接關閉是雙向的,此時TCP進入半關閉狀態)
          同樣的,HTTP/1.1客戶端可以期望連接是持久的,除非如前所述收到表示連接關閉的應答。當然,也可以主動發出一個包含Connection:close的請求以表明終止連接。
          無論客戶端還是服務端發出的報文包含Connection:close,則該請求均為連接上的最后一個請求(服務端發出此應答后關閉,因此不可能接收更多的請求)
          報文傳輸長度
              為保證持久性,連接上的報文都必須有一個自定義的報文傳輸長度(否則必須通過連接的關閉表示報文結束,因為TCP連接是面向流的),確定的規則按優先級由高到低排列如下:
              報文傳輸長度指報文中出現的報文體的長度(即,不包括頭長度,因為報文頭的結束可通過連續兩個CRLF確定)
          1.任何絕不能包含報文體(如1xx,204,304)的應答消息總是以頭域后的第一個空行結束,無視頭中所有的entity類型域的設置,包括Content-Length域。
          2.Transfer-Encoding域出現,其值為除"identify"以外的其他值,則用"chunked"傳輸編碼方式確定傳輸長度,具體方式留待下篇分析。
          3.Content- Length域出現,且Transfer-Encoding域未出現(出現則忽略Content-Length域)。Content-Length域的值 為十進制數的字節序,如Content-Length:1234,則1、2、3、4是分別作為一個octet傳輸的,因此需要atoi轉換成數值。
          4.如果報文使用了"multipart/byteranges"的媒體類型,且沒對傳輸長度做前面的指明,則這種自分割的媒體類型定義了傳輸長度。具體參見Range頭域的說明。
          5.服務端關閉連接(此方法不可用于客戶端發出的請求報文,因為客戶端關閉連接則使得服務端無法發送應答).
              為保持和HTTP/1.0的兼容性, 包含報文體的HTTP/1.1請求必須包含合法的Content-Length頭域,除非明確知道服務端是HTTP/1.1兼容的.如果請求包含消息體, 而沒有Content-Length域,那么如果服務端無法確定消息長度時,它會返回400(無效請求),或者堅持獲取合法Content-Length 而返回411(要求包含長度).

              所有接收實體的HTTP/1.1應用程序必須接受"chunked"傳輸編碼, 這樣允許當報文長度無法預先確定時可以運用此機制獲取報文長度.
              報文不能同時包含Content-Length頭域和非"identity" Transfer-Encoding.如果出現了, Content-Length域必須被忽略.
              當Content-Length域在允許報文體的報文中存在時, 其域值必須嚴格等于消息體中的8比特字節.HTTP/1.1 user agent 必須在接收并檢測到一個錯誤的長度時提醒用戶.
              以上方法中,最常見的還是使用Content-Length域表示報文體長度,Transfer-Encoding需要按格式解碼才能還原出發送編碼前的報文。

          流水
              支持持久連接的客戶端可以流水發送請求,服務端必須按發送的順序發送應答。
              假定持久連接和連接后即可流水的客戶端應當做好在第一次流水失敗后重新嘗試此連接。在這樣的嘗試中,在確定連接是持久的之前,客戶端不能再流水。
              客戶端同樣必須準備好在服務端送回所有相關應答前就關閉連接時重發請求。
              不應流水non-idempotent方法

          Proxy Servers
              對于代理服務端而言,正確實現Connection頭域指定的屬性尤為重要。
              代理服務端必須分立通告它的客戶端和連接的原始服務端持久連接的屬性,每個持久連接設置僅針對一個傳輸連接。
             
          實踐考量
              超時值,服務端通常會為每個連接維護一個定時器,一旦某個連接不活躍超過一定時間值,服務端會關閉此連接。考慮到一個客戶端可能通過代理服務端發出更多連接,代理服務端通常會將超時值設置得更高。
              還有一些關于從異步關閉中恢復的討論。

          報文傳輸要求
              使用TCP流控制來解決服務端臨時負載過高問題,而不是簡單的依賴客戶端重連而關閉連接。
              監視連接情況以獲取錯誤狀態消息
              關于使用100(繼續)狀態碼
              100狀態碼用于客戶端發送請求體之前測試是否可以發送該請求,對于Proxy,有以下要求:
          1.如果代理服務端接收到包含Expect頭域值為"100-continue"的請求, 而不明確知道下一跳服務不支持HTTP/1.1以上版本, 則它必須轉發這個請求, 包括Expect頭域.
          2.如果代理知道下一跳服務端為HTTP/1.0或者更低版本, 則它不能轉發此請求, 且必須以407應答客戶端.
          3.如果明確知道發出請求的客戶端版本為HTTP/1.0或者更低,則代理服務端絕不能轉發100應答,這條規則凌駕于轉發1xx應答的一般準則.

          Connection頭域說明
          BNF文法:
              Connection = "Connection" ":" 1#(connection-token)
              connection-token  = token
             
          Connection頭域中的token用于指定對于特定連接有意義的選項,因此proxy在轉發前要掃描此域,從頭中去除和token同名的域。例如Connection:Range,則要去掉Range域。
              HTTP/1.1定義了close這個token,發送者用此token表示在完成這個報文所屬請求/應答的收發后連接將關閉。


          posted @ 2008-09-24 18:01 LukeW 閱讀(552) | 評論 (1)編輯 收藏

          關于斷點續傳的調研

          一些討論:
          http://topic.csdn.net/t/20061214/22/5231907.html

          posted @ 2008-09-24 17:57 LukeW 閱讀(221) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 客服| 宜君县| 卓尼县| 景德镇市| 楚雄市| 增城市| 济阳县| 宕昌县| 上林县| 贡嘎县| 噶尔县| 淳安县| 渝中区| 旺苍县| 肇庆市| 蕲春县| 肇州县| 泽州县| 海林市| 临城县| 忻州市| 康马县| 常宁市| 平顶山市| 新绛县| 乡城县| 淮安市| 奉化市| 陇川县| 南宁市| 武邑县| 织金县| 奈曼旗| 娄底市| 曲周县| 塔河县| 平顶山市| 平南县| 绵竹市| 武定县| 革吉县|