Look into it ~

present
随笔 - 32, 文章 - 0, 评论 - 3, 引用 - 0
数据加载中……

2008年11月4日

android软件

    只有注册用户登录后才能阅读该文。阅读全文

posted @ 2008-11-20 16:24 LukeW 阅读(33) | 评论 (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 阅读(177) | 评论 (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 阅读(122) | 评论 (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 阅读(647) | 评论 (0)编辑 收藏

点子

    只有注册用户登录后才能阅读该文。阅读全文

posted @ 2008-11-06 18:17 LukeW 阅读(41) | 评论 (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 阅读(371) | 评论 (0)编辑 收藏