《嵌入式Linux应用开发》_第1页
《嵌入式Linux应用开发》_第2页
《嵌入式Linux应用开发》_第3页
《嵌入式Linux应用开发》_第4页
《嵌入式Linux应用开发》_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 HYPERLINK 华清远见嵌入式培训中心PAGE - 50 -PAGE - 48 -嵌入式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

2、命令查看进程信息0.25基础2-2使用proc文件系统查看进程信息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的

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

4、在命令模式下,输入“dd”将某行内容添加到剪贴板:在命令模式下,输入“yy”将剪贴板中的内容复制到某行:在命令模式下,输入“p”实验1-2 配置tftp服务实验目的与意义通过此实验,学员可以熟悉tftp服务的配置方法。基本原理和方法TFTP(TrivialFileTransferProtocol)即简单文件传送 HYPERLINK /network/d556/index.html t _blank 协议,最初打算用于引导 HYPERLINK /network/d528/index.html t _blank 无盘系统(通常是工作站或X终端)。和使用 HYPERLINK /network/m22

5、22/index.html t _blank TCP的文件传送协议(FTP)不同,为了保持简单和短小,TFTP将使用 HYPERLINK /net-protocol/udp/index.html t _blank UDP。TFTP的代码(和它所需要的UDP、 HYPERLINK /network/m2083/index.html t _blank IP和设备 HYPERLINK /network/m2664/index.html t _blank 驱动程序)都能适合只读存储器。Linux系统的服务以配置文件方法进行配置,因此要找到tftp服务的配置文件所在,并根据实际情况配置根目录和权限等内容

6、。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_source=11 cps=1002 flags=IPv4 实验1-3 配置

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

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

9、/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端口发送insecure NFS通过1024以上的端口发送wdelay 如果多个用户要写入NFS目

10、录,则归组写入(默认)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和GID(默认)root_squash root用户的所有请求映射成如anonymous用户一样的权

11、限(默认)no_root_squas root用户具有根目录的完全管理访问权限anonuid=xxx 指定NFS服务器/etc/passwd文件中匿名用户的UIDanongid=xxx 指定NFS服务器/etc/passwd文件中匿名用户的GID了解nfs相关的监控程序:基本NFS:rpc.nfsd是NFS服务器监控程序,它通过/etc/rc.d/init.d目录中的nfs脚本启动。NFS监控程序还启动rpc.mountd装载监控程序,并导出共享目录。RPC装载:可以用mount命令连接本地目录或网络目录,但还需要一个装载NFS目录的特殊监控程序rpc.mount端口映射器:portmap监控

12、程序只是定向RPC通信数据流,但它对于NFS服务很重要。如果不运行portmap,则NFS客户机无法找到从NFS服务器共享的目录重新启动与statd:当NFS服务需要中断或者重新启动时,rpc.statd监控程序和rpc.lockd在服务器重新启动之后使客户机恢复NFS连接锁定:通过共享NFS目录打开文件时,锁定可以使用户不能覆盖同一个文件。锁定通过nfslock脚本并使用rpc.lockd监控程序启动运行。实验1-4 建立嵌入式开发环境实验目的与意义通过此实验,学员可以配置交叉开发环境,进行嵌入式系统环境下的程序设计工作。进而掌握Linux系统下的环境变量设置方法。基本原理和方法在/etc/

13、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环境变量。这样的话,如果以非root登陆,则不会将交叉编译器添加到PATH中。因此请大家注意这个区别。可以查看/root/.bashrc文件,以了解

14、其区别。实验1-5 下载内核到嵌入式平台实验目的与意义通过此实验,学员可以熟悉利用超级终端下载系统内核的方法。基本原理和方法嵌入式应用开发是基于操作系统之上的,因此我们需要先把内核运行起来,有多种方式下载内核,如串口、JTAG、网口、USB等。前提是我们的引导代码提供了相应的驱动。U-Boot提供了非常好的网络接口支持,因此本实验使用U-Boot提供的网络工具(tftp)下载内核。整个下载过程通过超级终端进行监视。实验内容及步骤查看并配置主机IP:rootvm root#/ifconfig rootvm root#ifconfig eth0 3 up查看并配置目标机IP:确保Linux开发主机

