redhat编译内核( 转载)


在Linux内核中,包括了进程管理 (process management)、定时器(timer)、中断管理(interrupt management)、内存管理(memory management)、模块管理(module management)、虚拟文件系统接口(VFS layer)、文件系统(file system)、设备驱动程序(device driver)、进程间通信(inter-process communication)、网络管理(network management)、系统启动(system init)等操作系统功能的实现。
    新内核可以在http://www.kernel.org下载。

先把linux-2.6.18.2.tar.bz2 复制到/usr/src/ 的下面

tar jxvf  linux-2.6.18.2.tar.bz2

cd linux-2.6.18.2

 

make mrproper 把原来编译产生的垃圾删除

 

配置内核可以根据需要与爱好使用下面命令中的一个:

make config (基于文本的最为传统的配置界面)

make menuconfig (基于文本选单的配置界面)

make xconfig (基于图形窗口模式的配置界面)

make oldconfig (如果只想在原来内核配置的基础上修改一些小地方,会省去不少麻烦)

 

进行配置时,大部分选项可以使用其缺省值,只有小部分需要根据用户不同的需要选择。例如,如果需要内核支持DOS分区的文件系统,则要在文件系统部分选择FATDOS系统支持;系统如果配有网卡、PCMCIA卡等,需要在网络配置中选择相应卡的类型。

                          

选择相应的配置时,有三种选择,它们分别代表的含义如下:

                          

 Y”- 将该功能编译进内核

                          

 N”- 不将该功能编译进内核

                          

 M”- 将该功能编译成可以在需要时动态插入到内核中的模块。

                          

    将与核心其它部分关系较远且不经常使用的部分功能代码编译成为可加载模块,有利于减小内核的长度,减小内核消耗的内存,简化该功能相应的环境改变时对内核的影响。许多功能都可以这样处理,例如像上面提到的网卡的支持、对FAT等文件系统的支持。

                          

其实现在编译内核最关键的地方就是配置内核。我一般用make menuconfig配置内核。

配置2.6.0内核时如果你的主板是Intel芯片的话,你用默认配制也许就可以得到一个满意的内核哦。做法是make  menuconfig后离开时选择保存。

这里的难点是pci,如果你硬盘是IDE的那一定要选择好你主板上南桥芯片。SCSI的话就是要选择上你的SCSI卡型号。

还有就是网卡,声卡芯片的型号了,他们的型号你都可以用lspci 查找到比如我的是。

 

[root@leo boot]# lspci

00:00.0 Host bridge: Intel Corp. 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01)

00:01.0 PCI bridge: Intel Corp. 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (rev 01)

00:07.0 ISA bridge: Intel Corp. 82371AB/EB/MB PIIX4 ISA (rev 0 8)

00:07.1 IDE interface: Intel Corp. 82371AB/EB/MB PIIX4 IDE (rev 01)

00:07.2 USB Controller: Intel Corp. 82371AB/EB/MB PIIX4 USB

00:07.3 Bridge: Intel Corp. 82371AB/EB/MB PIIX4 ACPI (rev 0 8)

00:0f.0 VGA compatible controller: VMware Inc [VMware SVGA II] PCI Display Adapter

00:10.0 SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)

00:11.0 Ethernet controller: Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE] (rev 10)

00:12.0 Multimedia audio controller: Ensoniq ES1371 [AudioPCI-97] (rev 02)

 

编译配置

在这一部分涉及几个重要模块的配置请,特别注意.一般用"make menuconfig"命令来配置内核.

输入以上命令后出现一个菜单界面,用户可以对需要的模块.下面着重讲几个重要的配置

1)文件系统

请务必要选中ext3文件系统,

  File systems--->

  [*] Ext3 journalling file system support

  [*] Ext3 Security Labels

  [*] JBD (ext3) debugging support

  以上三项一定要选上,而且要内建(即标*). 这个非常重要,在配置完后一定要检查一下.config文件有没有"CONFIG_EXT3_FS=y"这一项如果不是"CONFIG_EXT3_FS=y"而是"CONFIG_EXT3_FS=m",你在运行内核时就会遇上以下错误: pivotroot: pivot_root(/sysroot,/sysroot/initrd) failed

  

2)网卡驱动

  请务必把自己网卡对应的驱动编译进内核,比较普遍的网卡是realtek 8139,以下就是这种网卡的配置,以供参考

  Device Drivers--->

  Networking support--->

  Ethernet (10 or 100Mbit) --->

  <*> RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)

  <*> RealTek RTL-8139 PCI Fast Ethernet Adapter support

3)声卡驱动

  也要选择自己声卡对应的驱动编译进内核,比较普遍的声卡是i810_audio,以下就是这种声卡的配置,以供参考

  Device Drivers --->

  Sound --->

  <*> Sound card support

  Advanced Linux Sound Architecture --->

  <*> Advanced Linux Sound Architecture

  <*> Sequencer support

  < > Sequencer dummy client

  <*> OSS Mixer API

  <*> OSS PCM (digital audio) API[*] OSS Sequencer API

  <*> RTC Timer support

  PCI devices --->

  <*> Intel i8x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111

  Open Sound System --->

  < > Open Sound System (DEPRECATED)

以上三项配置关系到新内核能否正常运行,请备加注意.其他的配置如果不是很了解,大可以按默认的选择.

 

make dep (确保关键文件在正确的位置) 2.5.*-2.6.0都不需要了。其实2.4.*某些内核也不需要了。

                          

make clean (确保所有有关文件都处于最新版本状态)

                          

make zImage (编译压缩形式的内核)

                          

在需要内核支持较多的外设和功能时,内核可能变得很大,此时可以编译大内核:

                          

make bzImage

                          

编译的时间与机器的硬件条件及内核的配置等因素有关,所获得的内核的位置在/usr/src/linux/arch/i386/boot目录下,当然这里假设用户的CPUx86型的。

                          

如果选择了可加载模块,编译完内核后,要对选择的模块进行编译:

                          

make modules (编译选择的模块)

                          

make module_install (将编译后的模块转移到系统标准位置)

 

# make install

 

上面的命令"make install":

 (1)把压缩内核映象拷贝到/boot目录下并创建相应的System.map符号链接

 (2)修改bootloader的配置文件;

 (3)调用mkinitrd程序创建内核的initrd映象对于GRUB而言将在/boot/grub/grub.conf配置文件增加如下类似的配置行:

 

      title Red Hat Linux (2.***)

      root(hd0, 1)

      kernel /boot/vmlinuz-2.*** ro root=LABEL=/

      initrd /boot/initrd-2.***.img

                          

模块在系统中的标准目录位于/lib/modules/x.y.z,后面的x.y.z是版本号,为安全起见,在运行#make  modules_install之前最好对/lib/modules进行备份。模块通常是带有扩展名.o的文件,使用命令lsmod可以对当前内核的模块进行列表。

                          

我一般是make bzImagemake modulesmake module_install; make install

                          

运行新内核之前,请检查一下/boot/grub/grub.conf的内容,下面的配置可作参考

# grub.conf generated by anaconda

#

# Note that you do not have to rerun grub after making changes to this file

# NOTICE:  You have a /boot partition.  This means that

#          all kernel and initrd paths are relative to /boot/, eg.

#          root (hd0,0)

#          kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00

#          initrd /initrd-version.img

#boot=/dev/hda

default=0

timeout=5

splashimage=(hd0,0)/grub/splash.xpm.gz

hiddenmenu

title Fedora Core (2.6.18.2)

        root (hd0,0)

        kernel /vmlinuz-2.6.18.2 ro root=/dev/VolGroup00/LogVol00 rhgb quiet

        initrd /initrd-2.6.18.2.img

title Fedora Core (2.6.18-1.2798.fc6)

        root (hd0,0)

        kernel /vmlinuz-2.6.18-1.2798.fc6 ro root=/dev/VolGroup00/LogVol00 rhgb quiet

        initrd /initrd-2.6.18-1.2798.fc6.img

 

现在重启机器,即可测试最新的内核。

Leave a comment

Linux 下串口编程入门

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍。

串口简介

串 行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换 接口玉枕纱厨技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺。

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍,如果要非常深入了解,建议看看本文所参考的 《Serial Programming Guide for POSIX Operating Systems》

计算机串口的引脚说明

序号 信号名称 符号 流向 功能
2 发送数据 TXD DTE→DCE DTE发送串行数据
3 接收数据 RXD DTE←DCE DTE 接收串行数据
4 请求发送 RTS DTE→DCE DTE 请求 DCE 将线路切换到发送方式
5 允许发送 CTS DTE←DCE DCE 告诉 DTE 线路已接通可以发送数据
6 数据设备准备好 DSR DTE←DCE DCE 准备好
7 信号地        信号公共地
8 载波检测 DCD DTE←DCE 表示 DCE 接收到远程载波
20 数据终端准备好 DTR DTE→DCE DTE 准备好
22 振铃指示 RI DTE←DCE 表示 DCE 与线路接通,出现振铃


回页首

串口操作

串口操作需要的头文件

#include     <stdio.h>      /*标准输入输出定义*/
#include     <stdlib.h>     /*标准函数库定义*/
#include     <unistd.h>     /*Unix 标准函数定义*/
#include     <sys/types.h>
#include     <sys/stat.h>
#include     <fcntl.h>      /*文件控制定义*/
#include     <termios.h>    /*PPSIX 终端控制定义*/
#include     <errno.h>      /*错误号定义*/


回页首

打开串口

在 Linux 下串口文件是位于 /dev 下的

串口一 为 /dev/ttyS0

串口二 为 /dev/ttyS1

打开串口是通过使用标准的文件打开函数操作:

int fd;<br />/*以读写方式打开串口*/<br />fd = open( "/dev/ttyS0", O_RDWR);<br />if (-1 == fd){ <br />/* 不能打开串口一*/ <br />perror(" 提示错误!");<br />}<br />


回页首

设置串口

最基本的设置串口包括波特率设置,效验位和停止位设置。

串口的设置主要是设置 struct termios 结构体的各成员值。

struct termio<br />{     unsigned short  c_iflag;        /* 输入模式标志 */    <br />    unsigned short  c_oflag;                /* 输出模式标志 */    <br />    unsigned short  c_cflag;                /* 控制模式标志*/     <br />    unsigned short  c_lflag;                /* local mode flags */  <br />    unsigned char  c_line;              /* line discipline */       <br />    unsigned char  c_cc[NCC];    /* control characters */<br />};<br />

设置这个结构体很复杂,我这里就只说说常见的一些设置:

波特率设置

下面是修改波特率的代码:

struct  termios Opt;<br />tcgetattr(fd, &Opt);<br />cfsetispeed(&Opt,B19200);     /*设置为19200Bps*/<br />cfsetospeed(&Opt,B19200);<br />tcsetattr(fd,TCANOW,&Opt);<br />

