收藏 分销(赏)

《嵌入式Linux应用开发》.doc

上传人:可**** 文档编号:4217166 上传时间:2024-08-26 格式:DOC 页数:48 大小:447KB
下载 相关 举报
《嵌入式Linux应用开发》.doc_第1页
第1页 / 共48页
《嵌入式Linux应用开发》.doc_第2页
第2页 / 共48页
《嵌入式Linux应用开发》.doc_第3页
第3页 / 共48页
《嵌入式Linux应用开发》.doc_第4页
第4页 / 共48页
《嵌入式Linux应用开发》.doc_第5页
第5页 / 共48页
点击查看更多>>
资源描述

1、 华清远见嵌入式培训中心嵌入式Linux应用开发实验指导书嵌入式Linux应用开发培训组编著课程编号:FSLA1001课内实验学时:18学时华清远见嵌入式培训中心2007年.版权所有实验项目及学时分配 序号实 验 项 目 名 称学时类型难易度1-1学习Linux系统命令0.5基础1-2配置tftp服务(*)0.5基础1-3配置nfs服务(*)0.5基础1-4建立嵌入式开发环境0.25基础1-5下载内核到嵌入式平台(*)0.25基础1-6挂载NFS根文件系统(*)0.5基础1-7编写并下载应用程序到嵌入式平台0.5基础2-1使用ps命令查看进程信息0.25基础2-2使用proc文件系统查看进程信

2、息0.25基础2-3使用fork、exit和exec系统调用编写多进程程序1设计2-4编写一个守护进程1设计2-5用消息队列编写一个客户端服务器通信的程序1.5设计2-6编写串口通信的多进程程序1.5综合3-1编写一个简单的网络通信程序(socket)1综合3-2Tcp网络编程2综合4-1基于Qt实现hello world对话框程序0.5设计4-2嵌入式Linux GUI虚拟帧缓存主机移植1.0设计4-3基于Qt图形界面的温度计的实现1.5综合实验1-1 学习Linux系统命令 实验目的与意义通过此实验,学员可以熟练运用Linux的操作,掌握GNU编程环境和基本命令。本实验是后面进行应用开发系

3、列实验的基础内容。Linux初级用户必须熟练掌握本实验的所有内容。 基本原理和方法在Linux环境下进行由浅入深的练习,并对比Windows环境下的程序设计。 实验内容及步骤1. 练习Linux下的基本命令使用方法l cd:切换目录l ls:列出目录下的内容l cp:文件复制l rm:删除文件l mv:转移/更名文件l ln:建立文件链接l mkdir:创建文件夹l rmdir:删除文件夹l kill:杀死系统中某个进程2. 练习vi编辑器的基本用法l 进入编辑模式:i、a、ol 进入命令模式:ESCl 保存文件:在命令模式下,输入“:w”l 退出vi编辑器:在命令模式下,输入“:q”l 删除

4、某行内容:在命令模式下,输入“dd”l 将某行内容添加到剪贴板:在命令模式下,输入“yy”l 将剪贴板中的内容复制到某行:在命令模式下,输入“p”实验1-2 配置tftp服务 实验目的与意义通过此实验,学员可以熟悉tftp服务的配置方法。 基本原理和方法TFTP(TrivialFileTransferProtocol)即简单文件传送协议,最初打算用于引导无盘系统(通常是工作站或X终端)。和使用TCP的文件传送协议(FTP)不同,为了保持简单和短小,TFTP将使用UDP。TFTP的代码(和它所需要的UDP、IP和设备驱动程序)都能适合只读存储器。Linux系统的服务以配置文件方法进行配置,因此要

5、找到tftp服务的配置文件所在,并根据实际情况配置根目录和权限等内容。tftp服务的配置文件tftp在/etc目录下,找到并编辑该文件即可。ubuntu发行版采用了新的服务机制,与RedHat Linux的tftp配置有少许不同,但是原理相同。 实验内容及步骤编辑tftp文件,使之符合嵌入式Linux开发需要,并设置其根目录在/tftpboot。servicetftp disable=no socket_type=dgram protocol=udp wait=yes user=root server=/usr/sbin/in.tftpd server_args=-s/test per_sou