15、的tftp服务已经正常工作,见实验1-3。启动U-Boot,进入下载模式。在U-Boot提示符下,输入下载命令:printenv/查看系统变量信息setenv ipaddr 34/设置IPsetenv serverip 3/设置服务器IPsaveenv/保存改变tftp 0 x30200000 zImage /把内核下载到开发板内存的0 x30200000地址上如果看到下载进度条,说明下载成功;如果网络有问题(如文件没有找到、tftp没有启动),或出现TTTT类似的字样。下载到内存中后,输入下面命令启动内核:bootm 0 x30200000/启动内核实验1-6 挂载NFS根文件系统实验目的与

16、意义通过此实验,学员可以熟悉Linux内核中NFS配置的选项,并可以编译一个支持NFS的内核。基本原理和方法基本原理见实验1-3和1-4内容。实验内容及步骤确保Linux开发主机的tftp服务和nfs服务已经正常工作,见实验1-3和1-4。编译内核,并选择NFS启动项:在内核源码目录中输入:make menuconfig找到内核命令行参数设置,配置内核启动方式为NFS(图中为实例,请根据实际路径进行调整):配置文件系统,加入NFS选项(进入Network File Systems),选中Root file system on NFS,让我们的系统可以支持NFS:保存,编译内核:make zIm

17、age实验1-7 编写并下载应用程序到嵌入式平台实验目的与意义通过此实验,学员将学习交叉编译应用程序和在ARM平台上验证程序的方法。基本原理和方法使用交叉编译器编译一个ARM平台的应用程序,通过NFS进行验证。实验内容及步骤编辑下面的c程序,使用arm-linux-的工具链编译,然后在目标板上执行。1) 在主机上, 编写一个最简单的 “hello world” 程序,代码如下:# include main(int argc, char *argv)int i;for ( i=0; i/proc/sys/fs/file-maxrootvm root#ls /proc/sys/fs/file-ma

18、x65536(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 /proc/sys/kernel/pid_max32768rootvm root#echo 65536 /proc/sys/kernel/pid_maxrootvm root#ls /proc/s

19、ys/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)其他一些信息rootvm root#cat /proc/cpuinfo - CPUrootvm root#cat /proc/interrupts - 中断 rootvm root#cat /proc/ioports

20、- 设备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分区的信息 rootvm root#cat /proc/version - Linux的版本号实验2-3 使用fork、exit和exec系统调用编写多进程程序实验目的与意义本实验将通过编写fork等系统调用

21、的程序,加深对系统进程及其控制的了解。基本原理和方法fork后父子进程会同步运行,但父子进程的返回顺序是不确定的。设两个变量global和test来检测父子进程共享资源的情况。同时在进程退出时对exit和_exit的区别进行测试和说明。实验内容及步骤1fork#include #include #include #include #include #include /#include intglobal=22;charbuf=the test content!n;int main(void)int test=0,stat;pid_t pid;if(write(STDOUT_FILENO,buf