设置波特率的例子函数:

/**<br />*@brief  设置串口通信速率<br />*@param  fd     类型 int  打开串口的文件句柄<br />*@param  speed  类型 int  串口速度<br />*@return  void<br />*/<br />int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,<br />                                     B38400, B19200, B9600, B4800, B2400, B1200, B300, };<br /><!-- code sample is too wide -->int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300, 38400,  <br />                                   19200,  9600, 4800, 2400, 1200,  300, };<br />void set_speed(int fd, int speed){<br />      int   i; <br />   int   status; <br />      struct termios   Opt;<br />       tcgetattr(fd, &Opt); <br />   for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) { <br />               if  (speed == name_arr[i]) {     <br />                   tcflush(fd, TCIOFLUSH);     <br />                        cfsetispeed(&Opt, speed_arr[i]);  <br />                      cfsetospeed(&Opt, speed_arr[i]);   <br />                     status = tcsetattr(fd1, TCSANOW, &Opt);  <br />                       if  (status != 0) {        <br />                         perror("tcsetattr fd1");  <br />                          return;     <br />                        }    <br />                       tcflush(fd,TCIOFLUSH);   <br />           }  <br /> }<br />}<br />

效验位和停止位的设置:

无效验 8位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS8;
奇效验(Odd) 7位 Option.c_cflag |= ~PARENB;
Option.c_cflag &= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;
偶效验(Even) 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag |= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;
Space效验 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= &~CSIZE;
Option.c_cflag |= CS8;

设置效验的函数:

/**<br />*@brief   设置串口数据位,停止位和效验位<br />*@param  fd     类型  int  打开的串口文件句柄<br />*@param  databits 类型  int 数据位   取值 为 7 或者8<br />*@param  stopbits 类型  int 停止位   取值为 1 或者2<br />*@param  parity  类型  int  效验类型 取值为N,E,O,,S<br />*/<br />int set_Parity(int fd,int databits,int stopbits,int parity)<br />{ <br /> struct termios options; <br />    if  ( tcgetattr( fd,&options)  !=  0) { <br />                perror("SetupSerial 1");     <br />               return(FALSE);  <br />    }<br />   options.c_cflag &= ~CSIZE; <br />     switch (databits) /*设置数据位数*/<br />        {   <br />        case 7:         <br />            options.c_cflag |= CS7; <br />            break;<br />      case 8:     <br />                options.c_cflag |= CS8;<br />             break;   <br />   default:    <br />                fprintf(stderr,"Unsupported data size\n"); return (FALSE);  <br />        }<br />switch (parity) <br />{   <br />       case 'n':<br />   case 'N':    <br />               options.c_cflag &= ~PARENB;   /* Clear parity enable */<br />         options.c_iflag &= ~INPCK;     /* Enable parity checking */ <br />            break;  <br />    case 'o':   <br />        case 'O':     <br />              options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/  <br />         options.c_iflag |= INPCK;             /* Disnable parity checking */ <br />               break;  <br />    case 'e':  <br /> case 'E':   <br />                options.c_cflag |= PARENB;     /* Enable parity */    <br />              options.c_cflag &= ~PARODD;   /* 转换为偶效验*/     <br />          options.c_iflag |= INPCK;       /* Disnable parity checking */<br />              break;<br />      case 'S': <br />  case 's':  /*as no parity*/   <br />          options.c_cflag &= ~PARENB;<br />         options.c_cflag &= ~CSTOPB;break;  <br />     default:   <br />         fprintf(stderr,"Unsupported parity\n");    <br />         return (FALSE);  <br />   }  <br />/* 设置停止位*/  <br />switch (stopbits)<br />{   <br />    case 1:    <br />         options.c_cflag &= ~CSTOPB;  <br />           break;  <br />    case 2:    <br />         options.c_cflag |= CSTOPB;  <br />           break;<br />   default:    <br />                 fprintf(stderr,"Unsupported stop bits\n");  <br />                return (FALSE); <br />} <br />/* Set input parity option */ <br />if (parity != 'n')   <br />  options.c_iflag |= INPCK; <br />tcflush(fd,TCIFLUSH);<br />options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/   <br />options.c_cc[VMIN] = 0; /* Update the options and do it NOW */<br />if (tcsetattr(fd,TCSANOW,&options) != 0)   <br />{ <br /> perror("SetupSerial 3");   <br /> return (FALSE);  <br />} <br />return (TRUE);  <br />}<br />

需要注意的是:

如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理,那么使用原始模式(Raw Mode)方式来通讯,设置方式如下:

options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/<br />options.c_oflag  &= ~OPOST;   /*Output*/<br />


回页首

读写串口

设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。

  • 发送数据
    char  buffer[1024];int    Length;int    nByte;nByte = write(fd, buffer ,Length)<br />
    
  • 读取串口数据

    使用文件操作read函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数。

    可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作。

    char  buff[1024];int    Len;int  readByte = read(fd,buff,Len);<br />
    


回页首

关闭串口

关闭串口就是关闭文件。

close(fd);<br />


回页首

例子

下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件

/**********************************************************************代码说明:使用串口二测试的,发送的数据是字符,<br /><!-- code sample is too wide -->但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号。我测试使用的是单片机发送数据到第二个串口,测试通过。<br />**********************************************************************/<br />#define FALSE  -1<br />#define TRUE   0<br />/*********************************************************************/<br />int OpenDev(char *Dev)<br />{<br />       int     fd = open( Dev, O_RDWR );         //| O_NOCTTY | O_NDELAY       <br />    if (-1 == fd)   <br />    {                       <br />            perror("Can't Open Serial Port");<br />           return -1;              <br />    }       <br />    else    <br />            return fd;<br />}<br />int main(int argc, char **argv){<br /> int fd;<br />     int nread;<br />  char buff[512];<br />     char *dev  = "/dev/ttyS1"; //串口二<br />    fd = OpenDev(dev);<br />  set_speed(fd,19200);<br />        if (set_Parity(fd,8,1,'N') == FALSE)  {<br />             printf("Set Parity Error\n");<br />               exit (0);<br />   }<br />while (1) //循环读取数据<br />{   <br />     while((nread = read(fd, buff, 512))>0)<br />   { <br />          printf("\nLen %d\n",nread); <br />                buff[nread+1] = '\0';   <br />            printf( "\n%s", buff);   <br />   }<br />}<br />      //close(fd);  <br />      // exit (0);<br />}<br />
Leave a comment

Linux 下串口编程入门

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍。

串口简介

串 行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换 接口玉枕纱厨技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺。

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍,如果要非常深入了解,建议看看本文所参考的 《Serial Programming Guide for POSIX Operating Systems》

计算机串口的引脚说明

序号 信号名称 符号 流向 功能
2 发送数据 TXD DTE→DCE DTE发送串行数据
3 接收数据 RXD DTE←DCE DTE 接收串行数据
4 请求发送 RTS DTE→DCE DTE 请求 DCE 将线路切换到发送方式
5 允许发送 CTS DTE←DCE DCE 告诉 DTE 线路已接通可以发送数据
6 数据设备准备好 DSR DTE←DCE DCE 准备好
7 信号地        信号公共地
8 载波检测 DCD DTE←DCE 表示 DCE 接收到远程载波
20 数据终端准备好 DTR DTE→DCE DTE 准备好
22 振铃指示 RI DTE←DCE 表示 DCE 与线路接通,出现振铃


回页首

串口操作

串口操作需要的头文件

#include     <stdio.h>      /*标准输入输出定义*/
#include     <stdlib.h>     /*标准函数库定义*/
#include     <unistd.h>     /*Unix 标准函数定义*/
#include     <sys/types.h>
#include     <sys/stat.h>
#include     <fcntl.h>      /*文件控制定义*/
#include     <termios.h>    /*PPSIX 终端控制定义*/
#include     <errno.h>      /*错误号定义*/


回页首

打开串口

在 Linux 下串口文件是位于 /dev 下的

串口一 为 /dev/ttyS0

串口二 为 /dev/ttyS1

打开串口是通过使用标准的文件打开函数操作:

int fd;<br />/*以读写方式打开串口*/<br />fd = open( "/dev/ttyS0", O_RDWR);<br />if (-1 == fd){ <br />/* 不能打开串口一*/ <br />perror(" 提示错误!");<br />}<br />


回页首

设置串口

最基本的设置串口包括波特率设置,效验位和停止位设置。

串口的设置主要是设置 struct termios 结构体的各成员值。

struct termio<br />{     unsigned short  c_iflag;        /* 输入模式标志 */    <br />    unsigned short  c_oflag;                /* 输出模式标志 */    <br />    unsigned short  c_cflag;                /* 控制模式标志*/     <br />    unsigned short  c_lflag;                /* local mode flags */  <br />    unsigned char  c_line;              /* line discipline */       <br />    unsigned char  c_cc[NCC];    /* control characters */<br />};<br />

设置这个结构体很复杂,我这里就只说说常见的一些设置:

波特率设置

下面是修改波特率的代码:

struct  termios Opt;<br />tcgetattr(fd, &Opt);<br />cfsetispeed(&Opt,B19200);     /*设置为19200Bps*/<br />cfsetospeed(&Opt,B19200);<br />tcsetattr(fd,TCANOW,&Opt);<br />

设置波特率的例子函数:

/**<br />*@brief  设置串口通信速率<br />*@param  fd     类型 int  打开串口的文件句柄<br />*@param  speed  类型 int  串口速度<br />*@return  void<br />*/<br />int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,<br />                                     B38400, B19200, B9600, B4800, B2400, B1200, B300, };<br /><!-- code sample is too wide -->int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300, 38400,  <br />                                   19200,  9600, 4800, 2400, 1200,  300, };<br />void set_speed(int fd, int speed){<br />      int   i; <br />   int   status; <br />      struct termios   Opt;<br />       tcgetattr(fd, &Opt); <br />   for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) { <br />               if  (speed == name_arr[i]) {     <br />                   tcflush(fd, TCIOFLUSH);     <br />                        cfsetispeed(&Opt, speed_arr[i]);  <br />                      cfsetospeed(&Opt, speed_arr[i]);   <br />                     status = tcsetattr(fd1, TCSANOW, &Opt);  <br />                       if  (status != 0) {        <br />                         perror("tcsetattr fd1");  <br />                          return;     <br />                        }    <br />                       tcflush(fd,TCIOFLUSH);   <br />           }  <br /> }<br />}<br />

效验位和停止位的设置:

无效验 8位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS8;
奇效验(Odd) 7位 Option.c_cflag |= ~PARENB;
Option.c_cflag &= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;
偶效验(Even) 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag |= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;
Space效验 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= &~CSIZE;
Option.c_cflag |= CS8;

设置效验的函数:

/**<br />*@brief   设置串口数据位,停止位和效验位<br />*@param  fd     类型  int  打开的串口文件句柄<br />*@param  databits 类型  int 数据位   取值 为 7 或者8<br />*@param  stopbits 类型  int 停止位   取值为 1 或者2<br />*@param  parity  类型  int  效验类型 取值为N,E,O,,S<br />*/<br />int set_Parity(int fd,int databits,int stopbits,int parity)<br />{ <br /> struct termios options; <br />    if  ( tcgetattr( fd,&options)  !=  0) { <br />                perror("SetupSerial 1");     <br />               return(FALSE);  <br />    }<br />   options.c_cflag &= ~CSIZE; <br />     switch (databits) /*设置数据位数*/<br />        {   <br />        case 7:         <br />            options.c_cflag |= CS7; <br />            break;<br />      case 8:     <br />                options.c_cflag |= CS8;<br />             break;   <br />   default:    <br />                fprintf(stderr,"Unsupported data size\n"); return (FALSE);  <br />        }<br />switch (parity) <br />{   <br />       case 'n':<br />   case 'N':    <br />               options.c_cflag &= ~PARENB;   /* Clear parity enable */<br />         options.c_iflag &= ~INPCK;     /* Enable parity checking */ <br />            break;  <br />    case 'o':   <br />        case 'O':     <br />              options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/  <br />         options.c_iflag |= INPCK;             /* Disnable parity checking */ <br />               break;  <br />    case 'e':  <br /> case 'E':   <br />                options.c_cflag |= PARENB;     /* Enable parity */    <br />              options.c_cflag &= ~PARODD;   /* 转换为偶效验*/     <br />          options.c_iflag |= INPCK;       /* Disnable parity checking */<br />              break;<br />      case 'S': <br />  case 's':  /*as no parity*/   <br />          options.c_cflag &= ~PARENB;<br />         options.c_cflag &= ~CSTOPB;break;  <br />     default:   <br />         fprintf(stderr,"Unsupported parity\n");    <br />         return (FALSE);  <br />   }  <br />/* 设置停止位*/  <br />switch (stopbits)<br />{   <br />    case 1:    <br />         options.c_cflag &= ~CSTOPB;  <br />           break;  <br />    case 2:    <br />         options.c_cflag |= CSTOPB;  <br />           break;<br />   default:    <br />                 fprintf(stderr,"Unsupported stop bits\n");  <br />                return (FALSE); <br />} <br />/* Set input parity option */ <br />if (parity != 'n')   <br />  options.c_iflag |= INPCK; <br />tcflush(fd,TCIFLUSH);<br />options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/   <br />options.c_cc[VMIN] = 0; /* Update the options and do it NOW */<br />if (tcsetattr(fd,TCSANOW,&options) != 0)   <br />{ <br /> perror("SetupSerial 3");   <br /> return (FALSE);  <br />} <br />return (TRUE);  <br />}<br />

需要注意的是:

如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理,那么使用原始模式(Raw Mode)方式来通讯,设置方式如下:

options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/<br />options.c_oflag  &= ~OPOST;   /*Output*/<br />


回页首

读写串口

设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。

  • 发送数据
    char  buffer[1024];int    Length;int    nByte;nByte = write(fd, buffer ,Length)<br />
    
  • 读取串口数据

    使用文件操作read函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数。

    可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作。

    char  buff[1024];int    Len;int  readByte = read(fd,buff,Len);<br />
    


回页首

关闭串口

关闭串口就是关闭文件。

close(fd);<br />


回页首

例子

下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件

/**********************************************************************代码说明:使用串口二测试的,发送的数据是字符,<br /><!-- code sample is too wide -->但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号。我测试使用的是单片机发送数据到第二个串口,测试通过。<br />**********************************************************************/<br />#define FALSE  -1<br />#define TRUE   0<br />/*********************************************************************/<br />int OpenDev(char *Dev)<br />{<br />       int     fd = open( Dev, O_RDWR );         //| O_NOCTTY | O_NDELAY       <br />    if (-1 == fd)   <br />    {                       <br />            perror("Can't Open Serial Port");<br />           return -1;              <br />    }       <br />    else    <br />            return fd;<br />}<br />int main(int argc, char **argv){<br /> int fd;<br />     int nread;<br />  char buff[512];<br />     char *dev  = "/dev/ttyS1"; //串口二<br />    fd = OpenDev(dev);<br />  set_speed(fd,19200);<br />        if (set_Parity(fd,8,1,'N') == FALSE)  {<br />             printf("Set Parity Error\n");<br />               exit (0);<br />   }<br />while (1) //循环读取数据<br />{   <br />     while((nread = read(fd, buff, 512))>0)<br />   { <br />          printf("\nLen %d\n",nread); <br />                buff[nread+1] = '\0';   <br />            printf( "\n%s", buff);   <br />   }<br />}<br />      //close(fd);  <br />      // exit (0);<br />}<br />
Leave a comment

嵌入式Linux系统的图形用户界面

  1. Qt/Embedded

  Qt是Trolltech公司发布的一个跨平台的C++图形界面应用程序框架。它实际上是一个类库, 里面包括了大量的可重用的类,其中既有按钮、窗口等这些可见类,也有定时器这样的不可见类和一些抽象类。Qt是完全面向对象,拥有良好的扩展性与稳定性, 并支持模块化编程。我们可以充分利用Qt高度面向对象和模块化的特征,从繁琐的X编程中解脱出来,专注于程序本身的内容,使Linux下窗口程序设计成为 一件非常轻松的事情。

  在Qt中,对象之间进行通信采用了一种被称作信号与槽(Signal-Slot)的方式,这是Qt的 重要特征之一。在MS-Windows中,程序通过消息队列和消息循环的方式进行消息的传递与事件的触发,而Qt的信号与槽机制采取了这样的方式:一个类 可以定义多个信号和多个槽,信号就好像是事件,而槽则是响应事件的方法,并且和一般的成员函数没有太大的区别。如果需要实现它们之间的通信时,就将某个类 的槽与某个类的信号连接起来,从而实现事件驱动。

  Qt/Embedded是Qt的嵌入式版本。因为Qt是KDE等项目使用的GUI库,所以有许多基于 Qt的X Window程序可以非常方便地移植到Qt/Embedded版本上。因此,自从Qt/Embedded以GPL条款形式发布以来,就有大量的嵌入式 Linux开发商转到了Qt/Embedded系统上。但是Qt/Embedded的问题是过于庞大,尽管Qt/Embedded声称可以裁剪到最少 630K,但这时的Qt/Embedded库已经基本上失去了使用价值。Qt/Embedded库目前主要针对手持式信息终端。因为对硬件加速支持匮乏, 很难应用到对图形速度、功能和效率要求较高的嵌入式系统中,比如机顶盒、游戏终端等。

  2. MicroWindows/NanoX

  MicroWindows是一个开源的项目,由美国Century Software公司主持开发。MicroWindows能够在没有任何操作系统或其他图形系统支持的情况下运行,它能对裸设备进行直接操作。这样 MicroWindows就显得十分小巧,便于移植到各种硬件和软件系统上。MicroWindows是分层设计的,这样便于用户按照自己的需求进行修 改、删减和增加。它分为三层:最底层是screen、mouse/touchpad和keyboard驱动程序,它们直接与显示和输入硬件打交道;中间层 是一个可移植的图形引擎层,它使用最底层提供的功能完成对画线、区域填充、文本、多边形、区域裁剪、色彩等的支持;最上层是API,提供给图形化程序调 用。目前,这些API支持Win32和NanoX接口。这样一来,它们就与Win32和X Window窗口系统保持了兼容,在这些系统间移植应用软件就要容易得多。

  该项目的主要特色在于提供了类似X的客户/服务器体系结构,并提供了相对完善的图形功能。

  3. MiniGUI

  MiniGui是国内的一个自由软件项目,目前,MiniGui由北京飞漫软件公司负责开发。 MiniGui有两个不同架构的版本。最初的MiniGui运行在PThread库之上,这个版本适合于功能单一的嵌入式系统,但存在系统健壮性不够的缺 点。在0.9.98版本中,引入了MiniGui-Lite版本,这个版本允许在不同的进程中创建应用程序,但同时只能有一个进程运行。

  MiniGui具有如下特点:

  (1)微客户/服务器结构:因为MiniGui客户/服务器体系在一个进程中实现,所以称之为微客户 /服务器结构。在MiniGui中,有一个线程,即服务器线程负责维护全局的窗口列表,而其他线程不能直接修改这些全局的数据结构。而是通过请求服务的模 式来完成。例如,当一个线程要求桌面线程创建一个窗口时,该线程通过向桌面线程发送消息,然后等待桌面线程的相应,由桌面线程完成请求的任务后再通知请求 线程这样一种方式来实现。

  (2)多线程多窗口:MiniGui的窗口包括:主窗口、子窗口、对话框、控件。MiniGui的主 窗口与附属主窗口对应于一个单独的线程,通过函数调用可建立主窗口以及对应的线程,每个线程都有一个消息队列,属于同一线程的所有主窗口从这一消息队列中 获取消息并由注册的窗口过程进行处理。

  (3)消息与消息循环:MiniGui是典型的消息驱动的系统。拥有单独线程与消息队列的窗口自创建后就处于消息循环中,读取消息队列中的消息并处理消息,直到接收到特定的消息为止。

  4. OpenGUI

  OpenGui在Linux系统上已经存在了很长的时间了。最初的名字叫FastGL,支持多种操作 系统平台,比如MS-DOS、QNX和Linux等,不过目前只支持x86硬件平台。OpenGui也分为三层。最底层是由汇编编写的快速图形引擎;中间 层提供了图形绘制API,包括线条、矩形、圆弧等;第三层用C++编写,提供了完整的GUI对象集。OpenGui比较适合于基于x86平台的实时系统, 可移植性稍差,目前的发展也基本停滞。

  综上所述,面向嵌入式Linux的GUI系统已经发展了很长时间,有些已经是比较成熟的产品了,同时 也得到了较为广泛的利用,例如Qt/Embedded目前已使用到了PDA和手机产品中,Motorola公司于2003年推出的手机产品中就使用了Qt /Embedded。而MicorWindows等轻量级的GUI系统在工控机、机顶盒等产品中也得以发挥其价值。

Leave a comment

一种基于嵌入式Linux图形用户接口的实现

