Look into it ~

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

          2008年11月4日

          android軟件

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

          posted @ 2008-11-20 16:24 LukeW 閱讀(37) | 評論 (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 閱讀(194) | 評論 (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 閱讀(137) | 評論 (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 閱讀(661) | 評論 (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 閱讀(382) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 正阳县| 洛扎县| 常德市| 白银市| 镇沅| 武乡县| 蒙阴县| 丹江口市| 赤水市| 正镶白旗| 沂源县| 浦北县| 黄陵县| 平利县| 疏附县| 大荔县| 石渠县| 马龙县| 乌鲁木齐县| 三都| 罗城| 盐池县| 雷山县| 石狮市| 廊坊市| 台江县| 营山县| 淳安县| 略阳县| 铁岭县| 周至县| 柏乡县| 平乐县| 突泉县| 华坪县| 宜君县| 瓮安县| 保山市| 教育| 伊通| 闽清县|