22、,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 if(pid = 0)global+; test+;printf(global=%d test%d Child,my PID is %dn,global,test,getpid();exit(0);/*e

23、lse 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);编译执行,并分析结果:rootlocalhost root# ./testthe test content! fork test!global=23 test=1 Child,my PID is 2751global=24 t

24、est=2 Parent,my PID is 2750可以看出父子进程打印出了各自的进程号和对应变量的值,显然global和test在父子进程间是独立的,其各自的操作不会对对方的值有影响。将上述代码最后的两行代码替换为注释掉的_exit(0)行,重新编译,查看结果,解释原因:rootlocalhost root# ./testthe test content! fork test!global=23 test=1 Child,my PID is 2771父进程的信息没有打印出来,其原因是:_exit()函数直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;而exit()

25、函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,即会 清理I/O缓冲。若将上述_exit(0)改为exit(0),则肯定会有打印。另外,需要注意换行符n会引起IO的清理操作,若下面的语句printf(global=%d test%d Parent,my PID is %d,global,test,getpid(); 加上n,则调用_exit(0)的结果和调用exit(0)的结果是一样的。2vfork的特点将上述代码的pid = fork(); 改为pid = vfork();编译后运行结

26、果如下: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,父进程运行时,在其基础之上再加2,得到上述运行结果。即vfork的特点是:在调用execv或者exit前子进程对变量的修改会影响到父进程,即他们是共享的;特别注意:父进程等待子进程调用execv或exit才继续执行。则若

27、子进程依赖父进程的进一步动作时,父进程又必须阻塞到子进程调用execv或者exit才会往下执行,此时就会造成“死锁”。读者可自己设计测试一下这种“死锁”状态。3execv函数族的使用注意点:调用execv后,程序不再返回!在上述代码基础上,在子进程的退出代码前加入如下代码:printf(global=%d test%d Child,my PID is %dn,global,test,getpid();if(execl(/bin/ps,ps,-au,NULL)0)perror(execl error!);printf(this message will never be printed!n);e

28、xit(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 23: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/

29、1 R 23:38 0:00 ps -auglobal=25 test=3 Parent,my PID is 29084waitpid的作用是等待子进程退出并回收其资源,同时可以通过WIFEXITED等宏调用可以检测子进程退出的状态。在第一个示例fork使用的代码基础上进行修改,添加检测进程退出状态的子函数,参考代码如下:void exit_check(int stat) if(WIFEXITED(stat)printf(exit normally!the return code is: %d n,WEXITSTATUS(stat); else if(WIFSIGNALED(stat)prin

30、tf(exit abnormally!the signal code is: %d %sn,WTERMSIG(stat), #ifdef WCOREDUMP /WCOREDUMP(stat) ? (core file generated):); #else); #endif / 条件编译,如WIFSIGNALED(stat)为非0, /且此进程产生一个内存映射文件(core dump)则返回非0 else if(WIFSTOPPED(stat) /如果子进程暂停(stopped)则返回非0printf(!the stop code is: %d n,WSTOPSIG(stat);在父进程处理g

31、lobal和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,my PID is 2973exit normally!the return code is: 0global=24 test=2 Parent,my PID is 2972可以看出父进程回收了退出的子进

32、程的资源,检测到了它的退出状态。实验2-4 编写一个守护进程实验目的与意义守护进程是Linux系统开发中很重要的知识点,本实验要求学员编写一个守护进程,通过本实验,学员可以熟悉守护进程的编写过程。基本原理和方法守护进程编写的主要步骤如下:1屏蔽一些有关控制终端操作的信号。防止在守护进程没有正常运转起来时,控制终端受到干扰退出或挂起。signal(SIGTTOU,SIG_IGN);signal(SIGTTIN,SIG_IGN);signal(SIGTSTP,SIG_IGN);signal(SIGHUP ,SIG_IGN);将 HYPERLINK /comm/read_out.htm?url=/d

33、ev/index.html t _blank 程序进入后台执行。由于守护进程最终脱离控制终端,到后台去运行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。这就是常说的“脱壳”。子进程继续函数fork()的定义如下:pid_t fork(void);脱离控制终端、登录会话和进程组。开发人员如果要摆脱它们,不受它们的影响,一般使用 setsid() 设置新会话的领头进程,并与原来的登录会话和进程组脱离。禁止进程重新打开控制终端。关闭打开的文件描述符,并重定向标准输入、标准输出和标准错误输出的文件描述符。进程从创建它的父进程那里继承了打开的文件描述符。如果不关闭,将会浪费

34、系统资源,引起无法预料的错误。关闭三者的代码如下:for (fd = 0, fdtablesize = getdtablesize();fd fdtablesize; fd+)close(fd);改变工作目录到根目录或特定目录进程活动时,其工作目录所在的文件系统不能卸下处理SIGCHLD信号。SIGCHLD信号是子进程结束时,向内核发送的信号。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。因此需要对SIGCHLD信号做出处理,回收僵尸进程的资源,避免造成不必要的资源浪费。可以用如下语句:signal(SIGCHLD,(void *)reap_status);

35、捕捉信号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 #include #include #include void init_daemon(void) int pid; in

36、t 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;+i)/关闭打开的文件描述符 close(i); chdir(/tmp);/改变工作目录到/tmp umask(0);

37、/重设文件创建掩模 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 at %sn,asctime(localtime(&t) ); fclose(fp); 编译:rootvm root#

38、gcc g o test init.c test.c 执行:rootvm root#./test 查看进程:rootvm root#ps ef 从输出可以发现test守护进程的各种特性满足上面的要求。实验2-5 用消息队列编写一个客户端服务器通信的程序实验目的与意义通过此实验,学员可以熟悉消息队列的概念,并能够用消息队列编写一个客户端服务器通信的程序。基本原理和方法本实验需要用消息队列设计一个简易的双人聊天程序(一个服务器,两个客户端)。消息队列重点在于消息类型的匹配,客户端和服务端的“通信协议”的设计。设计思想如下:服务器端:接受客户端发来的任何信息,并根据其消息类型,转发给对应的客户端。同

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

40、sgid; struct msgbuf /定义消息结构体:消息类型和消息数据 long mtype; char mtext128; buf1, buf2; msgid = msgget( KEY_MSG, IPC_CREAT|0666 ); while( 1 ) /无限循环,退出标志则会break msgrcv( msgid, &buf1, MSGSIZE, 1L, 0 ); /接受客户端1的消息printf( Receive client1 message: %sn, buf1.mtext ); /打印收到的消息if( buf1.mtext0 = x | buf1.mtext0 = X )

41、/若是退出标志,则给2个客户端都发退出信息 strcpy( buf1.mtext, x ); buf1.mtype = 3L; msgsnd( msgid, &buf1, MSGSIZE, 0 ); buf1.mtype = 4L; msgsnd( msgid, &buf1, MSGSIZE, 0 ); break; buf1.mtype = 4L;msgsnd( msgid, &buf1, MSGSIZE, 0 ); /将客户端1的消息转发给客户端2 msgrcv( msgid, &buf2, MSGSIZE, 2L, 0 ); /接受客户端2的消息printf( Receive clien

42、t2 message: %sn, buf2.mtext ); /打印收到的消息if( buf2.mtext0 = x | buf2.mtext0 = X )/若是退出标志,则给2个客户端发退出信息strcpy( buf2.mtext, x ); buf2.mtype = 3L; msgsnd( msgid, &buf2, MSGSIZE, 0 ); buf2.mtype = 4L; msgsnd( msgid, &buf2, MSGSIZE, 0 ); break; buf2.mtype = 3L;msgsnd( msgid, &buf2, MSGSIZE, 0 ); /将客户端2的消息转发给

43、客户端1 sleep(5); /若退出,则先等待,以确保客户端程序退出 msgctl( msgid, IPC_RMID, NULL ); /删除消息队列,释放空间 exit(0);客户端1:#define KEY_MSG 0 x101#define MSGSIZE 128#include #include #include #include #include main() int msgid; struct msgbuf long mtype; char mtext128; buf1, buf2; msgid = msgget( KEY_MSG, 0666 ); while( 1 ) prin

44、tf( input the msg to client2: ); gets( buf1.mtext ); buf1.mtype = 1L; msgsnd( msgid, &buf1, MSGSIZE, 0 ); /客户端1获取消息并发往服务器sleep(1); /等待一秒,以确保客户端2已经收到并发了回执 msgrcv( msgid, &buf2, MSGSIZE, 3L, 0 ); /准备从客户端2获取回执消息 if( buf2.mtext0 = x | buf2.mtext0 = X ) printf( client1 will quit!n ); break; printf( Recei

45、ve from client2, message: %sn, buf2.mtext ); 客户端2:#define KEY_MSG 0 x101#define MSGSIZE 128#include #include #include #include #include main() int msgid; struct msgbuf long mtype; char mtext128; buf1, buf2; msgid = msgget( KEY_MSG, 0666 ); while( 1 ) / block msgrcv( msgid, &buf2, MSGSIZE, 4L, 0 ); /

46、等待客户端1发消息 if( buf2.mtext0 = x | buf2.mtext0 = X ) printf( client2 will quit!n ); break; else printf( Receive from client1, message: %sn, buf2.mtext );sleep(1); /等待一秒,以确保客户端1已经收到了回执printf( input the msg to client1: ); gets( buf1.mtext ); buf1.mtype = 2L; msgsnd( msgid, &buf1, MSGSIZE, 0 ); /给客户端1发送回执

47、消息 运行测试。先编译运行服务器,确保消息队列已经创建完毕,并进入等待状态。结果如下:rootlocalhost root# ./serverReceive client1 message: i am client AReceive client2 message: ok! I have recieved your msg,Im client BReceive client1 message: xrootlocalhost root#客户端A的运行结果如下:rootlocalhost root# ./client1input the msg to client2:i am client ARe

48、ceive from client2, message: ok! I have recieved your msg,Im client Binput the msg to client2:xclient1 will quit!rootlocalhost root#客户端B的运行结果如下:rootlocalhost root# ./client2Receive from client1, message: i am client Ainput the msg to client1: ok! I have recieved your msg,Im client Bclient2 will quit

49、!rootlocalhost root#实验2-6 编写串口通信的多进程程序实验目的与意义通过本实验,学员可以掌握ARM的串行口工作原理,了解ARM的UART通讯。在了解了串口编程后,扩展到多串口同时通信,从而掌握远程主机间的进程间通信技术。基本原理和方法串口COM的读写主要是对其IO属性进行设定,然后用read和write对其进行操作。本实验设计主机1的进程A对串口反复写的程序和主机2客户进程B从COM读取的程序,可通过COM互连方式进行双机的测试,或通过交叉编译后在嵌入式开发板和主机之间进程调试。注意:两程序的串口参数设置的一致性。实验内容及步骤编写如下代码,并运行调试:/*写串口*/#i

50、nclude #include #include #include #include #include #include #include #include int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)struct termios newtio,oldtio;/*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/if ( tcgetattr( fd,&oldtio) != 0) perror(SetupSerial 1);return -1;bzero( &newtio, sizeof(

51、 newtio ) );/*步骤一,设置字符大小*/newtio.c_cflag |= CLOCAL | CREAD; newtio.c_cflag &= CSIZE; /*设置停止位*/switch( nBits )case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;/*设置奇偶校验位*/switch( nEvent )case O: /奇数newtio.c_cflag |= PARENB;newtio.c_cflag |= PARODD;newtio.c_iflag |= (INPCK | ISTRIP

52、);break;case E: /偶数newtio.c_iflag |= (INPCK | ISTRIP);newtio.c_cflag |= PARENB;newtio.c_cflag &= PARODD;break;case N: /无奇偶校验位newtio.c_cflag &= PARENB;break;/*设置波特率*/switch( nSpeed )case 2400:cfsetispeed(&newtio, B2400);cfsetospeed(&newtio, B2400);break;case 4800:cfsetispeed(&newtio, B4800);cfsetospe