随着Internet与网络的迅速发展 并向家庭领域不断扩展,使消费电子、计算机、通信(3C)一体化趋势日趋明显,嵌入式系统再度成为研究与应用的热点。嵌入式实 时Linux操作系统以价格低廉、功能强大又易于移植而正在被广泛采用,成为新兴的力量,如今随着WAP手机、PDA、机顶盒、及DVD/VCD播放机已 经迅速普及,用户对这些手持式设备的GUI提出了更高的要求,希望能看到像PC机才拥有的华丽美观的GUI。GUI已经成为了人与机器沟通的桥梁,嵌入式 系统对GUI的需求越来越高,而这一切均要求有一个轻型、占用资源少、高性能、高可靠、可配置及美观的GUI支持。

  1 Java的图形界面工具

  Java技术对于服务器,个人电脑和嵌入式系统来说是一项伟大的技术。由于其具有跨平台等特性。Java在服务器和 桌面电脑方面的应用是非常成功的。然而在GUI方面,Java只用非常有限的一些特征去构建图形用户界面。其思想就是采用平台无关的Java应用程序接口 打包到不同的操作系统来开发本地图形用户界面,被称之为抽象的窗口工具(AWT)。仅有普通的部件如文件域、文本区、选择框、单选按钮、列表框和按钮被 AWT支持,图形和图像的特性支持非常有限,也就是说,只足够构建简单的applet程序。认识到需要更高级的图形用户界面组件和图形能力,Sun公司开 发了Swing,Java 2D,Java3D,图像的输入/输出,以及Java高级图像(JAI)。Swing是用来构建Java图形界面的标准API(应用程序接口),一些 AWT类由Swing基础而来。它有一套完全的组件从按钮到文件域、表格、树型和文件编辑器。这些组件不依赖于操作系统本地的部件,而是用原始的图形像直 线、矩形、文字画出。这种画代表感观插件,它能够模仿本地的感观。SWT是基于Java开发的,它的设计理念是最大化了操作系统的图形构件的API,就是 说只要操作系统提供了相应图形的构件,那么SWT只是简单应用JNI技术调用它们,只有那些操作系统中不提供的构件,SWT才自己去做一个模拟的实现。另 外SWT还提供对操作系统本地图形用户界面的直接访问,因此,基于SWT的Java应用程序拥有本地的图形用户界面并且可以和本地别的应用程序和部件集成 在一起。使用SWT开发包,简单、跨平台、可靠等这些Jaya语言本身所具有的优点正渐渐融合到图形界面的应用程序开发中去。Java语言的另一扇成功之 门正在逐渐打开。

 2 SWT+GtkFB图形系统的体系结构

  2.1 SWT+GtkFB图形系统的体系结构

SWT

  2.1.1 SWT

  SWT处于体系机构的最上层,它与Java内的AwT和Swing同属于设计图形界面所需的高级函数库。而且SWT针对AWT 以及Swing的一些问题作了改善,如今它已发展成一套与作业系统无关的图形元件函数库。在元件的产生方面采用了适当的模拟,在基本的元件方面是采用原有 作业系统的,对于较复杂的元件才用仿真的技术。基于SWT的Java应用程序拥有本地的图形用户界面,并且可以和本地别的应用程序,以及部件集成在一起。

  SWT是基于Java语言开发出来的高级图形元件库,如图2所示SWT在Java端通过JNI(Java Native InteRFace)技术直接调用native端的GtkFB来使用操作系统的资源,JNI技术使得SWT程序可以与其他语言编写的Native端的代码 互相协作,将它们整合在一起;另一方面可使运行在JVM(JAava虚拟机)中的SWT代码调用GtkFB库函数或其他程序;此外利用 Invocation API,可将Java虚拟机嵌入到native端的应用中。JNI这个接口是双向的,相当于桥梁和纽带,它将SWT代码和native端的GtkFB代码 连接起来。

SWT在Java端通过JNI(Java Native Interface)技术直接调用native端的GtkFB来使用操作系统的资源

  2.1.2 Gtk库

  如图1所示,GTK会用到几个连接库,如基本数据类型用的Glib库,它是由基础类、核心应用支持类、实用功能类、数据类和对象系统类五个部分组成的。

  Pango是用于国际化文本的布局和显示的全功能框架。Pango可以处理以非从左到右方向排列的文本,并且可以容易地管理复杂语言,甚至还可 以处理根据使用环境而采用不同形式的信函。例如它支持双向文本,用户可以将从左到右的文本和从右到左的文本混合编排;还可有用于确定各种复杂文本(如阿拉 伯语和泰米尔语)形状的插件。Pango不仅仅是国际化,而且Pango库在Xft和XRender的支持下能很好地处理抗锯齿字体文本的显示。

  Pango还支持各种图形格式如libpng,libjpeg,libtiff和Framebuffer port用的FreeType等。实际上GTK提供gdk-pixbuf,gdk和gtk三个连接库,其中Gdk-pixbuf让我们可做相关的图像工 作,gdk是窗口绘图系统的抽象层,framebuffer相关的工作大部分在此完成,而gtk则是高层的应用程序接口。

  Atk(Accessibility Toolkit)可访问性工具箱。GTK充分利用ATK使残障人士(如视力低下或行动不便)与GTK应用程序交互成为可能。

 2.1.3 GtkFB的工作原理

  DirectFB访问图形硬件设备依赖于操作系统提供的内核接口,即帧缓冲设备Linux(FrameBuffer)。FrameBuffer实际上是用一块硬件来做显卡和软件之间的桥梁,的内核将其开放出来,

使用户的程序可以通过块内存来存取显卡。例如设定显示分辨率和色彩数、存取显示内存区等。不同的Linux需要提供针对不同显示硬件 FrameBuffer的驱动程序,这就是说DirectFB需要运行于FramBuffer之上,然而Linux内核提供了常见芯片的 FrameBuffer驱动。

  当一个应用程序连接到GtkFB时会调用gtk_init(),如图3所示,此时GtkFB 启动Linux的Framebiffer,设定分辨率和色彩数,接下来打开键盘和鼠标等外设(PDA打开按键和触控屏幕).然后到特定目录去读取字型,最 后对窗口和事件管理作初始化操作。GtkFB可以支持8、16、24、32bpp的framebuffer。

Gtk通过DirectFB访问FrameBufer设备和图形设备

  为了执行一个特定的图形操作,DirectFB芯片驱动程序将访问图形设备内存映射的I/O端口,并且把命令传递到图形设备卡的加速引擎。实际的硬件加速是完全在用户空间内完成的。

  2.2 SWT+GtkFB图形系统的优点

  2.2.1 内存消耗小、运行速度快特别适合嵌入式产品

  由于GtkFB直接运行在FrameBufer之上,跳过X系统,这样省下了X Server这一部分资源,这使得在内存消耗、运行速度上得到显著提高。另外采用的JNI技术使得程序运行速度、事件的响应有较高的提高,能满足时间要求较为严格的实时应用场合。

  2.2.2 系统稳定性好

  SWT 的稳定性,关键是源于SWT 的设计理念。SWT最大化了操作系统的图形构件API,就是说只要操作系统提供了相应图形的构件,那么SWT只是应用JNI技术调用它们,只有那些操作系 统中不提供的构件,SWT才自己去做一个的模拟实现。可以看出SWT性能上的稳定很大程度上取决于相应操作系统图形构件的稳定性。

  2.2.3 易于移植和共享

  SWT的API和桌面版完全相同,因而代码可以很容易地在桌面和嵌入式设备之间移植与共享。

  2.2.4 小巧可配置

  SWT采用了LGPL授权方式,用户可以自由地甚至是鼓励修改源代码使其更加满足用户的需求,很容易根据用户的需求来裁减特定的SWT+GtkFB,依据LGPL许可证,用户需要公布修改的源代码,但用户不必公布自给应用程序的源代码。

  2.2.5 易于开发

  SWT是基于Java语言开发的,具有平台薄雾浓云愁永昼独立性、面向对象、可移植、安全等Java语言所拥有特点。用户可以很容易的基于SWT提供的Widget(构件)开发出满足自己需要的Widget,而且很容易地使用这些Widget去构建应用程序。

  3 SWT+GtkFB图形系统的实现

  3.1 前期准备

  在Linux编译和安装SWT+GtkFB,首先到http://www.gtk.org/download下载如下的包:pkg-config、glib2.x;atk、pango、DirectFB、gtk+2.x。其次到http://www.eclipse.org/download下载swt.tgr.gz。

  下一步就是在/home/XXX/目录下创建SWT 和GTK两个目录并且设置环境变量。如下:

  export SWT_HOME=/home/XXX/SWT

  export SWT_HOME=/home/XXX/GTK

  export PKG_CONFIG_PATH=$GTK_HOME /lib/pkgconfig

  export LD_LIBRARY_PATH=$GTK_HOME/lib;$LD_LIBRARY_PATH

  此外增加“/home/XXX/GTK/bin”到系统的环境变量PATH下。

  3.2 编译和安装Gtk+2.0

  3.2.1 编译和安装pkg-config

  tar zxvf glib-2.0.6.tar.gz -C $GTK_HOME/src

  cd $GTK HOME/src/glib-2.0.6

  ./configure --prefix=$GTK_HOME

  make

  make install

  3.2.2 编译和安装atk

  tar zxvf atk-1.0.1.tar.gz -C $GTK_HOME/src

  cd $GTK_HOME/src/atk-1.0.1

  ./configure --prefix=$GTK_HOME

  make

  make install

  3.2.3 编译和安装pango、Direct FB、gtk+2.0 、swt-forgtk2.2

  步骤类似atk的安装。

  4 嵌入式Linux GUI的应用前景展望

  嵌入式Linux GUI的应用领域很多,既可以用于家电市场,还可以用于商业市场、工业及自动化市场、国防市场、通讯市场等。例如,在通讯市场,手机、可视电话、机顶盒等可能成为嵌入式Linu.x的运行平台,一个人性化的用户界面是赢得消费者关键因素。因此嵌入式Linux图形系统将担任着更加重要的角色。

  未来几年,嵌入式Linux GUI将朝以下方向发展:第一,轻型、占用资源少,不希望建立在庞大累赘的、非常消耗系统资源的操作系统和GUI之上。第二,高性能、高可靠性,特别是工 业实时控制系统,对实时性的要求非常高,并且比起嵌入式系统来说,对GUI的要求也更高。第三,可配置,我们必须清楚的意识到,嵌入式系统是一种定制设 备,它们对GUI的需求各不相同,有的系统只要求一些图形功能,而有些系统要求完备的GUI支持,因此,GUI也必须是可定制的。

Leave a comment

gdb命令手册

来源: ChinaUnix博客  
 
