Linux开发技术

更新时间:2023-10-27 04:08:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

Linux开发技术

一、 Linux概述

Linux是一种自由和开放源码的类Unix操作系统。目前存在着许多不同的Linux,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,从手机、平板电脑、路由器和视频游戏控制台,到台式计算机、大型机和超级计算机。Linux是一个领先的操作系统,世界上运算最快的10台超级计算机运行的都是Linux操作系统。严格来讲,Linux这个词本身只表示Linux内核,但实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU 工程各种工具和数据库的操作系统。Linux得名于计算机业余爱好者Linus Torvalds。 二、Linux

安装

对于Windows/Linux多操作系统共存的系统,安装顺序是先安装Windows系统,然后才是Linux。下面我们介绍在已经安装了Windows系统的单硬盘上如何安装RedHat Linux 9.0。 Linux安装前的准备工作

1.用Windows系统收集硬件信息 在安装Linux之前,您需要借助Windows系统了解计算机硬件的基本信息,如内存大小、声卡、显示器、鼠标和显卡型号等。 2.设置从光盘引导系统

Linux支持几种安装方式,但直接以光盘开机启动进行安装最方便和快速。若要机器以光盘启动,需要修改BIOS的设置,将CD-ROM变更至开机顺序的第一位。 3.Linux分区

Linux分区的表示方法

分区就是将磁盘驱动器分隔成独立的区域,每个区域都如同一个单独的磁盘驱动器,在DOS/Windows系统下磁盘分区可分为C、 D和E盘等。但Linux则将磁盘视为块设备文件来管理使用,它以 /dev(device的缩写)开头表示。 例: 在Linux用 “/dev/hda1”表示Windows下的C盘

其中:hd 表示IDE硬盘(SCSI硬盘用sd);hda 为 第一个IDE 硬盘(第二为 hdb);/dev/hda1 为主分区,逻辑分区 从5 开始,如: /dev/hda5、/dev/hda6、/dev/hda7等。 为Linux准备分区

Linux分区和Windows分区不同,不能共用。所以需要为Linux单独开辟一个空闲的分区,最好是最后一个分区。如图1中利用Windows下的Partition Magic(分区魔法)软件,在D盘上腾出空间创建新分区E盘(或利用已有的空闲E

盘),文件类型暂设为FAT32,作为稍后创建Linux分区使用,RedHat 9.0 大约需4 ~ 5GB的空间。 4.Linux 的文件系统

对于不同的操作系统,文件系统也不同。Windows文件系统为FAT16、FAT32和NTFS。而Linux的文件系统可分为ext2、ext3、swap和vfat。ext2支持最多为255 个字符的文件名;ext3 是基于 ext2之上,主要优点是减少系统崩溃后恢复文件系统所花费的时间,RedHat 9.0 默认文件系统为ext3;交换区swap是被用于支持虚拟内存;Windows的FAT分区在Linux下显示为vfat文件类型。 1.用RedHat 9.0第一张安装光盘引导开机,系统在开机后会出现安装菜单。 安装菜单中提供了供用户选择的图形和文本模式的安装方式,按回车选择图形模式进行安装。在进入图形画面的安装模式前,RedHat 9.0比以往的版本多了一个环节,那就是提示对安装光盘介质进行检测, 也可按“Skip”按钮跳过检测。 2.接着安装程序会自动检测硬件,包括视频卡(显示卡)、显示器和鼠标的配置,然后进入图形画面的安装向导。在出现“语言选择”的画面中,我们选择“简体中文”,这样接下去的安装过程界面的文字都会改为中文。在“键盘配置”画面中接受默认的“美国英语式”键盘。选择“下一步”,在“鼠标配置”窗口,系统自动检测出鼠标的配置。

3.选择安装类型,安装类型包含四种不同的安装方式:个人桌面、工作站、服务器和定制。“服务器”的安装适用于专职的服务器使用,“个人桌面”和“工作站”适合于初学者,为了让你更多地了解安装过程,我们将选择“定制”类型进行安装。

4.磁盘分区设置:确认了“定制”方式之后,系统会出现“磁盘分区设置”窗口,它提供了两种分区方式:“自动分区”和“用Disk Druid手工分区”。 “自动分区”是一个危险功能,因为它会自动删除原先硬盘上的数据,并格式化成为Linux的分区文件系统。所以除非计算机上没有其他操作系统,你才可以使用。建议采用Disk Druid程序进行手动分区,它的图形化界面比早期RedHat的fdisk程序操作更简单。 5.磁盘设置:在选择“用Disk Druid手工分区”后,会显示如图2的“磁盘设置”窗口,这是整个安装过程中惟一需要用户较多干预的步骤,也是很重要的环节。

只要有一个主分区就可以安装并使用Windows操作系统,同时D、E等逻辑盘的文件结构也都是独立的。而Linux系统归根结底就只有一个根目录,一个独立且惟一的文件结构。Linux的文件系统采用树型结构,整个文件系统由一个“根”和根上的几个分“杈”组成,Linux需创建几个“Linux Native”分区和“Linux Swap ”分区,每个分区都必须通过 “挂载点”,分别载入到 “根(/)”或几个分“杈(如/boot、/home等)”上。

一个最基本的Linux系统需有一个“/”根文件系统分区、一个“Swap”交换文件分区和/boot分区,为了用户使用方便建议还需创建一个 /home分区。 为Linux建立分区有几种办法,一种是编辑现有空闲分区,使它成为Linux分区。如果没有空闲的磁盘空间,就需要将现有的分区删除后,腾出空间,以建立Linux分区。

图2中的/dev/hda6是在Windows下用Partition Magic为Linux准备的分区E盘(图1)。下面我们将在/dev/hda6上创建“/”、“/boot”、“swap”和“/home”分区。

(1)因 /dev/hda6 的文件类型是vfat,需先删除此分区,使它变成 “空闲”设备和“空闲分区”;

(2)创建“/”分区:选中“空闲”设备,按“新建”按钮,进入“添加分区”的窗口中,挂载点选“/”,文件系统类型选“ext3”,大小输入“5000MB”。 (3)创建“/boot”:同(2),在挂载点选“/boot”,文件系统类型选“ext3”,大小输入“100MB”。 (4)创建swap:一般swap分区的大小设定为机器内存的2~3倍为最佳,在“添加分区”的窗口,文件系统类型选“swap”,大小为600MB(如果内存为256MB),它不需要挂载点;

(5)创建“/home”:在挂载点选“/home”,文件系统类型选“ext3”,我们选择“使用全部可用空间”选项,将剩余的磁盘分配给/home区。

6.在完成了创建Linux分区后,接下来出现“引导装载程序配置”窗口。 对于Windows/Linux多操作系统共存的系统,开机时如何指定引导的操作系统,这需要借助开机引导装载程序(Boot Loader)。Linux内置了两种开机引导装载程序——LILO与Grub,在图3引导装载程序配置中,我们将开机启动的操作系统设为DOS(Windows),同时默认系统设置——以Grub作为引导装载程序。 7.配置好引导装载程序后,在接下来的“网络配置”、“防火墙的配置”、“附加语言支持”和“时区选择”的窗口中,我们都按系统默认进行选择。 8.和Windows XP相同,有一个称为“root”权限最大的管理员账户,使用这个账户登录主机可以完全掌握整个系统,安装过程中需要设置它的口令,请记住设置的口令。在后面的“验证配置”的窗口中,我们以系统默认的设置进行。 9.接下来是进行“个人桌面默认的设置”,选择“定制要安装的软件包集合”。然后是系统软件包的选择安装,在“选择软件包组”窗口中,为了测试每个软件包的功能,选择最后一个选项“全部安装”,安装全部软件包需4850MB的硬盘空间,按“下一步”后,系统开始进行软件包的安装。在安装过程中,系统会提示插入第二及第三张安装光盘。 10.软件包安装完成后,系统会提示“创建引导盘”,当系统无法引导的情况下,引导盘可作为紧急救援盘,我们强烈建议要制作引导盘。

11.随后系统显示“图形化界面(X)配置”、“显示器设置”和“定制图形化配置”的窗口,分别显示系统检测出的视频卡(显示卡)的型号、内存和显示器的型号以及色彩深度、屏幕分辨率等,一般按系统的默认值设置即可。 完成了上述这些操作后,系统会显示安装完成的提示窗口。当你重新启动机器后,Windows的开机画面将被多操作系统引导程序Grub的精美图案所替代。

三、Linux程序设计基础(Linux C、VI、GCC、GDB、Make、IDE)

所有Linux系统都提供广泛的编程支持,并将其作为一项基本配置。当我们安装完Linux,既可以使用其中任何语言编程,并且无需额外的花费。 Linux编程可分为四大类:

1、Shell编程 2、高级语言编程

3、图形用户界面GUI编程 4、系统调用高级编程 作为标准安装,所有Linux发行版本都包括了对Shell、GAWK、Perl、Tcl/Tk、C/C++编程,以及GNOME和KDE(K Desktop Environment,K桌面环境)开发的编程支持。

Linux软件开发一直在Internet环境下进行。大多数Linux软件是经过自由软件基金会(Free Software Foundation)提供GNU(GNU即GNU’s not UNIX)公开认证授权的,因而被称为GNU软件。 GNU软件免费提供给用户使用,并被证明是非常可靠和高效的。许多流行的Linux实用程序如C编译器、Shell和编辑器都是GNU软件应用程序。