53、ed(&newtio, B4800);break;case 9600:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;case 115200:cfsetispeed(&newtio, B115200);cfsetospeed(&newtio, B115200);break;case 460800:cfsetispeed(&newtio, B460800);cfsetospeed(&newtio, B460800);break;default:cfsetispeed(&newtio, B9600);cfsetospeed

54、(&newtio, B9600);break;/*设置停止位*/if( nStop = 1 )newtio.c_cflag &= CSTOPB;else if ( nStop = 2 )newtio.c_cflag |= CSTOPB;/*设置等待时间和最小接收字符*/newtio.c_ccVTIME = 0;newtio.c_ccVMIN = 0;/*处理未接收字符*/tcflush(fd,TCIFLUSH);/*激活新配置*/if(tcsetattr(fd,TCSANOW,&newtio)!=0)perror(com set error);return -1;printf(set done

55、!n);return 0;/*打开串口函数*/int open_port(int fd,int comport)char *dev=/dev/ttyS0,/dev/ttyS1,/dev/ttyS2;long vdisable;if (comport=1)/串口1fd = open( /dev/ttyS0, O_RDWR|O_NOCTTY|O_NDELAY);if (-1 = fd)perror(Cant Open Serial Port);return(-1);else if(comport=2)/串口2fd = open( /dev/ttyS1, O_RDWR|O_NOCTTY|O_NDEL

56、AY);if (-1 = fd)perror(Cant Open Serial Port);return(-1);else if (comport=3)/串口3fd = open( /dev/ttyS2, O_RDWR|O_NOCTTY|O_NDELAY);if (-1 = fd)perror(Cant Open Serial Port);return(-1);/*恢复串口为阻塞状态*/if(fcntl(fd, F_SETFL, 0)0)printf(fcntl failed!n);elseprintf(fcntl=%dn,fcntl(fd, F_SETFL,0);/*测试是否为终端设备*/i

57、f(isatty(STDIN_FILENO)=0)printf(standard input is not a terminal devicen);elseprintf(isatty success!n);printf(fd-open=%dn,fd);return fd;int main(void) int fd;int nwrite,i;char buff=Hellon;/*打开串口*/if(fd=open_port(fd,1)0) perror(open_port error);return;/*设置串口*/if(i=set_opt(fd,115200,8,N,1)0) perror(se

58、t_opt error);return;printf(fd=%dn,fd);/*向串口写入字符串*/ for(i=0;i20;i+)nwrite=write(fd,buff,8);printf(nwrite=%dn,nwrite);sleep(1);close(fd);return;读串口程序的有关串口属性设置的子函数和写串口程序一致,这里仅给出主函数,如下:/*读串口程序*/int main(void) int fd;int nread,i;char buff=Hellon;if(fd=open_port(fd,1)0)/打开串口perror(open_port error);return;

59、if(i=set_opt(fd,115200,8,N,1)0)/设置串口perror(set_opt error);return;printf(fd=%dn,fd);fd=3;while(1)nread=read(fd,buff,8);/读串口printf(nread=%d,%sn,nread,buff);sleep(1);close(fd);return;程序调试:调试串口写程序时,可将主机的两个串口用串口连接线相连,如下图。然后主机可用串口调试工具,如串口调试精灵打开COM2,而程序代码打开COM1,并往里面循环写数据。若程序无异常,串口调试精灵会显示出所写的数据(有些主机只有一个COM时

60、,则需要两个主机进行配合测试)。主机COM1COM2图 串口写程序的调试你也可以在开发板和主机之间进行程序的调试。由于开发板一般用COM1作为显示终端,因此开发板的串口写程序要用COM2作为输出,并将COM2与远端主机的COM进行相连,开发板通过NFS模式进行程序的编译和运行,主机A则运行串口的读程序。概图如图2所示。Net主机A开发板NFS Server(主机B)COM1COMCOM1COM2图 开发板和主机间的串口读写程序调试注意:开发板的COM2可否进行读写,需要开发板上运行的内核的支持。实验3-1 编写一个简单的网络通信程序(socket)实验目的与意义同过本实验,编写一个简单的soc

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论