GDB的命令很多,本文不会全部介绍,仅会介绍一些最常用的。在介绍之前,先介绍GDB中的一个非常有用的功能:补齐功能。它就如同Linux下 SHELL中的命令补齐一样。当你输入一个命令的前几个字符,然后输入TAB键,如果没有其它命令的前几个字符与此相同,SHELL将补齐此命令。如果有 其它命令的前几个字符与此相同,你会听到一声警告声,再输入TAB键,SHELL将所有前几个字符与此相同的命令全部列出。而GDB中的补齐功能不仅能补 齐GDB命令,而且能补齐参数。
本文将先介绍常用的命令,然后结合一个具体的例子来演示如何实际使用这些命令。下面的所有命令除了第一条启动GDB命令是在SHELL下输入的,其余都是 GDB内的命令。大部分GDB内的命令都可以仅输入前几个字符,只要不与其它指令冲突。如quit可以简写为q,因为以q打头的命令只有quit。 List可以简写为l,等等。
1.启动GDB
你可以输入GDB来启动GDB
程序
。GDB程序有许多参数,在此没有必要详细介绍,但一个最为常用的还是要介绍的:如果你已经编译好一个程序,我们假设文件名为hello,你想用GDB调 试它,可以输入gdb hello来启动GDB并载入你的程序。如果你仅仅启动了GDB,你必须在启动后,在GDB中再载入你的程序。
2.载入程序 === file
在GDB内,载入程序很简单,使用file命令。如file hello。当然,
程序
的路径名要正确。
退出GDB === quit
在GDB的命令方式下,输入quit,你就可以退出GDB。你也可以输入'C-d'来退出GDB。
3.运行程序 === run
当你在GDB中已将要调试的程序载入后,你可以用run命令来执行。如果你的
程序
需要参数,你可以在run指令后接着输入参数,就象你在SHELL下执行一个需要参数的命令一样。
4.查看程序信息 === info
info指令用来查看程序的信息,当你用help info查看帮助的话,info指令的参数足足占了两个屏幕,它的参数非常多,但大部分不常用。我用info指令最多的是用它来查看断点信息。
4.1 查看断点信息
info br
br是断点break的缩写,记得GDB的补齐功能吧。用这条指令,你可以得到你所设置的所有断点的详细信息。包括断点号,类型,状态,内存地址,断点在源程序中的位置等。
4.2 查看当前源程序
info source
4.3 查看堆栈信息
info stack
用这条指令你可以看清楚程序的调用层次关系。
4.4 查看当前的参数
info args
5.列出源一段源
程序
=== list
5.1 列出某个函数
list FUNCTION
.2 以当前源文件的某行为中间显示一段源程序
list LINENUM
5.3 接着前一次继续显示
list
5.4 显示前一次之前的源程序
list -
5.5 显示另一个文件的一段程序
list FILENAME:FUNCTION 或 list FILENAME:LINENUM
6.设置断点 === break
现在我们将要介绍的也许是最常用和最重要的命令:设置断点。无论何时,只要你的
程序
已被载入,并且当前没有正在运行,你就能设置,修改,删除断点。设置断点的命令是break。有许多种设置断点的方法。如下:
6.1 在函数入口设置断点
break FUNCTION
6.2 在当前源文件的某一行上设置断点
break LINENUM
6.3 在另一个源文件的某一行上设置断点
break FILENAME:LINENUM
6.4 在某个地址上设置断点,当你调试的
程序
没有源程序是,这很有用
break *ADDRESS
除此之外,设置一个断点,让它只有在某些特定的条件成立时程序才会停下,我们可以称其为条件断点。这个功能很有用,尤其是当你要在一个程序会很多次执行到 的地方设置断点时。如果没有这个功能,你必须有极大的耐心,加上大量的时间,一次一次让程序断下,检查一些值,接着再让程序继续执行。事实上,大部分的断 下并不是我们所希望的,我们只希望在某些条件下让程序断下。这时,条件断点就可以大大提高你的效率,节省你的时间。条件断点的命令如下,在后面的例子中会 有示例。
6.5 条件断点
break ...if COND
7.其它断点操作
GDB给每个断点赋上一个整数数字,这个数字在操作断点时起到重要作用,它实际上就代表相应的断点。GDB中的断点有四种状态:
有效(Enabled)
禁止(Disabled)
一次有效(Enabled once)
有效后删除(Enabled for deletion)
在上面的四个状态有效和禁止都很好理解,禁止就是让断点暂时失效。一次有效就是当程序在此断点断下后,断点状态自动变为禁止状态。有效后删除就是当程序在此断点断下后,断点被删除。实际上,后两种状态一般不会碰到。
当你设置一个断点后,它的确省状态是有效。你可以用enable和disable指令来设置断点的状态为有效或禁止。例如,如果你想禁止2号断点,可以用下面的指令:
disable 2
相应的,如果想删除2号断点,可以有下面的指令:
delete 2
8.设置监视点 === watch
当你调试一个很大的程序,并且在跟踪一个关键的变量时,发现这个变量不知在哪儿被改动过,如何才能找到改动它的地方。这时你可以使用watch命令。简单地说,监视点可以让你监视某个表达式或变量,当它被读或被写时让
程序
断下。watch命令的用法如下:
watch EXPRESSION
watch指令是监视被写的,当你想监视某个表达式或变量被读的话,需要使用rwatch指令,具体用法是一样的。要注意的是,监视点有硬件和软件两种方 式,如果可能Linux尽可能用硬件方式,因为硬件方式在速度上要大大快于软件方式。软件方式由于要在每次执行一条指令后都要检查所要监视的值是否被改 变,因此它的执行速度会大大降低。同时它也无法设置成被读时让
程序
断下,因为读操作不会改变值,所以GDB无法检测到读操作。幸运的是,目前的PC机基本都支持硬件方式。如果你想确认一下你的机器是否支持硬件,你可以在调试程序时用watch设置一个监视点,如果GDB向你显示:
Hardware watchpoint NUM: EXPR
.检查数据
最常用的检查数据的方法是使用print命令。
print exp
print指令打印exp表达式的值。却省情况下,表达式的值的打印格式依赖于它的数据类型。但你可以用一个参数/F来选择输出的打印格式。F是一个代表 某种格式的字母,详细可参考输出格式一节。表达式可以是常量,变量,函数调用,条件表达式等。但不能打印宏定义的值。表达式exp中的变量必须是全局变量 或当前堆栈区可见的变量。否则GDB会显示象下面的一条信息:
No symbol "varible" in current context
10.修改变量值
在调试
程序
时,你可能想改变一个变量的值,看看在这种情况下会发生什么。用set指令可以修改变量的值:
set varible=value
例如你想将一个变量tmp的值赋为10,
set tmp=10
11.检查内存值
检查内存值的指令是x,x是examine的意思。用法如下:
x /NFU ADDR
其中N代表重复数,F代表输出格式(见2.13),U代表每个数据单位的大小。U可以去如下值:
b :字节(byte)
h :双字节数值
w :四字节数值
g :八字节数值
因此,上面的指令可以这样解释:从ADDR地址开始,以F格式显示N个U数值。例如:
x/4ub 0x4000
会以无符号十进制整数格式(u)显示四个字节(b),0x4000,0x4001,0x4002,0x4003。
12.输出格式
缺省情况下,输出格式依赖于它的数据类型。但你可以改变输出格式。当你使用print命令时,可以用一个参数/F来选择输出的打印格式。F可以是以下的一些值:
'x' 16进制整数格式
'd' 有符号十进制整数格式
'u' 无符号十进制整数格式
'f' 浮点数格式
13.单步执行指令
单步执行指令有两个step和next。Step可以让你跟踪进入一个函数,而next指令则不会进入函数。
14.继续执行指令
当程序被断下后,你查看了所需的信息后,你会希望
程序
执行下去,输入 continue, 程序会继续执行下去。
15.帮助指令help
在GDB中,如果想知道一条指令的用法,最方便的方法是使用help。使用方法很简单,在help后跟上指令名。例如,想知道list指令用法,输入
help list
Leave a comment

戴佩妮——《怎样》

专辑中文名 怎样

歌手 戴佩妮

资源格式 APE

发行时间 2001年01月

地区 台湾

语言 普通话

简介

专辑介绍:

    出道短短一年便备受各界肯定的戴佩妮,首张全创作专辑在亚洲地区佳评如潮、获奖无数,包括:新加坡金曲奖 2000─入围最佳新人奖、第一届马来西亚亚洲中文金曲奖-大马区最佳新人奖以及马来西亚第二届中文AIM颂奖典礼的最佳新人、最佳演绎女歌手、最佳专辑 等三项大奖,风头之劲,一时无二,继而向她邀歌的大有人在。

第二张全创作国语专辑《怎样》,依然有她的个人特色,比上一张少了尖锐性的创 作元素,更加轻松、没有压力。首支主打歌曲「日期」,很有王家卫电影「重庆森林」的感觉,是戴佩妮看见家里的一排罐头,发现每个罐头上都有个日期,而引发 的创作灵感,用一种轻松、乐观的态度去探讨人生哲学,是一首相当特别的民谣摇滚曲。除了戴佩妮最善长的民谣摇滚之外,《怎样》的曲风更融合了民谣、乡村、 另类摇滚、Fusion、爵士等元素,十分丰富多元,比上一张专辑进步不少。

 

如果我们还在一起会是怎样?

专辑曲目

1. Di Da...Excuse Me
2. 日期
3. 你要的爱
4. Thunder
5. 雨和太阳
6. 怎样
7. 好感觉
8. 遇见你的第4天
9. 醒了二年 睡了二年
10. 我有想法
11. 简单
12. 忽然
13. Andy Peterson solo
14. Jamie Wilson solo
15. 李守信solo
16. 黄中岳solo
17. 吴庆隆solo

 

下载地址:http://www.verycd.com/topics/275606/

Leave a comment

李健——《想念你》

专辑中文名 想念你

专辑英文名 missing you

歌手 李健

发行时间 2007年

简介

     最癫狂的年代,最清醒的坚持,最真实的情感!李健——拥有逆流之美的优秀唱作才子,2007中国原创乐坛最温暖男声,绝不庸常的作品,绝不媚俗的 声音:“异乡人”,唱出漂泊的心,守望美丽的梦;“风吹麦浪”,荡涤尘世烦嚣,怀恋单纯美好:“想念你”,金牌制作人张亚东亲力制作,弦乐铺陈真挚父子情 怀,真实、温暖、感动人心;“松花江”,对母亲河的歌唱,对生命记忆的回望……这是一个最好的时代,这是一个最坏的时代,时至今日的华语乐坛上演着太多的 极端。传播越来越快捷,资讯越来越发达,很多人一夜成“星”,然而星光熠熠的代价往往是每颗“星”一闪而过。R&B、“中国风”火了,几乎所有歌 手都争先恐后地R&B、“中国风”,然而跟风的代价通常是每首歌乏善可陈。造绯闻抑或是做音乐,抄袭抑或是原创,谁还在坚持着纯粹的音乐梦想?谁 还在变幻莫测的音乐江湖义无反顾地走着自己的路?从水木年华时期名噪一时的音乐王子,到单飞之后蜚声乐坛的实力唱将,李健很简单,他只做自己的音乐,在浑 沌的音乐江湖,怀揣着对音乐的虔诚,执着地走向最初的梦想

专辑曲目