四、Linux网络编程及应用/实例(Socket)

Linux网络编程实例详解

本文介绍了在Linux环境下的socket编程常用函数用法及socket编程的一般规则和客户/服务器模型的编程应注意的事项和常遇问题的解决方法,并举了具体代 码实例。要理解本文所谈的技术问题需要读者具有一定C语言的编程经验和TCP/IP方面的基本知识。要实习本文的示例,需要Linux下的gcc编译平台支持。

Socket定义

网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用—Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用 的Socket类型有两种:流式Socket—SOCK_STREAM和数据报式Socket—SOCK_DGRAM。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

Socket编程相关数据类型定义

计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Intenet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换。 我们要讨论的第一个结构类型是:struct sockaddr,该类型是用来保存socket信息的:

struct sockaddr {

unsigned short sa_family; /* 地址族, AF_xxx */ char sa_data[14]; /* 14 字节的协议地址 */ };

sa_family一般为AF_INET;sa_data则包含该socket的IP地址和端口号。

另外还有一种结构类型: struct sockaddr_in {

short int sin_family; /* 地址族 */

unsigned short int sin_port; /* 端口号 */ struct in_addr sin_addr; /* IP地址 */

unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大 小 */ };

这个结构使用更为方便。sin_zero(它用来将sockaddr_in结构填充到与struct sockaddr同样的长度)应该用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。sin_family通常被赋AF_INET;in_port和sin_addr应该转换成为网络字节优先顺序;而sin_addr则不需要转换。

我们下面讨论几个字节顺序转换函数:

htons()--\ ntohs()--\ 在这里, h表示\,n表示\,s 表示\,l表示 \ 。

打开socket 描述符、建立绑定并建立连接 socket函数原型为:

int socket(int domain, int type, int protocol);

domain参数指定socket的类型:SOCK_STREAM 或SOCK_DGRAM;protocol通常赋值“0”。Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。一旦通过socket调用返回一个socket描述符,你应该将该socket与你本机上的一个端口相关联(往往当你在设计服务器端程序时需要调用该函数。随后你就可以在该端口监听服务请求;而客户端一般无须调用该函数)。 Bind函数原型为 :

int bind(int sockfd,struct sockaddr *my_addr, int addrlen); Sockfd是一个socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。

最后,对于bind 函数要说明的一点是,你可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:

my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */ my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */ 通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。Bind()函数在成功被调用时返回0;遇到错误时返回“-1”并将errno置为相应的错误号。另外要注意的是,当调用函数时,一般不要将端口号置为小于1024的值,因为1~1024是保留端口号,你可以使用大于1024中任何一个没有被占用的端口号。

Connect()函数用来与远端服务器建立一个TCP连接,其函数原型为: int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); Sockfd是目的服务器的sockt描述符;serv_addr是包含目的机IP地址和端

原型为:

int select(int numfds,fd_set *readfds,fd_set *writefds,fd_set *exeptfds,struct timeval *timeout);

其中readfds、writefds、exceptfds分别是被select()监视的读、写和异常处理的文件描述符集合。如果你希望确定是否可以从标准输入和某个socket描述符读取数据,你只需要将标准输入的文件描述符0和相应的sockdtfd加入到readfds集合中;numfds的值是需要检查的号码最高的文件描述符加1,这个例子中numfds的值应为sockfd+1;当select返回时,readfds将被修改,指示某个文件描述符已经准备被读取,你可以通过FD_ISSSET()来测试。为了实现fd_set中对应的文件描述符的设置、复位和测试,它提供了一组宏: FD_ZERO(fd_set *set)----清除一个文件描述符集;

FD_SET(int fd,fd_set *set)----将一个文件描述符加入文件描述符集中;

FD_CLR(int fd,fd_set *set)----将一个文件描述符从文件描述符集中清除 ;

FD_ISSET(int fd,fd_set *set)----试判断是否文件描述符被置位。 Timeout参数是一个指向struct timeval类型的指针,它可以使select()在等待timeout长时间后没有文件描述符准备好即返回。struct timeval数据结构为:

struct timeval {

int tv_sec; /* seconds */

int tv_usec; /* microseconds */ };

我们通过程序3来说明: #i nclude sys/time.h #i nclude sys/types.h #i nclude unistd.h

#define STDIN 0 /*标准输入文件描述符*/ main() {

struct timeval tv; fd_set readfds; tv.tv_sec = 2;

tv.tv_usec = 500000; FD_ZERO(&readfds);

FD_SET(STDIN,&readfds);

/* 这里不关心写文件和异常处理文件描述符集合 */ select(STDIN+1, &readfds, NULL, NULL, &tv);