6、rce=11 cps=1002 flags=IPv4 实验1-3 配置NFS服务 实验目的与意义通过此实验,学员可以熟悉nfs服务,了解nfs服务原理和配置方法。 基本原理和方法NFS是网络文件系统(Network File System)的简称,是分布式计算系统的一个组成部分,可实现在异种网络上共享和装配远程文件系统。nfs的配置文件是/etc/exports,所以我们查看并修改这个文件。在该文件中增加根文件系统。 实验内容及步骤1. 安装nfs服务器端和客户端(如果没有该软件包)服务器端:rootvm root#apt-get install portmap nfs-kernel-serv

7、er客户机端:rootvm root#apt-get install portmap nfs-common2. 编辑/etc/exports,在其中增加要共享的目录rootvm root#gedit /etc/exports配置下面一行/rootfs *(rw,sync,no_root_squash)/rootfs是要共享的目录,代表允许所有的网络段访问,rw是可读写权限,sync是资料同步写入内存和硬盘,no_root_squash是NFS客户端分享目录使用者的权限,如果客户端使用的是root用户,那么对于该共享目录而言,该客户端就具有root权限3. 重启服务rootvm root#/et

8、c/init.d/portmap restartrootvm root#/etc/init.d/nfs-kernel-server restart或执行rootvm root#exportfs -ra(重新扫描/etc/exports,使用户修改/etc/exports配置文件不必重启NFS服务 )rootvm root#/showmount -e显示hostname中/etc/exports里设定的共享目录了解NFS共享的常用参数:ro 只读访问rw 读写访问sync 所有数据在请求时写入共享async NFS在写入数据前可以相应请求secure NFS通过1024以下的安全TCP/IP端口

9、发送insecure NFS通过1024以上的端口发送wdelay 如果多个用户要写入NFS目录,则归组写入(默认)no_wdelay 如果多个用户要写入NFS目录,则立即写入,当使用async时,无需此设置。hide 在NFS共享目录中不共享其子目录no_hide 共享NFS目录的子目录subtree_check 如果共享/usr/bin之类的子目录时,强制NFS检查父目录的权限(默认)no_subtree_check 和上面相对,不检查父目录权限all_squash 共享文件的UID和GID映射匿名用户anonymous,适合公用目录。no_all_squash 保留共享文件的UID和GI

10、D(默认)root_squash root用户的所有请求映射成如anonymous用户一样的权限(默认)no_root_squas root用户具有根目录的完全管理访问权限anonuid=xxx 指定NFS服务器/etc/passwd文件中匿名用户的UIDanongid=xxx 指定NFS服务器/etc/passwd文件中匿名用户的GID了解nfs相关的监控程序:l 基本NFS:rpc.nfsd是NFS服务器监控程序,它通过/etc/rc.d/init.d目录中的nfs脚本启动。NFS监控程序还启动rpc.mountd装载监控程序,并导出共享目录。l RPC装载:可以用mount命令连接本地目

11、录或网络目录,但还需要一个装载NFS目录的特殊监控程序rpc.mountl 端口映射器:portmap监控程序只是定向RPC通信数据流,但它对于NFS服务很重要。如果不运行portmap,则NFS客户机无法找到从NFS服务器共享的目录l 重新启动与statd:当NFS服务需要中断或者重新启动时,rpc.statd监控程序和rpc.lockd在服务器重新启动之后使客户机恢复NFS连接l 锁定:通过共享NFS目录打开文件时,锁定可以使用户不能覆盖同一个文件。锁定通过nfslock脚本并使用rpc.lockd监控程序启动运行。实验1-4 建立嵌入式开发环境 实验目的与意义通过此实验,学员可以配置交叉

12、开发环境,进行嵌入式系统环境下的程序设计工作。进而掌握Linux系统下的环境变量设置方法。 基本原理和方法在/etc/profile文件中修改PATH环境变量,添加工具链的路径。 实验内容及步骤编辑profile文件,在export之前,添加如下一行:rootvm root#/vi /etc/profilePATH=$PATH:/ usr/local/arm/3.3.2/bin然后使新配置文件生效:rootvm root# source /etc/profile在我们的系统中,没有使用/etc/profile这个全局有效的配置文件,而是使用root下的.bashrc环境变量。这样的话,如果以非

13、root登陆,则不会将交叉编译器添加到PATH中。因此请大家注意这个区别。可以查看/root/.bashrc文件,以了解其区别。实验1-5 下载内核到嵌入式平台 实验目的与意义通过此实验,学员可以熟悉利用超级终端下载系统内核的方法。 基本原理和方法嵌入式应用开发是基于操作系统之上的,因此我们需要先把内核运行起来,有多种方式下载内核,如串口、JTAG、网口、USB等。前提是我们的引导代码提供了相应的驱动。U-Boot提供了非常好的网络接口支持,因此本实验使用U-Boot提供的网络工具(tftp)下载内核。整个下载过程通过超级终端进行监视。 实验内容及步骤查看并配置主机IP:rootvm root