01 抚仙湖
02 风吹麦浪
03 童年
04 超越
05 松花江
06 天狐
07 异乡人
08 想念你
09 小鸟睡在我身旁
10 异乡人

下载地址:http://www.verycd.com/topics/341212/

Leave a comment

架构师之路——程序

架构师之路(1)---面向过程和面向对象 王泽宾

1、引言
   机 算机科学是一门应用科学,它的知识体系是典型的倒三角结构,所用的基础知识并不多,只是随着应用领域和方向的不同,产生了很多的分支,所以说编程并不是一 件很困难的事情,一个高中生经过特定的训练就可以做得到。但是,会编程和编好程绝对是两码事,同样的程序员,有的人几年之后成为了架构师,有的人却还在不 停地coding,只不过ctrl-c、ctrl-v用得更加纯熟了。在中国,编程人员最终的归途无外乎两条:一是转向技术管理,它的终点是CTO;二是 继续深入,它的终点是首席架构师,成为CEO的人毕竟是少数。如果你现在还是个普通的程序员,希望继续在技术这条路上前进的话,我想你还是应该先补充一点 软件工程的思想,学习一点有关设计模式的知识,只有具备这些能力,你才能从整体和宏观层面来考虑问题、分析问题和解决问题。本人Coding了很多年,中 间走了不少弯路,虽然最终没什么大成就,但总算有一些心得,很愿意把自己的一些经验拿出来跟大家分享,这或许对你的发展有所帮助。

由程序员转为架构师,最绕不开的概念就算是面向对象(OO)了。记得在大学的时候,我们专业开了一门课叫《面向对象的编程》。那个时候,我们刚刚学 了一门C语言,开发环境用的还是DOS下的Turbo C,半点项目开发的经验都没有,纯粹的空对空。所以,一学期下来,我始终处于一种懵懂状态,既没领会面向过程和面向对象到底有什么区别,也没搞懂面向对象 能带来什么好处。

2、面向过程(OP)和面向对象(OO)

2.1 蛋炒饭和盖浇饭
    有人这么形容OP和OO的不同:用面向过程的方法写出来的程序是一份蛋炒饭,而用面向对象写出来的程序是一份盖浇饭。所谓盖浇饭,北京叫盖饭,东北叫烩 饭,广东叫碟头饭,就是在一碗白米饭上面浇上一份盖菜,你喜欢什么菜,你就浇上什么菜。我觉得这个比喻还是比较贴切的。
蛋炒饭制作的细节,我不太清楚,因为我没当过厨师,也不会做饭,但最后的一道工序肯定是把米饭和鸡蛋混在一起炒匀。盖浇饭呢,则是把米饭和盖菜分别做好,你如果要一份红烧肉盖饭呢,就给你浇一份红烧肉;如果要一份青椒土豆盖浇饭,就给浇一份青椒土豆丝。

    蛋炒饭的好处就是入味均匀,吃起来香。如果恰巧你不爱吃鸡蛋,只爱吃青菜的话,那么唯一的办法就是全部倒掉,重新做一份青菜炒饭了。盖浇饭就没这么多麻烦,你只需要把上面的盖菜拨掉,更换一份盖菜就可以了。盖浇饭的缺点是入味不均,可能没有蛋炒饭那么香。
到底是蛋炒饭好还是盖浇饭好呢?其实这类问题都很难回答,非要比个上下高低的话,就必须设定一个场景,否则只能说是各有所长。如果大家都不是美食家,没那么多讲究,那么从饭馆角度来讲的话,做盖浇饭显然比蛋炒饭更有优势,他可以组合出来任意多的组合,而且不会浪费。

2.2 软件工程
    盖浇饭的好处就是“菜”“饭”分离,从而提高了制作盖浇饭的灵活性。饭不满意就换饭,菜不满意换菜。用软件工程的专业术语就是“可维护性”比较好,“饭” 和“菜”的耦合度比较低。蛋炒饭将“蛋”“饭”搅和在一起,想换“蛋”“饭”中任何一种都很困难,耦合度很高,以至于“可维护性”比较差。软件工程追求的 目标之一就是可维护性,可维护性主要表现在3个方面:可理解性、可测试性和可修改性。面向对象的好处之一就是显著的改善了软件系统的可维护性。

    面向过程(OP)和面向对象(OO)是不是就是指编码的两种方式呢?不是!你拿到了一个用户需求,比如有人要找你编个软件,你是不是需要经过需求分析,然 后进行总体/详细设计,最后编码,才能最终写出软件,交付给用户。这个过程是符合人类基本行为方式的:先想做什么,再想如何去做,最后才是做事情。有的同 学说:“我没按照你说的步骤做啊,我是直接编码的”。其实,你一定会经历了这三个阶段,只不过你潜意识里没有分得那么清楚。对于拿到需求就编码的人,可能 编着编着,又得倒回去重新琢磨,还是免不了这些过程,

    以OO为例,对应于软件开发的过程,OO衍生出3个概念:OOA、OOD和OOP。采用面向对象进行分析的方式称为OOA,采用面向对象进行设计的方式称 为OOD,采用面向对象进行编码的方式称为OOP。面向过程(OP)和面向对象(OO)本质的区别在于分析方式的不同,最终导致了编码方式的不同。

2.3 面向过程编程(OPP) 和面向对象编程(OOP)的关系

    关于面向过程的编程(OPP)和面向对象的编程(OOP),给出这它们的定义的人很多,您可以从任何资料中找到很专业的解释,但以我的经验来看,讲的相对枯燥一点,不是很直观。除非您已经有了相当的积累,否则说起来还是比较费劲。

我是个老程序员出身,虽然现在的日常工作更多倾向了管理,但至今依然保持编码的习惯,这句话什么意思呢?我跟大家沟通应该没有问题。无论你是在重复 我走过的路,或者已经走在了我的前面,大家都会有那么一段相同的经历,都会在思想层面上有一种理解和默契,所以我还是会尽量按照大多数人的常规思维写下 去。

面向过程的编程(OPP)产生在前,面向对象的编程(OOP)产生在后,所以面向对象的编程(OOP)一定会继承前者的一些优点,并摒弃前者存在的 一些缺点,这是符合人类进步的自然规律。两者在各自的发展和演变过程中,一定会相互借鉴,相互融合,吸收对方的优点,从而出现某些方面的趋同性。但是,即 使两者有更多的相似点,也不会改变它们本质上的不同,因为它们的出发点不同,完全是两种截然不同的思维方式。关于两者的关系,我的观点是这样的:面向对象 编程(OOP)在局部上一定是面向过程(OP)的,面向过程的编程(OPP)在整体上应该借鉴面向对象(OO)的思想。这一段说的的确很空洞,而且也一定 会有引来争议,不过,我劝您还是在阅读了后面的内容之后,再来评判我观点的正确与否。

象C++、C#、Java等都是面向对象的语言,c,php(暂且这么说,因为php4以后就支持OO)都是面向过程的语言,那么是不是我用C++ 写的程序一定就是面向对象,用c写的程序一定就是面向过程呢?这种观点显然是没有真正吃透两者的区别。语言永远是一种工具,前辈们每创造出来的一种语言, 都是你用来实现想法的利器。我觉得好多人用C#,Java写出来的代码,要是仔细看看,那实际就是用面向对象(OO)的语言写的面向过程(OP)的程序。

所以,即使给关羽一根木棍,给你一杆青龙偃月刀,他照样可以打得你满头是包。你就是扛着个偃月刀,也成不了关羽,因为你缺乏关羽最本质的东西---绝世武功。同样的道理,如果你没有领会OO思想,怎么可能写得出真正的OO程序呢?

那是不是面向过程就不好,也没有存在的必要了?我从来没有这样说过。事实上,面向过程的编程(OPP)已经存在了几十年了,现在依然有很多人在使 用。它的优点就是逻辑不复杂的情况下很容易理解,而且运行效率远高于面向对象(OO)编写的程序。所以,系统级的应用或准实时系统中,依然采用面向过程的 编程(OPP)。当然,很多编程高手以及大师级的人物,他们由于对于系统整体的掌控能力很强,也喜欢使用面向过程的编程(OPP),比如像 Apache,QMail,PostFix,ICE等等这些比较经典的系统都是OPP的产物。象php这些脚本语言,主要用于web开发,对于一些业务逻 辑相对简单的系统,也常使用面向过程的编程(OPP),这也是php无法跨入到企业级应用开发的原因之一,不过php5目前已经能够很好的支持OO了。

2.4 详解面向过程的编程(OPP)
 

  在面向对象出现之前,我们采用的开发方法都是面向过程的编程(OPP)。面向过程的编程中最常用的一个分析方法是“功能分解”。我们会把用户需求先分解成 模块,然后把模块分解成大的功能,再把大的功能分解成小的功能,整个需求就是按照这样的方式,最终分解成一个一个的函数。这种解决问题的方式称为“自顶向 下”,原则是“先整体后局部”,“先大后小”,也有人喜欢使用“自下向上”的分析方式,先解决局部难点,逐步扩大开来,最后组合出来整个程序。其实,这两 种方式殊路同归,最终都能解决问题,但一般情况下采用“自顶向下”的方式还是较为常见,因为这种方式最容易看清问题的本质。

我举个例子来说明面向过程的编程方式:

用户需求:老板让我写个通用计算器。

最终用户就是老板,我作为程序员,任务就是写一个计算器程序。OK,很简单,以下就是用C语言完成的计算器:

假定程序的文件名为:main.c。

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

    //变量初始化
    int nNum1,nNum2;
    char cOpr;
    int nResult;
    nNum1 = nNum2 = 0;
    cOpr = 0;
    nResult = 0;

    //输入数据
    printf("Please input the first number:rn");
    scanf("%d",&nNum1);
    printf("Please input the operator:rn");
    scanf("%s",&cOpr);
    printf("Please input the second number:rn");
    scanf("%d",&nNum2); 

    //计算结果 
    if( cOpr == '+' ){
    nResult = nNum1 + nNum2;
    }else if( cOpr == '-' ){
    nResult = nNum1 - nNum2;
    }else{
    printf("Unknown operator!");
    return -1;
    }

    //输出结果
    printf("The result is %d!",nResult);
    return 0;
}

抛开细节不讲,我想大多数人差不多都会这么实现吧,很清晰,很简单,充分体现了“简单就是美”的原则,面向过程的编程就是这样有条理的按照顺序来逐步实现用户需求。

凡是做过程序的人都知道,用户需求从来都不会是稳定的,最多只能够做到“相对稳定”。用户可能会随时提出加个功能,减个功能的要求,也可能会要求改 动一下流程,程序员最烦的就是频繁地变动需求,尤其是程序已经写了大半了,但这种情况是永远无法避免的,也不能完全归罪到客户或者需求分析师。