if (FD_ISSET(STDIN, &readfds)) printf(\

else printf(\

}

(程序3)

select()在被监视端口等待2.5秒钟以后,就从select返回.

五、Linux GUI编程及应用(QT)

Qt 是用来开发多平台GUI和应用程序的 C++ 工具包。它除了提供 C++ 类库之外,还提供了很多工具,使得开发更加快速容易。Qt支持多平台和国际化。因此,Qt开发出来的程序有更强的适应性。 Qt C++工具包自从1995年开始就已经成为许多商业软件的核心。Qt 被很多公司使用,如:AT&T, IBM, NASA, Xerox 和其他的一些小公司和组织。在保持易用性和强大功能的前提下,Qt 3.1 增加了很多重要的函数和新的类。Qt 的类尽可能的降低开发者的工作量,并且提供统一的接口以利于学习,Qt 是完全面向对象的。 1、Qt概要

Qt 包含了丰富的部件(在Windows术语中叫控件),这些部件提供了一些标准的功能。Qt 引进了一种创造性的内建对象通信机制--信号和槽,来代替过去不安全的回调技术。Qt还提供了传统的事件模型来处理鼠标按下,键盘敲击等事件。Qt多平台应用可以使用现代程序设计需要的所有用户界面功能,如:菜单,上下文菜单, 拖放, 和 可停靠工具栏等。

直观的命名规则和统一的设计方法简化了程序的设计。Qt 提供了一个视觉化的用户界面设计工具--Qt Designer。它支持Qt强大的布局功能。它可以用来设计GUI 或者通过内建的C++ 代码编辑器创建一个完整的程序。 Qt 可以很好的支持二维和三维的图形。它是平台无关OpenGL设计GUI工具包的事实标准。

Qt 可以使用标准的数据库创建平台无关的数据库应用。它内建了很多数据库的驱动,如:Oracle, Microsoft SQL Server, Sybase Adaptive Server, PostgreSQL, MySQL, 和ODBC-compliant 等。Qt Designer 完全整合了 Qt 的数据库功能,因此它可以提供数据库资料预览。包含了数据库的Qt相关部件,内建和自定制的部件都可以增加数据感知功能。

利用Qt 的风格和主题,Qt 在很多支持的平台上具有本地外观。一份源代码,只需要重新编译就可以运行于 Windows(95, 98, NT4, ME, 2000, XP), Mac OSX, Linux, Solaris, HP_UX 和其他支持X11的各种Unix系统。Qt程序也可以运行于嵌入Qt的系统。Qt 的 qmake 工具可以生成于目标平台相适应的makefiles 或者.dsp 文件。

许多用户在单一平台下使用Qt开发,如:Windows, Mac OS X和Unix系统。既然Qt的体系结构利用了平台底层的属性,所以它在特定的平台下会支持该平台特有的属性,例如:在Windows下支持ActiveX, 在 Unix 下支持 Motif 。 Qt使用Unicode 并且提供了大量的国际化支持。Qt 提供 QtLinguist 和其它的一些工具来支持翻译。应用程序的文本可以很容易的使用和混合许多Unicode支持的语言,如:阿拉伯文,中文,英文,希伯莱文,日文,俄文等。

Qt为许多特定的领域提供了特定的类。例如:XML 模块包括了SAX 和 DOM 解析器。通过使用与STL兼容的Qt集成类,对象可以保存在内存中。通过标准的协议,Qt 的输入输出和网络类支持本地和远程的文件处理。

通过使用插件和动态库,Qt应用程序可以扩展他们的功能。插件提供了额外的解码器,数据库驱动,图像格式,风格和部件等。动态库可以提供没有范围约束的功能。这些插件和动态库作为产品来出售。 Qt是一个被广泛使用的成熟的C++工具包。除了在商业上的应用之外,免费版本的Qt还是Linux桌面环境的基础。Qt的多平台开发系统,视觉化的开发方式,和高效的API将使得应用程序的开发更轻松,更具有乐趣。 在线参考:

http://www.trolltech.com/references/customers/ http://www.trolltech.com/references/partners/ 2、部件

Qt 具有一系列丰富的部件(按钮,卷轴等)可以满足很多应用。如果有特殊的需要,你可以很容易和灵活派生出子类。

Qt 提供了很多部件。所谓部件就是一个视觉元素,它们做和在一起来构成用户界面。按钮,菜单, 卷轴,消息窗口和应用程序窗口都是部件的例子。Qt 的部件并不严格区分控件和容器;所有的部件即可以用作控件有可以用作器。通过继承现有的Qt部件可以很容易的定制自己的部件。当然在极少数情况下,为了特殊的应用,有可能要重头开始创建自己的部件。

部件是QWidget,它的子类或者由这些子类创建的自定制类的实例。一个部件可以包含很多子部件。这些子部件显示在父部件的区域内。一个没有父部件的部件我们称之为顶层部件(如一个窗口),它一般会在桌面环境的任务栏上占据一个位置。任何部件都可以使顶层部件,任何部件都可以成为其他部件的子部件。布局管理器会自动的安排子部件在父部件区域中的位置,当然你也可以手动来安排。当父部件无效,隐藏或者被删除的时候,这些动作也会影响相应的子部件。 标签,消息框,工具提示等可以使用不止一种的颜色,字体和语言。例如:通过使用HTML的子集,Qt的文本部件就可以显示多语种的文本。 图17-1 Qwidget 类层次的一个片段

3、信号和槽

Qt 的内部对象通讯使用信号和槽机制。信号和槽机制很容易理解和使用,并且被Qt Designer支持。

GUI程序需要相应用户的动作。例如,当用户点击一个菜单项或者工具栏按钮的时候,程序就会执行相应的代码。一般情况下,我们希望任何类型的对象之间可以互相通讯。编程人员需要把相应的事件和代码联系起来。以前的工具包使用了一种回调机制,这种机制不是类型安全的,它不够强壮并且不是面向对象的。 Trolltech提出了“信号和槽”的解决方案。它是一种强大的内部对象通讯机制,可以完全代替以前工具包使用的回调和Message Maps机制。信号和槽非常灵活,完全面向对象并且是使用 C++来实现的。

使用以前的回调机制,为了把一个按钮和一段执行代码联系起来,则必须给这个按钮传递一个函数指针。这样,当这个按钮被按下时,这个函数就会被调用。但是以前的工具包并不保证传给这个函数的参数类型是正确的,这样就很容易发生问题。此外,回调机制把一个GUI元素和一个函数紧密的联系在一起,这样就很难独立的开发一个类。

图17-2 信号和槽连接的抽象图

Qt 的信号和槽却不同,当一个事件发生时,Qt 部件会发送一个信号。例如,当一个按钮被按下的时候,它就可能发送\信号。编程人员可以创建一个函数(槽)并调用connect()函数把这个槽和信号联系起来。Qt的信号和槽机制并不要求一个类知道另一个类的信息,因此我们可以开发出高度可重用的类。信号和槽是类型安全的,当类型不匹配的时候,它会给出警告。 例子,假设把退出按钮的clicked()信号和程序的quit()槽联系在一起,那么当用户点击退出按钮将终止程序。代码可能如下:

connect( button, SIGNAL(clicked()), qApp, SLOT(quit()) ); 信号和槽之间的联系可以在程序运行期间动态的添加和删除。

信号和槽的实现扩展了C++语法并且充分利用了C++的面向对象的性质。信号和槽是类型安全的,可以重载或者重新实现,而且它们在类中可以定义为公有的,保护的或者私有的。 4、GUI程序

用Qt可以既快速又容易的创建GUI程序,你可以手工编写代码也可以通过视觉化的编程工具Qt Designer来生成。

Qt提供了创建GUI程序所需的所有类和函数。你可以使用Qt来创建带有菜单,

工具栏和状态栏的基于视窗的程序,也可以创建带有按钮和标签的基于对话框的程序。Qt支持单文档界面(SDI)和多文档界面(MDI)。此外,Qt 也支持拖放和剪贴。

工具栏可以在其范围内任意移动,拖放到其他地方或者处于飘浮状态。这些功能是内建的,你不需要添加额外的代码。当然,如果需要你可以改变它的性质。 Qt简化了程序的设计。例如:如果菜单项,工具按钮和快捷键执行同一个动作,那么这个动作的实现代码可以只要一份。

Qt还提供了消息框和一系列的标准对话框来与用户交互。如:选择文件,文件夹,字体和颜色等。实际上,你有可能只是简单的使用Qt的一个语句就可以实现这个功能。

通过一个简单基本的例子来阐述Qt应用程序的基本结构。实验Hello world程序中将显示有一段飘动的彩色的“Hello World”文字。实验代码如下: ", hello.pro文件内容如下:

/***************************************************** *hello.pro

*****************************************************/ TEMPLATE = app

CONFIG = qt warn_on release HEADERS = hello.h SOURCES = hello.cpp \\ main.cpp

TARGET = hello ", main.cpp文件代码如下:

/***************************************************** *main.cpp

*****************************************************/ #include \

#include /*

The program starts here. It parses the command line and builds a message string to be displayed by the Hello widget. */

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

QApplication a(argc,argv); QString s;

for ( int i=1; i

if ( s.isEmpty() ) s = \Hello h( s );

h.setCaption( \

QObject::connect( &h, SIGNAL(clicked()), &a, SLOT(quit()) ); h.setFont( QFont(\h.setBackgroundColor( Qt::white ); // default bg color a.setMainWidget( &h ); h.show();

return a.exec(); } ", hello.h头文件代码如下:

/***************************************************** *hello.h

*****************************************************/ #ifndef HELLO_H #define HELLO_H

#include

class Hello : public QWidget {

Q_OBJECT public:

Hello( const char *text, QWidget *parent=0, const char *name=0 ); signals:

void clicked(); protected:

void mouseReleaseEvent( QMouseEvent * ); void paintEvent( QPaintEvent * ); private slots: void animate(); private: QString t; int b; }; #endif ", hello.cpp文件代码如下:

/***************************************************** *hello.h

*****************************************************/ #include \

#include #include #include #include /*

Constructs a Hello widget. Starts a 40 ms animation timer. */

Hello::Hello( const char *text, QWidget *parent, const char *name ) : QWidget(parent,name), t(text), b(0) {

QTimer *timer = new QTimer(this);

connect( timer, SIGNAL(timeout()), SLOT(animate()) ); timer->start( 40 ); resize( 260, 130 ); } /*

This private slot is called each time the timer fires. */

void Hello::animate() {

b = (b + 1) & 15; repaint( FALSE ); } /*

Handles mouse button release events for the Hello widget.

We emit the clicked() signal when the mouse is released inside the widget. */

void Hello::mouseReleaseEvent( QMouseEvent *e ) {

if ( rect().contains( e->pos() ) ) emit clicked(); } /*

Handles paint events for the Hello widget.

Flicker-free update. The text is first drawn in the pixmap and the pixmap is then blt'ed to the screen. */

void Hello::paintEvent( QPaintEvent * ) {

static int sin_tbl[16] = {

0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38}; if ( t.isEmpty() ) return;

// 1: Compute some sizes, positions etc. QFontMetrics fm = fontMetrics(); int w = fm.width(t) + 20; int h = fm.height() * 2; int pmx = width()/2 - w/2; int pmy = height()/2 - h/2;

// 2: Create the pixmap and fill it with the widget's background

QPixmap pm( w, h );

pm.fill( this, pmx, pmy );

// 3: Paint the pixmap. Cool wave effect QPainter p; int x = 10;

int y = h/2 + fm.descent(); int i = 0;

p.begin( &pm );

p.setFont( font() );

while ( !t[i].isNull() ) { int i16 = (b+i) & 15;

p.setPen( QColor((15-i16)*16,255,255,QColor::Hsv) ); p.drawText( x, y-sin_tbl[i16]*h/800, t.mid(i,1), 1 ); x += fm.width( t[i] ); i++; }

p.end();

// 4: Copy the pixmap to the Hello widget bitBlt( this, pmx, pmy, &pm ); }

实验代码说明: 1)头文件

在头文件中,一般包含了程序所需要的数据结构、常量、或者定义好的函数,如果在应用程序中的开始加入头文件,就可以方便的使用它定义好的一切。一般在应用程序中,还会包含此程序自己定义的头文件。如在main.cpp中包含的头文件有:

#include \

#include 在hello.h 中包含有头文件有: #include

在hello.cpp中包含的头文件有: #include \

#include #include #include #include

其中是所有Qt应用程序所必须包含的类,它创建了应用程序的对象,来管理整个应用程序,包括管理整个应用程序范围内的各种资源,例如默认得字体和光标等。hello.h是程序自己的头文件,它定义了自己的hello组件。程序中还用到了QpushButton按钮,它在中有定义。 由此可知,一个Qt应用程序一般包含三种头文件: ", 必要的头文件,,一般包含在main.cpp文件中。 ", 此应用程序自定义的组件的头文件,hello.h,一般在hello.h文件中定义,包含在main.cpp文件和hello.cpp文件中。

", 此应用程序用到的Qt的各类组件的头文件,如等,一般包含在hello.cpp文件或者需要的地方。 2)程序中的初始化

通常程序包含的主函数为:

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

main()函数是程序的入口.在使用Qt时,main()只是在把控制交给Qt库之前做一些初始化的工作。

argc是命令行参数的数目,argv是命令参数的数组.这并不是Qt 特有的,而是C++的特点,但是,Qt需要处理这些参数。 QApplication a( argc, argv );

a是本程序的QApplication对象,它被创建的目的是处理一些命令参数。注意,所有能被Qt识别的参数会被从argv中除去(argc 也会相应的减小为留下的参数的数目)。

注意:在使用任何Qt窗口系统之前,QApplication对象必须被创建。 3)创建组件

Qt中,在建立Qapplication对象之后,创建组件非常方便,只要建立所需要的组件类的对象即可。 s=”Hello World”; Hello h(s);

H组件被选择为应用程序的主组件。 4)设置组件的几何特性

在将显示组件之前,最好设置好组件的资源,如文字、大小、背景色、字体等,可以直接调用Qwidght类的成员函数,也可以重载它的成员函数。如: h.setCaption( \

QObject::connect( &h, SIGNAL(clicked()), &a, SLOT(quit()) ); h.setFont( QFont(\h.setBackgroundColor( Qt::white ); // default bg color 5)Signal和Slot

Qt的特征就是采用了Signal和Slot机制,这里最重要函数connect(),它连接发送端的信号至接收端的成员。当指定信号和成员函数时,用SIGNAL()和SLOT()宏。此实验中用到了2次此函数,一次连接单击信号clicked()和退出SLOT quit(),当运行这个程序时,单击组件时,将退出应用程序。

QObject::connect( &h, SIGNAL(clicked()), &a, SLOT(quit()) );

另一次是连接每次溢出时间,就飘动文字,当运行程序时,会看到飘动的文字。 connect( timer, SIGNAL(timeout()), SLOT(animate()) ); 6)实现组件和进入主循环

在创建了一个组件后,它总是不可见的,必须调用show()函数使其可见。 hello.show();

此函数用来显示组件和它的子组件。

创建组件并显示后,程序将调用exec()进入主事件循环体,它是Qapplication的成员函数。

return a.exec();

这里就是main()把控制权交给Qt的地方。

7)程序的编译和连接

编译时需要一个Makefile文件,在文件中编写了如何用头文件和源文件编译出目标文件的过程及一些设置。本实验中Makefile文件是通过tmake程序生成的。

1、按照实验说明,在Linux操作系统目录下新建一个文件夹,如hello,在此工程文件夹下建立工程文件,hello.pro,main.cpp,hello.h,hello.cpp。

2、在实验源程序完成后,使用tmake可执行程序生成Makefile文件,这是hello.pro文件是必须得,使用如下命令:

tmake -o Makefile hello.pro 这时,在文件目录下将生成Makefile文件,由于实验室编译ARM平台的程序hello,因此首先必须指定tmake.conf文件的路径,这个文件指定了所用的编译器设置,所以环境变量的设置是必须得,否则将会可能无法生成我们所需要的Makefile文件或者无法指定正确的交叉编译器。环境变量的参考设置如下:

export TMAKEDIR=$PWD

export TMAKEPATH=$PWD/tmake-1.13/lib/qws/linux-arm-g++ export PATH=$TMAKEDIR/bin:$PATH

3、在上一步中,我们已经生成了Makefile文件了,这样,我们就可以进行编译了,首先确定Makefile中的编译器使用的是正确的交叉编译器的路径。如果编译时报错交叉编译器命令错误,则必须修改Makefile文件中的交叉编译器,实验参考设置如下:

CC =/usr/local/arm/2.95.3/bin/arm-linux-gcc CXX = /usr/local/arm/2.95.3/bin/arm-linux-g++ LINK = /usr/local/arm/2.95.3/bin/arm-linux-gcc 如果编译中报错无法找到相关共享库文件,比如libjpeg.so.62库等,则首先确保在QT移植的实验中已经正确的交叉编译安装了jpeg-6b库文件的软件包。如果已经安装,但是仍然无法寻找到共享库文件的路径,则需修改Makefile文件中的相关的库的变量值,将库文件添加进来,比如参考设置如下:

SUBLIBS=-L/usr/local/arm/2.95.3/arm-linux/lib –ljpeg 可能根据安装情况的不同所包含的库文件的路径也可能不同。 如果此工程能顺利被编译,则会在工程文件目录下生成hello文件了,这个文件就是ARM平台的可执行程序。

4、生成hello文件后,下载到实验系统中观察程序的执行结果。

在/DM2410/root/bin目录下新建立一个qtopia的文本文件,其内容如下: #! Bin/sh

export set HOME=/root export set QTDIR=/opt/qt export set QPEDIR=/opt/qpe

export set QWS_KEYBOARD=\ export set QWS_MOUSE_PROTO=\ export set PATH=$QPEDIR/bin:$PATH

export set LD_LIBRARY_PATH=$QTDIR/lib:$QPEDIR/lib $QPEDIR/bin/hello –qws

然后将生成hello文件拷贝到/DM2410/root/opt/QPE/bin目录下,通过网线将实验系统通过NFS服务器挂接上PC主机,如果已经连接上了PC机的NFS服务器,则执行:

read(fd,&num,sizeof(int)); //从文件里读出数据 printf(\

printf(\scanf(\从键盘输入数据

write(fd,&num,sizeof(int)); //把输入的数据写入驱动程序文件中去 read(fd,&num,sizeof(int)); //读出输入的数据内容 printf(\

close(fd); //关闭文件 } else {

printf(\} }

十一、内核和设备驱动编程

一 、实验目的

1、学习Linux操作系统下内核程序的编写和应用 2、学习可编程接口芯片的编程控制方法 3、了解驱动程序的结构 4、了解驱动程序常用结构体 5、了解驱动程序常用函数 二、实验原理

1 关于设备驱动

驱动程序是一组代码,这部分代码负责将应用程序的一些需求,如读、写等操作,正确无误的传递给相关的硬件,并使硬件能够做出正确反应的代码。驱动程序像是一个黑盒子,它隐藏了硬件的工作细节,应用程序只需要通过一组标准化的接口,就可以实现对硬件的操作。 设备驱动程序的作用在于提供机制,即解决提供什么功能的问题,而如何使用这些功能则交给用户程序处理。 设备驱动程序是操作系统内核和机器硬件之间的接口,它为应用程序屏蔽硬件的细节,一般来说,Linux的设备驱动程序需要完成如下功能: (1)初始化设备;

(2)提供各类设备服务;

(3)负责内核和设备之间的数据交换;

(4)检测和处理设备工作过程中出现的错误。

更为方便的是,Linux下的设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得Linux下的设备操作犹如文件一般。在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。这些函数就是open ()、close ()、read ()、write () 等。

Linux主要将设备分为二类:字符设备和块设备(当然网络设备及USB等其它设备的驱动编写方法又稍有不同)。这两类设备的不同点在于:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,而块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回

请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备主要针对磁盘等慢速设备。本实验做的是字符设备的驱动编写。 2、Linux设备驱动程序分类

Linux设备驱动程序在Linux的内核源代码中占有很大的比例,源代码的长度日益增加,主要是驱动程序的增加。虽然Linux内核的不断升级,但驱动程序的结构还是相对稳定。 驱动程序基本框架如下 (1)初始化设备模块 (2)设备打开模块

(3)数据读写和控制模块

(4)中断处理模块(有的驱动程序没有) (5)设备释放,卸载模块

以上的各个模块基本上都有各自专门的函数,后面会具体介绍 3、内核模块

Linux以模块的形式加载设备类型,通常来说一个模块对应一个设备驱动,这样便于多个设备的协调工作也利于应用程序的开发和扩展。

设备驱动在准备好以后可以编译到内核中,在系统启动时和内核一起启动,这种方法在嵌入式Linux系统中经常被采用。但是通常情况下设备驱动的动态加载更为普遍,这使得开发人员不必在调试过程中频繁启动机器就能完成设备驱动的开发工作,本实验就是动态加载模块。

设备驱动在加载时首先调用入口函数init_module(),该函数完成设备驱动的初始化工作,比如寄存器置位、结构体赋值等一系列工作,其中最重要的一个工作就是向内核注册该设备,对于字符设备调用register_chrdev()完成注册,对于块设备需要调用register_blkdev()完成注册。注册成功后,该设备获得了系统分配的主设备号、自定义的次设备号,并建立起于文件系统的关联。设备在卸载时需要回收相应的资源,令设备的响应寄存器复位并从系统中注销该设备,字符设备调用unregister_chrdev()、块设备调用unregister_blkdev()。系统调用部分则是对设备的操作过程,比如open、read、write、ioctl等。图3-1为一个设备驱动模块动态挂载、卸载和系统调用的全过程。

用户空间内核空间模块insmodInit_module()register_XXX系统调用设备驱动内核模块rmmodClearup_module()unregister_XXX 图3—1 内核模块使用过程简图 4、编程中用到的函数

(1)int init_module()和void cleanup_module(void)

一个模块至少要包含这两个函数,装载模块时首先调用init_module(),在这里完成设备驱动的初始化工作,比如寄存器置位、结构体赋值等一系列动作,当然内核设备的注册也在这里完成。

卸载模块时会调用 cleanup_module(void),如果没有它,加载的模块就没法卸载了,这样累积下来会使得内核变得臃肿。 (2)register_chrdev()和unregister_chrdev()

对于字符设备,注册该设备用到的函数就是register_chrdev(),例如 ret=register_chrdev(MAJOR,NAME,&fops);

其中,参数MAJOR为主设备号, NAME为设备名,fops为包含基本函数入口点的结构体,类型为file_operations。

同样的,当注销该设备时,程序会调用unregister_chrdev(),例如

unregister_chrdev(MAJOR,NAME,&fops);

当模块被卸载时会调用cleanup_module(void),这里面就有unregister_chrdev()这个函数,参数同上

(3) open()函数,对设备特殊文件进行open()系统调用时,将调用驱动程序的open () 函数,int open(struct inode * inode ,struct file * file); 其中参数inode为设备特殊文件的inode (索引结点) 结构的指针,参数file是指向这一设备的文件结构的指针。open()的主要任务是确定硬件处在就绪状态、验证次设备号的合法性、控制使用设备的进程数、根据执行情况返回状态码(0表示成功,负数表示存在错误) 等;

(4)read()函数 当对设备特殊文件进行read() 系统调用时,将调用驱动程序read()数,void read(struct inode * inode ,struct file * file ,char * buf ,int count) ;

参数buf是指向用户空间缓冲区的指针,由用户进程给出,count 为用户进程要求读取的字节数,也由用户给出。read() 函数的功能就是从硬设备或内核内存中读取或复制count个字节到buf 指定的缓冲区中。在复制数据时要注意,驱动程序运行在内核中,而buf指定的缓冲区在用户内存区中,是不能直接在内

核中访问使用的,因此,必须使用特殊的复制函数来完成复制工作。 (5) write( ) 函数 当设备特殊文件进行write () 系统调用时,将调用驱动程序的write () 函数,它的形式,参数和read()一样,write ()的功能是将参数buf 指定的缓冲区中的count 个字节内容复制到硬件或内核内存中 (6)release()函数 当最后一个打开设备的用户进程执行close ()系统调用时,内核将调用驱动程序的release () 函数:void release (struct inode * inode ,struct file * file) ; release 函数的主要任务是清理未结束的输入/输出操作、释放资源、用户自定义排他标志的复位等。

(7) ioctl() 函数 该函数是特殊的控制函数,可以通过它向设备传递控制信息或从设备取得状态信息,函数原型为:int ioctl (struct inode * inode ,struct file * file ,unsigned int cmd ,unsigned long arg);

参数cmd为设备驱动程序要执行的命令的代码,由用户自定义,参数arg 为 相应的命令提供参数,类型可以是整型、指针等。

(8)一个重要结构体struct file_operations,例如程序中用到的 static struct file_operations fops={ .open= tyue_open, .ioctl= tyue_ioctl, .release= tyue_close};

程序中不管是open还是read,ioctl等函数都会有个指针类型参数指向这个结构体,这里会定义各种具体用于操作的函数,基本上看看这里就知道这个驱动程序可以干些什么 (9)创建设备的命令

在注册设备之前必须先创建这个设备,创建设备时会用到设备的主从设备号,当然最好同时指定其权限。应用程序通过设备文件系统(devfs)的名字(或节点)访问硬件设备,所有的设备节点在/dev目录下。利用mknod命令生成设备文件系统的节点,但只有超级用户才能生成设备文件。主设备号用于内核区分设备驱动,次设备号用于设备驱动区分设备。一个设备驱动可能控制多个设备。新的设备驱动要有新的主设备号。比如我创建了一个设备 mknod /dev/fei c 250 0 -m 666

如上我就在/dev/目录下创建了一个名为fei的字符设备,主设备号为250,次设备号为0,权限为666,可以读写,系统中本来已经有了一些设备,因此有些设备号已经被注册过了,为了避免冲突可以键入命令 # more /proc/devices

显示已经存在的设备及其主设备号等信息,如果我的注册成功,也可以在里面看

到的

三、实验过程

1、 实验最初是从加载hello world模块开始的,这是一个很简单的模块,只有最基本的初始化模块和卸载模块函数,程序如下 #include int init_module( void ) {

printk(\ return 0; }

void cleanup_module( void ) {

printk(\}

make后生成hello.ko,然后 #/sbin/insmod hello.ko

加载模块,然后在系统日志/var/messages/里输出“hello,world”,在我电脑上我有root权限,可以打开系统日志,实验室里我没打开,但是可以用命令 #dmesg

这样可以看到输出的结果,然后 #lsmod

可以看到我刚刚加载进去的模块hello.ko,键入命令 #/sbin/rmmod hello.ko

卸载模块,可以看到Goodbye world的输出,我记得在实验室这些做得很顺利,在我电脑上加载可以,也有输出结果,但是卸载时说moudle is in use,不给我卸载,我也没用模块啊

这个程序本身是没用的,没有实现任何功能,只是让我们熟悉一下模块的加载卸载罢了,为下面8253的驱动编写做些准备 2、可编程计数器8253驱动程序的编写 【1】8253简介

8253可编程定时/计数器是Intel公司生产的通用外围芯片之一,有3个独立的十六位计数器,技术频率范围为0~2MHz,它所有的技术方式和操作方式都通过编程控制。

1. 8253有六种工作方式: 方式0:计数结束中断 方式1:可编程频率发生器 方式2:频率发生器 方式3:方波频率发生器 方式4:软件触发的选通信号 方式5:硬件触发的选通信号

8253引脚图

# qtopia

此时将会观察到实验结果输出。实验系统液晶显示屏上将会显示一个有Hello World字符串的对话框界面。

六、Linux Shell编程及应用

Shell 简介

Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。 实际上Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核。不仅如此,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令组成的程序。Shell编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果。 Linux提供了像MicrosoftWindows那样的可视的命令输入界面--X Window的图形用户界面(GUI)。它提供了很多桌面环境系统,其操作就象Windows一样,有窗口、图标和菜单,所有的管理都是通过鼠标控制。现在比较流行的桌面环境系统是KDE和GNOME。 每个Linux系统的用户可以拥有他自己的用户界面或Shell,用以满足他们自己专门的Shell需要。 同Linux本身一样,Shell也有多种不同的版本。目前主要有下列版本的Shell: Bourne Shell:是贝尔实验室开发的。 BASH:是GNU的Bourne Again Shell,是GNU操作系统上默认的shell。 Korn Shell:是对Bourne SHell的发展,在大部分内容上与Bourne Shell兼容。 C Shell:是SUN公司Shell的BSD版本。 Z Shell:The last shell you’ll ever need! Z是最后一个字母,也就是终极Shell。它集成了bash、ksh的重要特性,同时又增加了自己独有的特性。

实现一个简单的shell程序

一、 实验内容

能在虚拟shell界面下响应一些简单的shell命令。实现自己模拟shell下的cd指令。未实现复杂的输入/输出从定向和管道。了解 Shell的执行过程。

二、 模拟shell的分析

模拟shell的程序先要可以启动一控制台用与用户的交互,接受用户的输入,显示运行结果。给出提示符后,输入我们自己的命令,将用户命令存储起来,分解该命令得到用户要掉用的指令和它的参数。如果该命令中有管道或输入/输出从定象的操作则告诉用户不支持该操作。

接下来我们就该完成寻找指令文件的工作了。通过系统调用到固定的路径的文件夹查找所要执行的指令文件,如果未找到则报错。如果我们找到了命令的路径,就可以执行命令了。通过调用fork()创建一个子进程,在子进程中执行命令。如果命令不是后台的则父进程要等待子进程的结束,才可以在接受用户的输入。如果命令是后台的则父进程不需要等待子进程的执行结束,就可以继续接受用户的输入。

另外我们要添加一个可以离开模拟shell的命令,该指令被输入用户就可以离开我们的模拟shell.

三、 模拟shell的设计

1、定义一个宏 #define BUFFERSIZE 255表示用户的最长输入

2、定义一个全局的数组char buffer[BUFFERSIZE+1];用于存放用户的输入以及后来的指令路径。

3、定义一个局部char *input;用于存放用户的最终输入。根据用户输入的具体的大小动态地创建数组input = (char*) malloc(sizeof(char) * (li_inputlen+1));将buffer[]中的内容拷贝到input[]中strcpy(input,buffer);

4、定义一个局部的指针数组char *arg[20];用于存放将input[]中的用户的命令分解。

5、定义一个变量int is_back = 0; 0表示前台进程。1表示是后台进程。

设置一个while(1)循环,用于一直等待用户的输入命令。检测用户的输入命令,如果是“leave”则break该循环。

用while循环来获取用户的输入,并将输入存放在buffer中。遇到换行或超出最大值则退出循环。

用for循环来拆分用户的输入,创建具体的每个参数的大小的arg[],arg[k] = (char *)malloc(sizeof(char)*j);

使用while循环来获取去环境变量中的路径列表。不断的查找用户的输入指令。

四、 实现的详细步骤

(1)在虚拟的shell界面上出现命令提示符($或#);

定义一个char *pathl来保存当前用户所处的工作目录。我们通过系统调用get_current_dir_name()函数来获得用户的工作目录,该函数的头文件为unistd.h,所以我们要包含该头文件(#include”unistd.h”)。令path = get_current_dir_name(),接着我们要把path里的内容打印出来不换行(printf(“%S>$”,path))。这样我们就完成了第一不的操作。

(2)获取用户指令:获取用户在命令提示符后面输入的命令及其参数,并注意命令输入的最大长度;

用一个字符数组来存放用户输入的命令,输入的最大值是BUFFERSIZE,通过getchar()来获取用户的输入当用户按下回车或输入的命令超最大长度输入完成。

如果输入的命令过长则告诉用输入的指令不可以超过BUFFERSIZE,用户可以接着输入要执行的命令。

如果输入正确则将buffer数组里具体的命令转储到input数组中使用malloc()函数来创建具体的input数组,数组的长度是buffer[]中命令长度li_inputlen。代码可以写为 input = (*char) malloc(sizeof(char)*(li_inputlen+1)); 多加一‘/0’所以要li_inputlen+1;

同时要将头文件包含进来(#include”malloc.h”)。然后进行拷贝 Strcpy(input,buffer),注意包含头文件(#include”string.h”)。 (3)解析指令:对用户输入的命令进行解析,解析出命令名和参数;

此时用户的命令存储在数组 input 里,接着我们学要来解析命

令。令里面有指令和它的参数,所以我们需要将它们分开。我们定义一指针数组(char *arg[20])来存放指令和参数。指令和参数的个数不得超出20个。如果

命令中有“<”,“>”和“|”的存在则告诉用户该指令不支持(printf(\is not supported!\);)。如果命令的最后是“&”,则表明该命令是需要后台运行将is_back设为1。 通过‘ ’,‘\\t’和‘\\0’来划分用户输入的命令。先将input数组的字符一个一的存到buffer[]中,当遇到‘ ’后在buffer[]里加入‘\\0’。这时buffer[]中有用的长度为j,然后arg[k] = (char*) malloc(sizeof(char)*j)来创建字符数组。将buffer[]考如arg[k]数组中(strcpy(arg[k],buffer))。然后将j=0,k++,接着取下一个参数。当取到最后一个字符是结束该操作。

(4)寻找命令文件:每个命令的执行都必须依靠对应的可执行文件,这些文件的存放路径存放在用户的PATH环境变量里;

我们需要到用户的.login文件中去找我们需要的环境变量PATH,其中路径变量是一组绝对路径的列表。当我们获取了路径变量,然后依次搜索各路径,来确定用户输入的命令文件的位置。

我们设置了一个退出的命令,因为我们的程序是使用了while(1)循环来接受用户的不断输入,我们需要有一个可以离开即退出循环的命令我们将该命令设为“leave”,并打印“bye-bye”。需要让arg[0]中的指令和“leave”比较(strcmp(arg[0], “leava”) ==0),如果相同退出该循环。

由于“cd ”指令是由shell提供的,所以我们需要写自己的“cd”指令。当我们检测到用户输入“ cd ”指令时,我们需要自己编写。当该指令的参数多与一个时提示参数错误。通过调用chdir(char*)函数来实现工作目录的切换。它的头文件是“unistd.h”。它的参数是工作目录的路径,如果查找不成功则返回-1。如果不成功则报告路径错误。成功则改变目录后继续等待用户的输入。

如果不是以上的指令,则我们需要去查找指令文件根据PATH中的路径。我们用一个函数来实现该操作,该函数为 int is_fileexist(char *comm)。函数返回-1表示没有该指令,返回0表是找到该命令。参数comm是我们要查找的指令。

在函数中先调用getenv(“PATH”)来获取PATH值放到path中即 path=getenv(“PATH”)其头文件为“stdlib.h”。由于PATH环境变量里面有很多路径,他们是用“:”分隔的。我通过将一次取一个路径,并将他们存到buffer[]里。将buffer里的路径和指令即才comm或arg[0]连成一个字符串(strcat(buffer,comm))。接着调用access(buffer,F_OK)来看该路径下是否有该指令,如果有返回0,没有则返回-1。access(char*,int )函数的第二个参数为F_OK表是查看文件是否存在,为其他表示文件权限的控制。access()函数的头文件是 unistd.h。如果不存在则继续查找其他路径,如果都没找到则告诉用户没找到该命令。如果找到则执行下一步。

(5)执行命令:可通过fork( )系统调用创建一个进程来完成执行命令的任务,具体的命令执行用execv( )函数。

当我们得到了指令的路径,就可以执行该命令了。通过调用fork()创建一个进程,在进程中执行该进程。Fork()会创建一个新子进程,其子进程会复制父进程的数据与堆栈空间并继承父进程的用户代码、组代码、环境变量、已打开的文件代码、工作目录和资源限制等。

如果fork()成功,则父进程会返回新建子进程的IP(PID),而在新建子进程中返回0。如果失败则返回-1。

使用exec(const char* path, const char* arg[])函数来执行我们的命令。

第一个参数为指令的路径及路径,第二个参数为指令和参数。

如果用户命令子进程为后台进程即is_back==1,则父进程不需要等待子进程的运行结束。如果用户命令子进程不是后台的则父进程需要等待子进程的结束,使用waitpid()函数waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则 参数 status 可以设成 NULL。参数 pid 为欲等待的子进程识别码,参数 option 可以为 0 。如果执行成功则返回子进程识别码(PID) ,如果有错误发生则返回返回值 -1。

注意头文件的引入,#include” sys/types.h”,#include” sys/wait.h” 运行界面及结果分析

运行的截图如下:

我将我的程序在Eclipse的控制台中的运行结果截图下来 运行的基本正常。

七、Linux PHP编程及应用

PHP 独特的语法混合了 C、Java、Perl 以及 PHP 自创的语法。

它可以比 CGI或者Perl更快速的执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。PHP具有非常强大的功能,所有的CGI的功能PHP都能实现,而且支持几乎所有流行的数据库以及操作系统。最重要的是PHP可以用C、C++进行程序的扩展!

Linux php安装

1.下载新的MySql_server.rpm

rpm -ivh Mysql_server_XXXX.rpm安装server平台

rpm -ivh Mysql_client_xxxx.rpm安装client包

如果你是更新安装的话,可能提示 confict,so replace rpm -ivh 为 rpm -Uvh

2.安装 apache

tar -zxvf httpd-2.2.6.tar.gz

cd httpd-2.2.6

。/configure——prefix=/usr/local/apache——enable-module=so make

make install

3.安装 php-5.2.4

tar -zxvf php-5.2.4.tar.gz

cd php-5.2.4 。/configure——prefix=/usr/local/php ——with-apxs2=/usr/local/apache2/bin/apxs

——with-config-file-path=/usr/local/lib——with-mysql make

make install

cp php.ini-dist /usr/local/lib/php.ini

4.配置

vi /usr/local/apache/conf/httpd.conf对apache做如下配置

#ServerAdmin一行改为您的邮箱地址

#DocumentRoot \此处为html文件主目录

#Options FollowSymLinks MultiViews为安全起见,去掉\

# DirectoryIndex default.php default.phtml default.php3 default.html default.htm #

# 设置apache的默认文件名次序

#AddType application/x-httpd-php .php .phtml .php3 .inc

#AddType application/x-httpd-php-source .phps

# 设置php 文件后缀

存盘退出

vi /usr/local/lib/php.ini

#register-golbals = On

存盘退出

5.启动apache

/usr/local/apache2/bin/apachectl start

如果提示一下错误:

Can not load /usr/local/apache2/modules/libphp5.so into server:

/usr/local/apache2/modules/libphp5.so :

Can't restore segment prot after reloc: Permission denied

Linux

因为无法加载php 模块,在调试PHP 程序是提示下载php ,或者显示php 源 代码,解决方法:

修改 httpd.conf

LoadModule php5_module modules/libphp5.so

AddType application/x-httpd-php .php

执行:chcon /usr/local/apache2/modules/libphp5.so -t shlib_t

注销系统重新进入

/usr/local/apache2/bin/apachectl start

PHP特性

PHP的特性包括:

1、开放的源代码: 所有的PHP源代码事实上都可以得到。 2、PHP是免费的。 和其它技术相比,PHP本身免费。

3、php的快捷性 程序开发快,运行快,技术本身学习快。嵌入于HTML:因为PHP可以被嵌入于HTML语言,它相对于其他语言,编辑简单,实用性强,更适合初学者。

4、跨平台性强: 由于PHP是运行在服务器端的脚本,可以运行在UNIX、LINUX、WINDOWS下。

5、效率高: PHP消耗相当少的系统资源。 6、图像处理: 用PHP动态创建图像

7、面向对象: 在php4,php5 中,面向对象方面都有了很大的改进,现在php完全可以用来开发大型商业程序。

8、专业专注: PHP支持脚本语言为主,同为类C语言。

技术应用

1,伪静态

2,静态页面生成 3,数据库缓存 4,过程缓存

5,div+cssw3c标准 6,大负荷 7,分布式

8,jquery框架集成 9,flex

10,桌面程序应用(不擅长) 11,支持MVC模型

PHP的优点

一、学习过程和方法

PHP的语法类似于C,Perl,ASP或者JSP。对于那些对上述之一的语言较熟悉的人来说,PHP太简单了。相反的,如果你对PHP了解较多,那么你对于其他几种语言的学习都很简单了。你只需要很短的时间内将PHP的核心语言特点全部掌握,你可能已经非常了解HTML,甚至你已经知道怎样用编辑设计软件或者手工来制作好看的WEB站点。由于PHP代码能够无障碍的添加进你的站点,在你设计和维护站点的同时,你可以很轻松的加入PHP使得你的站点更加具有动态特性。

二、数据库连接

PHP可以编译成具有与许多数据库相连接的函数。PHP与MySQL是现在绝佳的组合,如果再加上Apache服务器,就是相当完美的了。你还可以自己编写外围的函数取间接存取数据库。通过这样的途径当你更换使用的数据库时,可以轻松的更改编码以适应这样的变化。PHPLIB就是最常用的可以提供一般事务需要的一系列基库。 三、可扩展性

就像前面说的那样,PHP已经进入了一个高速发展的时期。对于一个非程序员来说为PHP扩展附加功能可能会比较难,但是对于一个PHP程序员来说并不困难。

四、PHP优点面向对象

PHP提供了类和对象。基于web的编程工作非常需要面向对象编程能力。 五、PHP优点可伸缩性

传统上网页的交互作用是通过CGI来实现的。CGI程序的伸缩性不很理想,因为它为每一个正在运行的CGI程序开一个独立进程。解决方法就是将经常用来编写CGI程序的语言的解释器编译进你的web服务器(比如mod_perl,JSP)。PHP就可以以这种方式安装,虽然很少有人愿意这样以CGI方式安装它。内嵌的PHP可以具有更高的可伸缩性。

八、Linux Java编程技术及应用

在LINUX下配置JAVA开发环境【转自http://chenzhe.blogchina.com】

1. 去http://java.sun.com/j2se/1.4.2/download.html 下载一个Linux Platform的JDK,

建议下载RPM自解压格式的(RPM in self-extracting file,j2sdk-1_4_2_06-linux-i586-rpm.bin); 2. 上载到Linux服务器上,在shell下执行命令:

[root@LinuxServer rpm]# chmod 755 j2sdk-1_4_2_06-linux-i586-rpm.bin [root@LinuxServer rpm]# ./j2sdk-1_4_2_06-linux-i586-rpm.bin

这时会有一段Sun的协议,敲几次空格键,当询问是否同意的时候,敲yes就可以了。

Sun Microsystems, Inc. Binary Code License Agreement for the

JAVATM 2 SOFTWARE DEVELOPMENT KIT (J2SDK), STANDARD EDITION, VERSION 1.4.2_X ...

Do you agree to the above license terms? [yes or no]yes Unpacking... Checksumming... 0 0

Extracting...

UnZipSFX 5.40 of 28 November 1998, by Info-ZIP (Zip-Bugs@lists.wku.edu). inflating: j2sdk-1_4_2_06-linux-i586.rpm Done.

注: 如果直接执行unzip命令来解压也是可以的,总之得到一个rpm软件包.

3. 程序会自动生成一个j2sdk-1_4_2_06-linux-i586.rpm文件,这是主程序包,下面来安装;

[root@LinuxServer rpm]#rpm -ivh j2sdk-1_4_2_06-linux-i586.rpm Preparing... ########################################### [100%] 1:j2sdk ########################################### [100%]

4. 设置环境变量

通常都喜欢用export命令直接在shell下设置

[root@LinuxServer rpm]# export JAVA_HOME=/usr/java/j2sdk1.4.2_06 [root@LinuxServer

rpm]#

export

CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar [root@LinuxServer rpm]# export PATH=$PATH:$JAVA_HOME/bin

当然这样设置环境变量是可以生效的,但是只对当前shell生效。

如果从另外一个shell登陆,将不能使用刚才设置的变量。所以最好的方法还是修改.bashrc文件。

[root@LinuxServer rpm]#vi .bashrc set JAVA_HOME=/usr/java/j2sdk1.4.2_06 export JAVA_HOME

set PATH=$PATH:$JAVA_HOME/bin export PATH

set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export CLASSPATH

当然也可以通过更改/etc/profile来实现,不过不推荐这么做, 因为这样的设置将对所以用户的shell都生效,对系统安全会产生影响。 就是在这个文件的最后加上:

export JAVA_HOME=/usr/java/j2sdk1.4.2_06

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$PATH:$JAVA_HOME/bin

下面来验证一下变量设置是否生效(####注意:在验证前先logout一下,再重新登陆);

[root@LinuxServer rpm]# echo $JAVA_HOME /usr/java/j2sdk1.4.2_06/

[root@LinuxServer rpm]# echo $CLASSPATH

/usr/java/j2sdk1.4.2_06/lib/dt.jar:/usr/java/j2sdk1.4.2_06/lib/tools.jar

[root@LinuxServer rpm]# echo $PATH

/usr/java/j2sdk1.4.2_06/bin/:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:

/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin [root@LinuxServer rpm]# JAVA-version JAVA version \

JAVA(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_06-b03) JAVA HotSpot(TM) Client VM (build 1.4.2_06-b03, mixed mode)

5. 环境设置OK,看看JDK是否能正常工作,我们来写一个测试文件test.java [root@LinuxServer rpm]#vi test.java class test {

public static void main(String[] args) {

System.out.println(\} }

保存退出,下面来编译、执行;

[root@LinuxServer text]# javac test.java [root@LinuxServer text]# JAVA test Hello World!

OK,工作正常。

6. 如果要使某个用户具有运行java命令的权限,只要修改其bash初始化文件即可。

比如要给用户longware以运行java命令的权限, [root@LinuxServer root]# vi /home/longware/.bashrc set JAVA_HOME=/usr/java/j2sdk1.4.2_06 export JAVA_HOME

set PATH=$PATH:$JAVA_HOME/bin export PATH

set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export CLASSPATH

7. 至此,Linux上JDK的安装完毕。下面安装eclipse-SDK-3.0-linux-gtk.zip 去www.eclipse.org下载一个eclipse3.0. 将eclipse-SDK-3.0-linux-gtk.zip解压到/opt中

8、编写一个脚本用于启动eclipse

#!/bin/bash #

# 执行 eclipse 3 #

export JAVA_HOME=/usr/java/j2sdk1.4.2_06 export CLASSPATH=/usr/java/j2sdk1.4.2_06/lib /opt/eclipse/eclipse

-vm

/usr/java/j2sdk1.4.2_06/bin/java

-data

/home/chenzhe/workspace &

# -vm 参数用以指定使用哪一个 jvm 来执行Eclipse, # -date参数用以指定Eclipse的数据目录。

在此指定其存在用户根目录(/home/chenzhe/)下的workspace目录中

将脚本保存到/usr/local/bin中,叫eclipse,并给eclipse分配755权限

9、在桌面上创建一个启动器,

随便选一个图标,路径设置到/opt/eclipse/eclipse,/opt/eclipse/icon.xpm是eclipse自身带的图标.

10、双击图标,或者在终端输入eclipse, 搞定!

九、Linux数据库编程技术及应用

LinuxLinux数据库程序开发数据库程序开发

Skeleton.MySQL简介 .MySQL管理

.Mysql存储引擎

.数据库开发的基本原理 .开发实例

MySQL简介

.MySQL是一个小型关系型数据库管理系 统,开发者为瑞典MySQLAB公司,在2008 年1月16号被Sun公司收购。

.MySQL被广泛地应用在Internet上的中小型 网站中。由于其体积小、速度快、总体拥 有成本低,尤其是开放源码这一特点

E:\\Jeffrey\\Screenshot-MySQL - Mozilla Firefox.png MySQL

MySQL

.MySQL是一个广受Linux社区人们喜爱的半 商业的数据库。MySQL是可运行在大多数 的Linux平台(i386,Sparc等),以及少许非 甚至非Unix平台。

http://www.it.com.cn/f/news/081/17/mysql-logo.jpg

MySQL特性

http://www.it.com.cn/f/news/081/17/mysql-logo.jpg .使用C和C++编写,并使用了多种编译器进 行测试,保证源代码的可移植性

.支持AIX、FreeBSD、HP-UX、Linux、 Mac OS、NovellNetware、OpenBSD、 OS/2 Wrap、Solaris、Windows等多种操 作系统

.为多种编程语言提供了API。这些编程语言 包括C、C++、Eiffel、Java、Perl、PHP、 Python、Ruby和Tcl等。

MySQL特性

.支持多线程,充分利用CPU资源;

.优化的SQL查询算法,有效地提高查询速 度;

.既能够作为一个单独的应用程序应用在客 户端服务器网络环境中,也能够作为一个 库而嵌入到其他的软件中提供多语言支 持,常见的编码如中文的GB 2312、

BIG5,日文的Shift_JIS等都可以用作数据 表名和数据列名;

MySQL特性

.提供TCP/IP、ODBC和JDBC等多种数据库 连接途径;

.提供用于管理、检查、优化数据库操作的 管理工具;

.可以处理拥有上千万条记录的大型数据 库。

MySQL管理

.可以使用命令行工具管理MySQL数据库 (命令mysql和mysqladmin),也可以从

MySQL的网站下载图形管理工具MySQLAdministrator和MySQLQuery Browser。

Mysql存储引擎

.MyISAMMysql的默认数据库,最为常用。拥有 较高的插入,查询速度,但不支持事务

.InnoDB事务型数据库的首选引擎,支持ACID事 务,支持行级锁定

BDB源自Berkeley DB,事务型数据库的另一种 选择,支持COMMIT和ROLLBACK等其他事务特 性

.Memory所有数据置于内存的存储引擎,拥有极 高的插入,更新和查询效率。但是会占用和数据 量成正比的内存空间。并且其内容会在Mysql重新 启动时丢失 .????

.数据库管理员界面

数据库程序开发原理

数据库管理工具

流程图: 磁盘: 数据库 数据库

文本框: 数据库服务器进程 数据库服务器进程 创建数据库 数据库管理员

数据库程序开发原理

.开发人员界面

开发工具

流程图: 磁盘: 数据库 数据库

数据库服务器进程数据库驱动程序 开发工具类库 开发人员

数据库程序开发原理

.用户界面

应用程序

流程图: 磁盘: 数据库 数据库

文本框: 数据库服务器进程 数据库服务器进程

文本框: 数据库驱动程序 数据库驱动程序

文本框: 开发工具类库 开发工具类库

Screenshot-火车站点查询-1 用户

数据库程序开发

.QT中数据库开发用到的类

–用户接口层:这些窗口部件不仅连接数据库还 可为用户所浏览。

–应用编程接口层:这些类存取数据库。

–驱动程序层:这个层在数据库和SQL类之间提 供了底层的桥梁。

数据库程序开发

.QT中数据库开发用到的类

–QSqlDatabase:用来连接数据库。

–QSqlQuery,QSqlCursor:用来操作数据库。 –数据库操作支持类:QSqlError、QSqlField、 QSqlIndex和QSqlRecord。

–驱动层类:QSqlResult、QSqlDriver和 QSqlDriverFactoryInterface。编程时很少用 到。

// 建立连接

#include

#include

#include \

intmain( intargc, char *argv[] ) {

QApplicationapp( argc, argv);

QSqlDatabase*defaultDB=

QSqlDatabase::addDatabase( DB_SALES_DRIVER );

if ( defaultDB) {

defaultDB->setDatabaseName( DB_SALES_DBNAME );

defaultDB->setUserName( DB_SALES_USER );

defaultDB->setPassword( DB_SALES_PASSWD );

defaultDB->setHostName( DB_SALES_HOST );

if ( defaultDB->open() ) {

// 数据库被成功打开,我们现在可以运行SQL命令。 } }

return 0; }

//利用QSqlCursor访问数据库

#include

#include

#include

#include \

boolcreateConnections();

intmain( intargc, char *argv[] ) {

QApplicationapp( argc, argv);

if ( createConnections() ) {

QSqlCursorcur( \指定表/视图名称

cur.select(); // 我们将检索每一条记录

while ( cur.next() ) {

qDebug( cur.value( \

cur.value( \

cur.value( \ } }

return 0; }

//利用QSqlQuery访问数据库

#include

#include

#include

#include \

boolcreateConnections();

intmain( intargc, char *argv[] ) {

QApplicationapp( argc, argv);

if ( createConnections() ) {

QSqlDatabase*oracledb= QSqlDatabase::database( \

// 从oracle数据库向ODBC(默认)数据库复制数据

QSqlQuerytarget;

QSqlQueryquery( \

if ( query.isActive() ) {

while ( query.next() ) {

target.exec( \

query.value(0).toString() +

\ } } }

return 0; }

下面讲一个实例

.本章利用MySQL数 据库和QT联合开发 了一个火车站点查询 程序。

1.数据库的建立

.首先介绍MySql的安装过程,本实验至少需

要安装一个的服务器端和一个MySqlAdministrator的图形界面客户端。MySql服

务器端用来完成数据库的各种操作,实现 数据存储,MySqlAdministrator用来完成和 用户的交互,实验中,我们主要使用它完 成数据库的建立工作。

.在安装MySql之前,可以从Sun公司的官方 网站上下载相关的文件(MySql已经被Sun 公司收购,成为了Sun公司的产品)。 MySql官方下载地只是

http://dev.mysql.com/downloads/mysql/5.0.html。MySqlAdministrator的官方下载地

址是http://dev.mysql.com/downloads/gui- tools/5.0.html。

.如果不能确定自己的Linux版本,你可以通 过下载源代码包进行安装,这样可以保证 程序的兼容性,在一般情况下,你可以进 入root用户,通过如下命令完成编译和安 装。整个编译和安装的过程可能会比较漫 长。

.如果你使用的Linux是Ubtuntu,你可以采用 一些简单的办法,安装过程会非常方便快 捷。首先,是安装MySql的服务器端,使用 如下命令:

.$ sudoapt-get install mysql-server-5.0

.在安装的过程中,安装程序会要求你输入 管理员(用户名为root)的密码,这个密码 一定要记住,这是以后进行数据库操作所 必备的。

.接着需要安装MySqlAdministraor。通过

“应用程序”>“添加删除”命令,打开“添加/删 除程序”的对话框,输入“MySql”进行检索, 然后从检索结果列表中选择 Administrator”(可能会检索不到,那么需 要在“显示”项中选择“所有开源应用程序”, 这样重新检索就出现)

打开MySqlAdministrator登录对话框

登录成功后系统会出现MySqlAdministrator的主界面

输入MySql,进入MySql控制台界面,在控制台模式 下,可以使用命令操作MySql数据库,例如,在

“MySql>”的提示符下输入“status”回车,查看你的 MySql登录信息

.选择Catalog选项,右击选择Create Schema,MySql提示用户输入新的数据库 名称,输入“StationHelper”,然后单击确 定,创建数据库StationHelper

.然后选择Tables选项卡,点击下方Create Tables按钮,通过Table Editor对话框来创 建表,如下图所示。首先选中“Columns and Indices”题签中表格的空白列,可以观 察到下面的“Column Details”项变为可填写 状态,填写相应的列信息

在表的创建过程中表的类型要选择InnoDB类型,只 有这样创建的数据库才支持外键等属性,默认的表 的类型为“MylSAM”。

.如果使用图形界面,需要额外安装一个软 件包,该软件包的名称叫做MySQLQuery Browser,用来查看数据库表中的数据,该 软件需要一个libgtkhtml的运行库。我们在 Ubuntu系统下在终端中键入如下命令即可

安装MySQLQuery Browser软件包:

.$ sudoapt-get install mysql-query-browser .按照填写MySQLAdministrator登录信息的 方法,填写其他登录信息,然后单击 Connect按钮登录到MySQL数据库中。

.登录成功后会出现MySQLQuery Browser 的主界面,如下图所示,在该窗口中可以 对数据库中的数据进行操作。操作主要采 用SQL语句进行交互,我们在窗口上方的 文本框中输入SQL语句,然后单击右侧的 “Execute”按钮执行该SQL语句,

.如果使用命令行模式添加数据,需要以root 用户进入mysql数据库。然后使用use命令 打开StationHelper数据库。然后使用 INSERT语句插入数据。用户可以通过 SELECT语句检查输入是否成功。

.$ mysql-uroot-p<你的密码> .mysql> use StationHelper

.mysql> INSERT INTO stations VALUES(1, ‘大连’);

.mysql> SELECT * FROM stations;

2 .绘制应用程序界面

.设计界面所用的空间大部分在上一节QT中 有说明。此外,还有一些额外的控件,其 中GroupBox控件在“Containers”中, “DataBrowser”和“DataTable”控件在 “Database”中。

.“DataBrowser”中文称作“数据浏览控件”, 用来对数据库中的数据进行逐条浏览的,

.“DataTable”中文称作“数据表格”,用来对数 据中的数据进行表格形式的查看。

.添加数据库相关的控件的时候,QT 会弹出 “Data Browser Wizard”向导。在该对话框 中选择相应的数据库,和需要进行的查 询,QT会根据用户在这个向导中所作的设

置,自动把相应的查询与控件进行关联, 使这些控件可以正常的工作。如下图:

列车时刻表UI

TrainsList对话窗UI

运行结果

.单击窗口下方 .的“详情”按钮

.可以查看T131.列车的详细情况

十、嵌入式Linux系统设计及应用

步骤:a)登录进入linux操作系统,打开命令窗口进入myprojects文建一文件夹取名为charmod命令如下:

cd/myprojects mkdir charmod

b)进入charmod文件夹,新建文件globalvar.c,并在其中输入 cd

charmod //进入文件夹

vi globalvar.c //新建文件globalvar.c

c)保存文件进入命令行模式并对其进行编译. d)新建应用层测试文件globalvartest.c e)保存文件并对其进行编译。 f)载入驱动模块globalvar.o

g)创建节点以便于访问设备,其命令如下所示:

mknod/dev/globalvar c 254 0

h)运行应用层测试程序

字符设备驱动程序流程图 声明许可证 register_chrdev() 注册字符设备 源程序代码如下:

Ret<0 Y N 失败退出 module_init(globalvar_init) 初始化设备 struct file_operations 填充结构体 Read()读设备数据 Write()往设备写数据 unregister_chrdev() 取消模块注册 Ret<0 N Y module_exit(globalvar_exit) 退出 卸载模块

/*globalvar.c*/

#include #include #include #include #include #include #include #include #include #include #include #include

#define MAJOR_NUM 254 //定义主设备号为254 static int global_var=0;

MODULE_LICENSE(\用来声明一个模块的许可证

static ssize_t globalvar_read(struct file*file,char

*buf,size_t len,loff_t*ppos) //读函数read()完成从设备中读出数据 {

copy_to_user(buf,&global_var,sizeof(int)); //把驱动程序缓冲区的内容放到用户程序中; return sizeof(int); }

static ssize_t globalvar_write(struct file*file,char *buf,size_t len) //写函数write()完成往设备中写入数据 {

copy_from_user(&global_var,buf,sizeof(int)); // 把用户程序的内容放到驱动程序缓冲区内; return sizeof(int); }

static struct file_operations globalvar_fops={ read: globalvar_read, write: globalvar_write,

}; // 填充设备驱动程序接口,即函数入口点

static int globalvar_init(void) //初始化设备 {

int ret;

ret=MAJOR_NUM,\

&globalvar_fops); //此函数用于设备的注册,其中MAJOR_NUM为主设备号,globalvar为设备名,globalvar_fops为包含基本函数入口点的

file_operations类型结构体 if(ret<0) {

printk(\} else {

printk(\}

return ret; }

static void globalvar_exit(void) {

int ret;

ret=unregister_chrdev(MAJOR_NUM,\用于取消已注册的驱动,当执行卸载函数时,它会调用此注销函数将设备进行注销。

if(ret<0) {

printk(\} else {

printk(\} }

module_init(globalvar_init); // 加载驱动程序时,内核自动调用,初始化硬件,注册设备

module_exit(globalvar_exit); //卸载驱动程序时,内核自动调用,删除设备节点,注销设备

/*globalvartest.c*/ #include #include #include #include int main() {

int fd,num; //定义文件描述符

fd=open(\以可读可写方式打开驱动程序文件; if(fd!=-1) {

本文来源:https://www.bwwdw.com/article/dvn2.html

Top