14、#/ifconfig rootvm root#ifconfig eth0 192.168.1.23 up查看并配置目标机IP:确保Linux开发主机的tftp服务已经正常工作,见实验1-3。启动U-Boot,进入下载模式。在U-Boot提示符下,输入下载命令:printenv/查看系统变量信息setenv ipaddr 192.168.1.134/设置IPsetenv serverip 192.168.1.23/设置服务器IPsaveenv/保存改变tftp 0x30200000 zImage /把内核下载到开发板内存的0x30200000地址上如果看到下载进度条,说明下载成功;如果网络有问题

15、(如文件没有找到、tftp没有启动),或出现TTTT类似的字样。下载到内存中后,输入下面命令启动内核:bootm 0x30200000/启动内核实验1-6 挂载NFS根文件系统 实验目的与意义通过此实验,学员可以熟悉Linux内核中NFS配置的选项,并可以编译一个支持NFS的内核。 基本原理和方法基本原理见实验1-3和1-4内容。 实验内容及步骤确保Linux开发主机的tftp服务和nfs服务已经正常工作,见实验1-3和1-4。编译内核,并选择NFS启动项:在内核源码目录中输入:make menuconfig找到内核命令行参数设置,配置内核启动方式为NFS(图中为实例,请根据实际路径进行调整)

16、:配置文件系统,加入NFS选项(进入Network File Systems),选中Root file system on NFS,让我们的系统可以支持NFS:保存,编译内核:make zImage实验1-7 编写并下载应用程序到嵌入式平台 实验目的与意义通过此实验,学员将学习交叉编译应用程序和在ARM平台上验证程序的方法。 基本原理和方法使用交叉编译器编译一个ARM平台的应用程序,通过NFS进行验证。 实验内容及步骤编辑下面的c程序,使用arm-linux-的工具链编译,然后在目标板上执行。1) 在主机上, 编写一个最简单的 “hello world” 程序,代码如下:# include m

17、ain(int argc, char *argv)int i;for ( i=0; i/proc/sys/fs/file-maxrootvm root#ls /proc/sys/fs/file-max65536(2)修改网络TTLrootvm root#ls /proc/sys/net/ ipv4/ip_default_ttl64rootvm root#echo 128 /proc/sys/net/ipv4/ip_default_ttlrootvm root#ls /proc/sys/net/ ipv4/ip_default_ttl128(3)修改系统中最大进程数量rootvm root#ls

18、 /proc/sys/kernel/pid_max32768rootvm root#echo 65536 /proc/sys/kernel/pid_maxrootvm root#ls /proc/sys/kernel/pid_max65536(4)修改普通用户的最大RTC频率rootvm root#ls /proc/sys/dev/rtc/max-user-freq64rootvm root#echo 128 /proc/sys/dev/rtc/max-user-freqrootvm root#ls /proc/sys/dev/rtc/max-user-freq128(5)其他一些信息root

19、vm root#cat /proc/cpuinfo - CPUrootvm root#cat /proc/interrupts - 中断 rootvm root#cat /proc/ioports - 设备IO端口 rootvm root#cat /proc/meminfo - 内存信息(i.e. mem used, free, swap size) rootvm root#cat /proc/partitions - 所有设备的所有分区 rootvm root#cat /proc/pci - PCI设备的信息 rootvm root#cat /proc/swaps - 所有Swap分区的信息

20、 rootvm root#cat /proc/version - Linux的版本号实验2-3 使用fork、exit和exec系统调用编写多进程程序 实验目的与意义本实验将通过编写fork等系统调用的程序,加深对系统进程及其控制的了解。 基本原理和方法fork后父子进程会同步运行,但父子进程的返回顺序是不确定的。设两个变量global和test来检测父子进程共享资源的情况。同时在进程退出时对exit和_exit的区别进行测试和说明。 实验内容及步骤1fork#include #include #include #include #include #include /#include intg

21、lobal=22;charbuf=the test content!n;int main(void)int test=0,stat;pid_t pid;if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1)perror(write error!);printf( fork test!n);/* fork */pid = fork(); /*we should check the error*/if(pid = -1)perror(fork);exit;/*if the pid=0 then it is the child*/else