以我们上面的代码为例,用户可能会提出类似的要求:
首先,你程序中实现了“加法”和“减法”,我还想让它也能计算“乘法”、“除法”。
其次,你现在的人机界面太简单了,我还想要个Windows计算器的界面或者Mac计算器的界面。

用户需求开始多了,我得琢磨琢磨该如何去写这段代码了。我今天加了“乘”“除”的运算,明天保不齐又得让我加个“平方”、“立方”的运算,这要是把 所有的运算都穷尽了,怎么也得写个千八百行代码吧。还有,用户要求界面能够更换,还得写一大堆界面生成的代码,又得来个千八百行。以后,这么多代码堆在一 起,怎么去维护,找个变量得半天,看懂了代码得半天,万一不小心改错了,还得调半天。另外,界面设计我也不擅长,得找个更专业的人来做,做完了之后再加进 来吧。这个过程也就是“软件危机”产生的过程。伴随着软件广泛地应用于各个领域,软件开发的规模变得越来越大,复杂度越来越高,而其用户的需求越来越不稳 定。

根据用户提出的两个需求,面向过程的编程该如何去应对呢?我想大家都很清楚怎么去改。Very easy,把“计算”和“界面”分开做成两个独立的函数,封装到不同的文件中。
假定程序的文件名为:main.c。

#include "interface.h"
#include "calculate.h"
int main(int argc, char *argv[]){

    //变量初始化
    int nNum1,nNum2;
    char cOpr;
    int nResult;
    nNum1 = nNum2 = 0;
    cOpr = 0;
    nResult = 0;

    //输入数据
    if( getParameters(&nNum1,&nNum2,&cOpr) == -1 )
    return -1;

    //计算结果 
    if( calcMachine(nNum1,nNum2,cOpr,&nResult) == -1 )
    return -1;

    //输出结果
    printf("The result is %d!",nResult);

    return 0;
}

interface.h:
int getParameters(int *nNum1,int * nNum2,char *cOpr);

interface.c:
int getParameters(int *nNum1,int * nNum2,char *cOpr){
    printf("Please input the first number:rn");
    scanf("%d",nNum1);
    printf("Please input the operator:rn");
    scanf("%s",cOpr);
    printf("Please input the second number:rn");
    scanf("%d",nNum2);

    return 0;
}

calculate.h:
int calcMachine(int nNum1,int nNum2,char cOpr, int *nResult);

calculate.c:
int calcMachine(int nNum1,int nNum2,char cOpr,int *nResult){
    if( cOpr == '+' ){
        *nResult = nNum1 + nNum2;
    }else if( cOpr == '-' ){
        *nResult = nNum1 - nNum2;
    }else{
        printf("Unknown operator!");
        return -1;
    };
    return 0;
}

“计算”和“界面”分开之后,添加新功能或者修改bug就方便多了,遇到与“计算”相关的需求就去修改calculate模块,遇到与“界面”相关的需求就去修改interface模块,因此,整个系统模块之间的“耦合度”就被放松了,可维护性有了一定程度的改善。

面向过程的编程(OPP)就是将用户需求进行“功能分解”。把用户需求先分解成模块(.h,.c),再把模块(.h,.c)分解成大的功能(function),然后把大的功能(function)分解成小的功能(function),如此类推。

功能分解是一项很有技术含量的工作,它不仅需要分解者具有丰富的实战经验,而且需要科学的理论作为指导。如何分解,分解原则是什么,模块粒度多大合适?这些都是架构师的要考虑的问题,也是我们后面要着重讲的内容。

面向过程的编程(OPP)优点是程序顺序执行,流程清晰明了。它的缺点是主控程序承担了太多的任务,各个模块都需要主控程序进行控制和调度,主控和模块之间的承担的任务不均衡。
有的人把面向过程定义为:算法 + 数据结构,我觉得也很准确。面向过程的编程中算法是核心,数据处于从属地位,数据随算法而流动。所以采用面向过程的方式进行编程,一般在动手之前,都要编写一份流程图或是数据流图。

3 架构师的职责

    近来看到CSDN上有个CTO俱乐部,里面聊得是不亦乐乎。我怀着无比崇敬的态度,拜读了一下牛人们的发言。里面有个哥们发起一个话题:“CTO, 你多久没有写程序了?”。有人回答:“不写代码的CTO,属于......这公司问题大了!”。看到这里,我就赶紧撤了,怕忍不住反驳几句,反而遭到牛人 们的群殴。试想,一个上点规模的IT公司,还得靠CTO来写程序的话,那是不是才叫问题大了呢。当然,我没有做过CTO,所以我有我的不同看法,而且还愿 意表达出来,无知者无畏。我情愿相信:我所理解的CTO跟这位CTO所理解的是两回事。所以我想,如果有人能把CTO的职责给标准化了,也许就不会有这么 多的争论了。
    同样的道理,关于架构师的定义,大家也有着不同的理解。什么是架构师?架构师有哪些职责?我觉得有必要提前明确一下,要不然大家沟通起来也会产生类似问题,子说子理,卯说卯理,但是压根说得不是一码子事。

3.1 什么是架构师

曾经有这么个段子:
甲:我已经应聘到一家中型软件公司了,今天上班的时候,全公司的人都来欢迎我。
乙:羡慕ing,都什么人来了?
甲:CEO、COO、CTO、All of 程序员,还有会计、司机都来了。
乙:哇,他们太重视你了,人才啊,这么多人迎接你!
甲:没有啊,就一个人!
乙:靠,#%¥$%...

    很多的创业公司,一人身兼数职的情形还是很常见的。至少,我是经历过的,一个人包办了所有的开发过程,连测试我都做了,绝对的一条龙,但是经常踩钢丝、骑 独轮车总会有失足的时候,结果有一次,从我手里发出去的光盘母盘,含有病毒僵尸,以至于被迫收回已经推上市场的2万张光盘,从那之后,我的心脏就开始变得 无比坚强,现在就是整个后台服务都瘫痪了,我也只是微微一笑。其实,一个人身兼架构师和程序员,甚至多种角色,没什么不妥,后面还会讲这个话题,这种现象 不是中国特色,跟国外是完全接轨的。我曾经跟米国的一个工程师在msn中聊过类似的话题,发现他们的路子跟咱们没什么不同,在IT这个行业,我们跟世界的 差距只有1天,他们刚弄出来的新东西,我们这里第2天保准见得到。

    架构师这个称呼不是拍脑袋想出来的,是有国际标准(ISO/IEC 42010)可查的。架构师是软件开发活动中的众多角色之一,它可能是一个人、一个小组,也可能是一个团队。微软对架构师有一个分类参考,我们参考一下, 他们把架构师分为4种:企业架构师EA(Enterprise Architect)、基础结构架构师IA(Infrastructure Architect)、特定技术架构TSA(Technology-Specific Architect)和解决方案架构师SA (Solution Architect)。微软的这个分类是按照架构师专注的领域不同而划分的。

    EA的职责是决定整个公司的技术路线和技术发展方向。盖茨给自己的Title就是首席软件架构师,网易丁磊也喜欢这么称呼自己,实际上就是EA角色;IA 的工作就是提炼和优化技术方面积累和沉淀形成的基础性的、公共的、可复用的框架和组件,这些都是一个技术型公司传承下来的最宝贵的财富之一;特定技术架构 师TSA,他们主要从事类似安全架构、存储架构等专项技术的规划和设计工作;SA的工作则专于解决方案的规划和设计,“解决方案”这个词在中国已经到了严 重泛滥的程度,大忽悠们最喜欢把它挂在嘴边。所谓解决方案,就是把产品、技术或理论,不断地进行组合,来创造出满足用户需求的选择。售前工程师一般都是带 着它到客户那里去发挥的。

    大公司会把各种类型的架构师分得很清楚,小公司一般就不那么讲究了,架构师多数是是IA+TSA+SA,一人包打天下,所以说大公司出专才,小公司出全才。

    实际工作中,我们也经常会见到另一种比较简单的分类方式,把架构师分为软件架构师和系统架构师。软件架构师基本上是TSA+IA,这也是程序员最容易突 破,最可能走上的一条道路,比如JAVA架构师、DotNet架构师、LAPM架构师等等,我后面所讲的内容都是与软件架构师的相关的话题。系统架构师实 际上是SA+TSA,更着力于综合运用已有的产品和技术,来实现客户期望的需求。系统架构师要求通晓软、硬件两方面的知识,所以它的知识体系相对庞杂。关 于系统架构师的话题,我们可以稍后再作讨论。

3.2 架构师的职责

架构师需要参与项目开发的全部过程,包括需求分析、架构设计、系统实现、集成、测试和部署各个阶段,负责在整个项目中对技术活动和技术说明进行指导和协调。
架构师主要职责有4条:

1、确认需求
    在项目开发过程中,架构师是在需求规格说明书完成后介入的,需求规格说明书必须得到架构师的认可。架构师需要和分析人员反复交流,以保证自己完整并准确地理解用户需求。

2、系统分解
    依据用户需求,架构师将系统整体分解为更小的子系统和组件,从而形成不同的逻辑层或服务。随后,架构师会确定各层的接口,层与层相互之间的关系。架构师不仅要对整个系统分层,进行“纵向”分解,还要对同一逻辑层分块,进行“横向”分解。
    软件架构师的功力基本体现于此,这是一项相对复杂的工作。

3、技术选型
    架构师通过对系统的一系列的分解,最终形成了软件的整体架构。技术选择主要取决于软件架构。
Web Server运行在Windows上还是Linux上?数据库采用MSSql、Oracle还是Mysql?需要不需要采用MVC或者Spring等轻量级的框架?前端采用富客户端还是瘦客户端方式?类似的工作,都需要在这个阶段提出,并进行评估。
架构师对产品和技术的选型仅仅限于评估,没有决定权,最终的决定权归项目经理。架构师提出的技术方案为项目经理提供了重要的参考信息,项目经理会从项目预算、人力资源、时间进度等实际情况进行权衡,最终进行确认。

4、制定技术规格说明
    架构师在项目开发过程中,是技术权威。他需要协调所有的开发人员,与开发人员一直保持沟通,始终保证开发者依照它的架构意图去实现各项功能。
    架构师与开发者沟通的最重要的形式是技术规格说明书,它可以是UML视图、Word文档,Visio文件等各种表现形式。通过架构师提供的技术规格说明书,保证开发者可以从不同角度去观察、理解各自承担的子系统或者模块。
架构师不仅要保持与开发者的沟通,也需要与项目经理、需求分析员,甚至与最终用户保持沟通。所以,对于架构师来讲,不仅有技术方面的要求,还有人际交流方面的要求。

3.3 架构师的误区

1、架构师就是项目经理
    架构师不是项目经理。项目经理侧重于预算控制、时间进度控制、人员管理、与外部联系和协调等等工作,具备管理职能。一般小型项目中,常见项目经理兼架构师。