22、if(pid = 0)global+; test+;printf(global=%d test%d Child,my PID is %dn,global,test,getpid();exit(0);/*else be the parent*/global+=2;test+=2;printf(global=%d test%d Parent,my PID is %dn,global,test,getpid();exit(0);/printf(global=%d test%d Parent,my PID is %d,global,test,getpid();/_exit(0);编译执行,并分析结果:

23、rootlocalhost root# ./testthe test content! fork test!global=23 test=1 Child,my PID is 2751global=24 test=2 Parent,my PID is 2750可以看出父子进程打印出了各自的进程号和对应变量的值,显然global和test在父子进程间是独立的,其各自的操作不会对对方的值有影响。将上述代码最后的两行代码替换为注释掉的_exit(0)行,重新编译,查看结果,解释原因:rootlocalhost root# ./testthe test content! fork test!global

24、=23 test=1 Child,my PID is 2771父进程的信息没有打印出来,其原因是:_exit()函数直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;而exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,即会 清理I/O缓冲。若将上述_exit(0)改为exit(0),则肯定会有打印。另外,需要注意换行符n会引起IO的清理操作,若下面的语句printf(global=%d test%d Parent,my PID is %d,global,

25、test,getpid(); 加上n,则调用_exit(0)的结果和调用exit(0)的结果是一样的。2vfork的特点将上述代码的pid = fork(); 改为pid = vfork();编译后运行结果如下:rootlocalhost root# ./testthe test content! fork test!global=23 test=1 Child,my PID is 2849global=25 test=3 Parent,my PID is 2848 可以看出,vfork与fork区别在于共享的资源不一样,vfork调用后,子进程先对global和test加1,父进程运行时,在

26、其基础之上再加2,得到上述运行结果。即vfork的特点是:在调用execv或者exit前子进程对变量的修改会影响到父进程,即他们是共享的;特别注意:父进程等待子进程调用execv或exit才继续执行。则若子进程依赖父进程的进一步动作时,父进程又必须阻塞到子进程调用execv或者exit才会往下执行,此时就会造成“死锁”。读者可自己设计测试一下这种“死锁”状态。3execv函数族的使用注意点:调用execv后,程序不再返回!在上述代码基础上,在子进程的退出代码前加入如下代码:printf(global=%d test%d Child,my PID is %dn,global,test,getpi

27、d();if(execl(/bin/ps,ps,-au,NULL)0)perror(execl error!);printf(this message will never be printed!n);exit(0);编译运行后结果为:rootlocalhost root# ./testthe test content! fork test!global=23 test=1 Child,my PID is 2909USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDroot 2719 0.0 0.6 4360 1032 pts/1 S 2

28、3:14 0:00 /bin/bashroot 2908 0.0 0.1 1340 276 pts/1 R 23:38 0:00 ./testroot 2909 0.0 0.4 2684 736 pts/1 R 23:38 0:00 ps -auglobal=25 test=3 Parent,my PID is 29084waitpid的作用是等待子进程退出并回收其资源,同时可以通过WIFEXITED等宏调用可以检测子进程退出的状态。在第一个示例fork使用的代码基础上进行修改,添加检测进程退出状态的子函数,参考代码如下:void exit_check(int stat) if(WIFEXIT

29、ED(stat)printf(exit normally!the return code is: %d n,WEXITSTATUS(stat); else if(WIFSIGNALED(stat)printf(exit abnormally!the signal code is: %d %sn,WTERMSIG(stat), #ifdef WCOREDUMP /WCOREDUMP(stat) ? (core file generated):); #else); #endif / 条件编译,如WIFSIGNALED(stat)为非0, /且此进程产生一个内存映射文件(core dump)则返回非

30、0 else if(WIFSTOPPED(stat) /如果子进程暂停(stopped)则返回非0printf(!the stop code is: %d n,WSTOPSIG(stat);在父进程处理global和test变量前加入如下代码:if(waitpid(pid,&stat,0)!=pid)perror(wait error);exit_check(stat); / the status of exit check编译运行后结果为:rootlocalhost root# ./testthe test content! fork test!global=23 test=1 Child,

31、my PID is 2973exit normally!the return code is: 0global=24 test=2 Parent,my PID is 2972可以看出父进程回收了退出的子进程的资源,检测到了它的退出状态。实验2-4 编写一个守护进程 实验目的与意义守护进程是Linux系统开发中很重要的知识点,本实验要求学员编写一个守护进程,通过本实验,学员可以熟悉守护进程的编写过程。 基本原理和方法守护进程编写的主要步骤如下:1屏蔽一些有关控制终端操作的信号。防止在守护进程没有正常运转起来时,控制终端受到干扰退出或挂起。signal(SIGTTOU,SIG_IGN);signa

32、l(SIGTTIN,SIG_IGN);signal(SIGTSTP,SIG_IGN);signal(SIGHUP ,SIG_IGN);2 将程序进入后台执行。由于守护进程最终脱离控制终端,到后台去运行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。这就是常说的“脱壳”。子进程继续函数fork()的定义如下:pid_t fork(void);3 脱离控制终端、登录会话和进程组。开发人员如果要摆脱它们,不受它们的影响,一般使用 setsid() 设置新会话的领头进程,并与原来的登录会话和进程组脱离。4 禁止进程重新打开控制终端。5 关闭打开的文件描述符,并重定向标准输入

33、、标准输出和标准错误输出的文件描述符。进程从创建它的父进程那里继承了打开的文件描述符。如果不关闭,将会浪费系统资源,引起无法预料的错误。关闭三者的代码如下:for (fd = 0, fdtablesize = getdtablesize();fd fdtablesize; fd+)close(fd);6 改变工作目录到根目录或特定目录进程活动时,其工作目录所在的文件系统不能卸下7 处理SIGCHLD信号。SIGCHLD信号是子进程结束时,向内核发送的信号。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。因此需要对SIGCHLD信号做出处理,回收僵尸进程的资源,

34、避免造成不必要的资源浪费。可以用如下语句:signal(SIGCHLD,(void *)reap_status);捕捉信号SIGCHLD,用下面的函数进行处理:void reap_status() int pid; .程序清单:init.ctest.c 实验内容及步骤守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态。初始化程序中的init_daemon函数负责生成守护进程。读者可以利用init_daemon函数生成自己的守护进程。 1 init.c #include #include #include #in

35、clude #include #include void init_daemon(void) int pid; int i; if(pid=fork() exit(0);/是父进程,结束父进程 else if(pid 0) exit(1);/fork失败,退出 /是第一子进程,后台继续执行 setsid();/第一子进程成为新的会话组长和进程组长 /并与控制终端分离 if(pid=fork() exit(0);/是第一子进程,结束第一子进程 else if(pid 0) exit(1);/fork失败,退出 /是第二子进程,继续 /第二子进程不再是会话组长 for(i=0;i NOFILE;+

36、i)/关闭打开的文件描述符 close(i); chdir(/tmp);/改变工作目录到/tmp umask(0);/重设文件创建掩模 return; 2 test.c #include #include void init_daemon(void);/守护进程初始化函数 int main() FILE *fp; time_t t; init_daemon();/初始化为Daemon while(1)/每隔一分钟向test.log报告运行状态 sleep(60);/睡眠一分钟 if(fp=fopen(test.log,a) =0) t=time(0); fprintf(fp,Im here a

37、t %sn,asctime(localtime(&t) ); fclose(fp); 编译:rootvm root#gcc g o test init.c test.c 执行:rootvm root#./test 查看进程:rootvm root#ps ef 从输出可以发现test守护进程的各种特性满足上面的要求。实验2-5 用消息队列编写一个客户端服务器通信的程序 实验目的与意义通过此实验,学员可以熟悉消息队列的概念,并能够用消息队列编写一个客户端服务器通信的程序。 基本原理和方法本实验需要用消息队列设计一个简易的双人聊天程序(一个服务器,两个客户端)。消息队列重点在于消息类型的匹配,客户端

38、和服务端的“通信协议”的设计。设计思想如下:服务器端:接受客户端发来的任何信息,并根据其消息类型,转发给对应的客户端。同时,检测是否有退出标志,有则给所有的客户端发送退出标志,等待10s后,确定客户端都退出后,删除消息队列,释放空间,并退出。客户端:A和B,A给B发送信息,先发给服务器,由服务器根据自定义协议转发该消息给B。同时B接受到消息后,经由服务器给A一个回执信息,以此形成简易的聊天模式。程序清单:server.c client1.c client2.c 实验内容及步骤编写服务器端程序:#define KEY_MSG 0x101 /使用共有的IPC key#define MSGSIZE 128#include #include #include #include #include

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服