2、架构师负责需求分析
    架构师不是需求分析员。需求分析人员的工作是收集需求和分析需求,并与最终用户、产品经理保持联系。架构师只对最终的需求审核和确认,提出需求不清和不完整的部分,他会跟需求分析员时刻保持联系。架构师是技术专家,不是业务专家。

3、架构师从来不写代码
    这是一个尚存争论的问题。目前有两种观点:
观点1:架构师不写代码,写代码纯体力活,架构师写代码大材小用。架构师把UML的各种视图交给开发人员,如果有不明确的地方,可以与架构师随时沟通。
观点2:架构师本来自于程序员,只是比程序员站的层面更高,比程序员唯一多的是经验和知识,所以架构师也免不了写代码。
    我个人觉得这两种说法是与架构师的出身和所处的环境有关。
    架构师首先是一个技术角色,所以一定是来自于技术人员这个群体,比如系统架构师,多是来自于运维人员,可能本身代码写得并不多,或者说写不出来很漂亮的代 码。软件架构师多是来自于程序员,有着程序员的血统和情怀,所以在项目开发过程中,可能会写一些核心代码。我们的理想是架构师不用写代码,但事实上有时候 过于理想。架构师写不写代码,可能取决于公司的规模、文化、开发人员的素质等现实情况。另外,架构师也不是跟程序员界限分得那么清楚,按照能力也有高中低 之分,写不写代码不是区分两者的根本标准。

3.4 架构师的基本素质

周星驰有个片子《喜剧之王》,剧中的尹天仇整天揣着本《演员的自我修养》,一个好演员不仅需要天赋,也需要一定的理论指导,无师自通的人毕竟是少 数。架构师的成长过程也是这样。从普通程序员到高级程序员,再到架构师,是一个经验积累和思想升华的过程。经验积累是一个方面,素质培养是另一个方面,两 者相辅相成,所以我觉得有必要把架构师的所要具备的素质罗列一下,作为程序员努力的方向。

1、沟通能力
    为了提高效率,架构师必须赢得团队成员、项目经理、客户或用户认同,这就需要架构师具有较强的沟通能力。沟通能力是人类最普遍性的素质要求,技术人员好像 容易忽略,想成为架构师就不能忽略。千万不要抱着这样的观念:怀才跟怀孕似的,时间久了总会被人发现的。还是天桥上卖大力丸的哥们说得对:光说不练假把 式,光练不说傻把式。看看你周围的头头脑脑们,哪一个不是此中高手,我们千万不要鄙视,认为这是阿谀奉承、投机钻营,凡事都要看到积极的一面,“沟通”的 确是一种能力。我认为自己是一个略内向的人,因为我是农村出来的孩子,普通话都说不好,以前或多或少带有点自卑感,幻想着是金子总会发光,所以在职业生涯 中吃了不少亏。现在,我深深懂得了沟通的重要性,我会很主动地跟同事们,跟老大们不定时地沟通,感觉工作起来顺畅多了。

    这一条我认为最为重要,所以排在首位。我甚至认为下面几条都可以忽略,唯一这一条得牢记,而且要常常提醒自己。

2、领佳节又重阳导能力
      架构师能够推动整个团队的技术进展,能在压力下作出关键性的决策,并将其贯彻到底。架构师如何来保证这种执行力?这就需要架构师具有领佳节又重阳导能力。

    架构师的领佳节又重阳导能力的取得跟项目经理不太一样。项目经理主要负责解决行政管理,这种能力与技术关系不大,他有人薄雾浓云愁永昼权和财权,再扯上一张“领佳节又重阳导”的虎皮,采用“ 胡萝卜加大棒”的方式,基本上可以保证执行力。架构师在项目里面可能更多地使用非正式的领佳节又重阳导力,也就是我们常说的影响力,里面包括个人魅力、技术能力、知 识传递等等。

3、抽象思维和分析能力
    架构师必须具备抽象思维和分析的能力,这是你进行系统分析和系统分解的基本素质。只有具备这样的能力,架构师才能看清系统的整体,掌控全局,这也是架构师 大局观的形成基础。你如何具备这种能力呢?一是来自于经验,二是来自于学习。架构师不仅要具备在问题领域上的经验,也需要具备在软件工程领域内的经验。也 就是说,架构师必须能够准确得理解需求,然后用软件工程的思想,把需求转化和分解成可用计算机语言实现的程度。经验的积累是需要一个时间过程的,这个过程 谁也帮不了你,是需要你去经历的。但是,如果你有意识地去培养,不断吸取前人的经验的话,还是可以缩短这个周期的。这也是我写作此系列的始动力之一。

4、技术深度和广度

   架构师最好精通1-2个技术,具备这种技术能力可以更加深入的理解有关架构的工作原理,也可以拉近和开发人员的距离,并形成团队中的影响力。

   架构师的技术知识广度也很重要,需要了解尽可能多的技术,所谓见多识广,只有这样,才可能综合各种技术,选择更加适合项目的解决方案。有的人说,架构师技术广度的要求高于技术深度的要求,这是很有道理的。
总而言之,一句话:架构师是项目团队中的技术权威。

面向过程和面向对象这两个基本概念,不仅架构师需要非常清楚,程序员、设计师也要非常清楚,这也是系统分析、设计和编码最基本的常识。我接触的程序 员,很多人只停留在一种“似是而非”的程度,这是不行的,想要继续前进,就得把基础夯实,所以我觉得很有必要先回回炉,补补课。

Posted in 嵌入式系统 | Leave a comment

Linux的ftp服务vsftp详细配置

    本文以redhat AS 4.0为例:首先要安装linux下的vsftp软件包。
  rpm -qa|gerp vsftpd //查找vsftpd有没有安装
  如果没有安装就 vsftpd-2.0.1-5.i386.rpm (在第一张光盘)
  在linux中有一个非常重要的一点就是要挂载光驱 mount /media/cdrom
  在这里我们就不用源代码安装了。用的是rpm安装
  #rpm -ivh vsftpd-2.0.1-5.i386.rpm
  这里就安装好了。

  service vsftpd start 启动vsftpd服务
  如果在不设置任何的情况下,可以以匿名的方式访问该ftp。
  注.如果访问不了的时候请大家要把linux的防火墙也要关闭:
  iptables -F 清除防火墙
  在安装好ftp会产生几个文件:
  /etc/vsftpd/vsftpd.conf 主配置文件
  /etc/vsftpd.ftpusers 指定哪些用户不能访问FTP服务器
  /etc/vsftpd.user_list 文件中指定的用户是否可以访问ftp服务器由vsftpd.conf文件中的userlist_deny的取值来决定。
  这几个文件就是整个ftp控制和禁止用户的权限配置。。。
    下面我们就来设置一个vsftpd的核心文件
  # cd /etc/vsftpd/vsftpd.conf 这就是vsftpd的核心配置文件
  anonymous_enable=YES/no 是否允许匿名用户登录
  anonymous_enable=yes/no 是否允许匿名上传文件
  local_enable= YES/no 是否允许本地用户登录
  write_enable= YES/no 是否允许本地用户上传
  guest_enable=yes/no 是否允许虚拟用户登录;
  local_mask=022 设置本地用户的文件生成掩码为022,默认值为077
  dirmessage_enable= YES 设置切换到目录时显示.message隐含文件的内容
  xferlog_enable= YES 激活上传和下载日志
  connect_from_port_20=YES 启用FTP数据端口连接
  pam_service_name=vsftpd 设置PAM认证服务的配置文件名称, 该文件存放在/etc/pam.d目录下
  userlist_enable= YES 允许vsftpd.user_list文件中的用户访问服务器
  userlist_deny= YES 拒绝vsftpd.user_list文件中的用户访问服务器
  listen= YES/no 是否使用独占启动方式(这一项比较重要)
  tcp_wrappers= YES/no 是否使用tcp_wrappers作为主机访问控制方式
  最主要的就是这些设置了。(这是一般都是默认的不是太懂的不要动)
  大家可以设置下面的设置:
  ftpd_banner=welcome to ftp service 设置连接服务器后的欢迎信息
  idle_session_timeout=60 限制远程的客户机连接后,所建立的控制连接,在多长时间没有做任何的操作就会中断(秒)
  data_connection_timeout=120 设置客户机在进行数据传输时,设置空闲的数据中断时间
  accept_timeout=60 设置在多长时间后自动建立连接
  connect_timeout=60 设置数据连接的最大激活时间,多长时间断开,为别人所使用;
  max_clients=200 指明服务器总的客户并发连接数为200
  max_per_ip=3 指明每个客户机的最大连接数为3
  local_max_rate=50000(50kbytes/sec)
  anon_max_rate=30000 设置本地用户和匿名用户的最大传输速率限制
  pasv_min_port=端口
  pasv-max-prot=端口号 定义最大与最小端口,为0表示任意端口;为客户端连接指明端口;
  listen_address=IP地址 设置ftp服务来监瑞脑消金兽听的地址,客户端可以用哪个地址来连接;
    listen_port=端口号 设置FTP工作的端口号,默认的为21
  chroot_local_user=YES 设置所有的本地用户可以chroot
  chroot_local_user=NO 设置指定用户能够chroot
  chroot_list_enable=YES
    chroot_list_file=/etc/vsftpd.chroot_list(只有/etc/vsftpd.chroot_list中的指定的用户才能执行 )
  local_root=path 无论哪个用户都能登录的用户,定义登录帐号的主目录, 若没有指定,则每一个用户则进入到个人用户主目录;
  chroot_local_user=yes/no 是否锁定本地系统帐号用户主目录(所有);锁定后,用户只能访问用户的主目录/home/user,不能利用cd命令向上转;只能向下;
  chroot_list_enable=yes/no 锁定指定文件中用户的主目录(部分),文件:/chroot_list_file=path 中指定;
  userlist_enable=YES/NO 是否加载用户列表文件;
  userlist_deny=YES 表示上面所加载的用户是否允许拒绝登录;
  userlist_file=/etc/vsftpd.user_list 列表文件
  这些就是高级设置了。大家可以适当的更改。
  #vi /etc/hosts.allow
  vsftpd:192.168.5.128 :D ENY 设置该IP地址不可以访问ftp服务(vsftpd在独占启动方式下支持tcp_wrappers主机访问控制方式)
  时间限制:
  #cp /usr/share/doc/vsftpd-1.1.3/vsftpd.xinetd /etc/xinetd.d/vsftpd
  #vi /etc/xinetd.d/vsftpd/
  修改 disable = no
  access_time = hour:min-hour:min (添加配置访问的时间限制(注:与vsftpd.conf中listen=NO相对应)
  例: access_time = 8:30-11:30 17:30-21:30 表示只有这两个时间段可以访问ftp
  ftp的配置基本上只有这些了。

Posted in Linux操作系统 | Leave a comment