《嵌入式Linux應(yīng)用開(kāi)發(fā)》_第1頁(yè)
《嵌入式Linux應(yīng)用開(kāi)發(fā)》_第2頁(yè)
《嵌入式Linux應(yīng)用開(kāi)發(fā)》_第3頁(yè)
《嵌入式Linux應(yīng)用開(kāi)發(fā)》_第4頁(yè)
《嵌入式Linux應(yīng)用開(kāi)發(fā)》_第5頁(yè)
已閱讀5頁(yè),還剩43頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、 HYPERLINK 華清遠(yuǎn)見(jiàn)嵌入式培訓(xùn)中心PAGE - 50 -PAGE - 48 -嵌入式Linux應(yīng)用開(kāi)發(fā)實(shí)驗(yàn)指導(dǎo)書(shū)嵌入式Linux應(yīng)用開(kāi)發(fā)培訓(xùn)組編著課程編號(hào):FSLA1001課內(nèi)實(shí)驗(yàn)學(xué)時(shí):18學(xué)時(shí)華清遠(yuǎn)見(jiàn)嵌入式培訓(xùn)中心2007年.版權(quán)所有實(shí)驗(yàn)項(xiàng)目及學(xué)時(shí)分配 序號(hào)實(shí) 驗(yàn) 項(xiàng) 目 名 稱學(xué)時(shí)類型難易度1-1學(xué)習(xí)Linux系統(tǒng)命令0.5基礎(chǔ)1-2配置tftp服務(wù)(*)0.5基礎(chǔ)1-3配置nfs服務(wù)(*)0.5基礎(chǔ)1-4建立嵌入式開(kāi)發(fā)環(huán)境0.25基礎(chǔ)1-5下載內(nèi)核到嵌入式平臺(tái)(*)0.25基礎(chǔ)1-6掛載NFS根文件系統(tǒng)(*)0.5基礎(chǔ)1-7編寫(xiě)并下載應(yīng)用程序到嵌入式平臺(tái)0.5基礎(chǔ)2-1使用ps

2、命令查看進(jìn)程信息0.25基礎(chǔ)2-2使用proc文件系統(tǒng)查看進(jìn)程信息0.25基礎(chǔ)2-3使用fork、exit和exec系統(tǒng)調(diào)用編寫(xiě)多進(jìn)程程序1設(shè)計(jì)2-4編寫(xiě)一個(gè)守護(hù)進(jìn)程1設(shè)計(jì)2-5用消息隊(duì)列編寫(xiě)一個(gè)客戶端服務(wù)器通信的程序1.5設(shè)計(jì)2-6編寫(xiě)串口通信的多進(jìn)程程序1.5綜合3-1編寫(xiě)一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)通信程序(socket)1綜合3-2Tcp網(wǎng)絡(luò)編程2綜合4-1基于Qt實(shí)現(xiàn)hello world對(duì)話框程序0.5設(shè)計(jì)4-2嵌入式Linux GUI虛擬幀緩存主機(jī)移植1.0設(shè)計(jì)4-3基于Qt圖形界面的溫度計(jì)的實(shí)現(xiàn)1.5綜合實(shí)驗(yàn)1-1 學(xué)習(xí)Linux系統(tǒng)命令實(shí)驗(yàn)?zāi)康呐c意義通過(guò)此實(shí)驗(yàn),學(xué)員可以熟練運(yùn)用Linux的

3、操作,掌握GNU編程環(huán)境和基本命令。本實(shí)驗(yàn)是后面進(jìn)行應(yīng)用開(kāi)發(fā)系列實(shí)驗(yàn)的基礎(chǔ)內(nèi)容。Linux初級(jí)用戶必須熟練掌握本實(shí)驗(yàn)的所有內(nèi)容。基本原理和方法在Linux環(huán)境下進(jìn)行由淺入深的練習(xí),并對(duì)比Windows環(huán)境下的程序設(shè)計(jì)。實(shí)驗(yàn)內(nèi)容及步驟練習(xí)Linux下的基本命令使用方法cd:切換目錄ls:列出目錄下的內(nèi)容cp:文件復(fù)制rm:刪除文件mv:轉(zhuǎn)移/更名文件ln:建立文件鏈接mkdir:創(chuàng)建文件夾rmdir:刪除文件夾kill:殺死系統(tǒng)中某個(gè)進(jìn)程練習(xí)vi編輯器的基本用法進(jìn)入編輯模式:i、a、o進(jìn)入命令模式:ESC保存文件:在命令模式下,輸入“:w”退出vi編輯器:在命令模式下,輸入“:q”刪除某行內(nèi)容:

4、在命令模式下,輸入“dd”將某行內(nèi)容添加到剪貼板:在命令模式下,輸入“yy”將剪貼板中的內(nèi)容復(fù)制到某行:在命令模式下,輸入“p”實(shí)驗(yàn)1-2 配置tftp服務(wù)實(shí)驗(yàn)?zāi)康呐c意義通過(guò)此實(shí)驗(yàn),學(xué)員可以熟悉tftp服務(wù)的配置方法?;驹砗头椒═FTP(TrivialFileTransferProtocol)即簡(jiǎn)單文件傳送 HYPERLINK /network/d556/index.html t _blank 協(xié)議,最初打算用于引導(dǎo) HYPERLINK /network/d528/index.html t _blank 無(wú)盤(pán)系統(tǒng)(通常是工作站或X終端)。和使用 HYPERLINK /network/m22

5、22/index.html t _blank TCP的文件傳送協(xié)議(FTP)不同,為了保持簡(jiǎn)單和短小,TFTP將使用 HYPERLINK /net-protocol/udp/index.html t _blank UDP。TFTP的代碼(和它所需要的UDP、 HYPERLINK /network/m2083/index.html t _blank IP和設(shè)備 HYPERLINK /network/m2664/index.html t _blank 驅(qū)動(dòng)程序)都能適合只讀存儲(chǔ)器。Linux系統(tǒng)的服務(wù)以配置文件方法進(jìn)行配置,因此要找到tftp服務(wù)的配置文件所在,并根據(jù)實(shí)際情況配置根目錄和權(quán)限等內(nèi)容

6、。tftp服務(wù)的配置文件tftp在/etc目錄下,找到并編輯該文件即可。ubuntu發(fā)行版采用了新的服務(wù)機(jī)制,與RedHat Linux的tftp配置有少許不同,但是原理相同。實(shí)驗(yàn)內(nèi)容及步驟編輯tftp文件,使之符合嵌入式Linux開(kāi)發(fā)需要,并設(shè)置其根目錄在/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 實(shí)驗(yàn)1-3 配置

7、NFS服務(wù)實(shí)驗(yàn)?zāi)康呐c意義通過(guò)此實(shí)驗(yàn),學(xué)員可以熟悉nfs服務(wù),了解nfs服務(wù)原理和配置方法。基本原理和方法NFS是網(wǎng)絡(luò)文件系統(tǒng)(Network File System)的簡(jiǎn)稱,是分布式計(jì)算系統(tǒng)的一個(gè)組成部分,可實(shí)現(xiàn)在異種網(wǎng)絡(luò)上共享和裝配遠(yuǎn)程文件系統(tǒng)。nfs的配置文件是/etc/exports,所以我們查看并修改這個(gè)文件。在該文件中增加根文件系統(tǒng)。實(shí)驗(yàn)內(nèi)容及步驟安裝nfs服務(wù)器端和客戶端(如果沒(méi)有該軟件包)服務(wù)器端:rootvm root#apt-get install portmap nfs-kernel-server客戶機(jī)端:rootvm root#apt-get install portma

8、p nfs-common編輯/etc/exports,在其中增加要共享的目錄rootvm root#gedit /etc/exports配置下面一行/rootfs *(rw,sync,no_root_squash)/rootfs是要共享的目錄,代表允許所有的網(wǎng)絡(luò)段訪問(wèn),rw是可讀寫(xiě)權(quán)限,sync是資料同步寫(xiě)入內(nèi)存和硬盤(pán),no_root_squash是NFS客戶端分享目錄使用者的權(quán)限,如果客戶端使用的是root用戶,那么對(duì)于該共享目錄而言,該客戶端就具有root權(quán)限重啟服務(wù)rootvm root#/etc/init.d/portmap restartrootvm root#/etc/init.d

9、/nfs-kernel-server restart或執(zhí)行rootvm root#exportfs -ra(重新掃描/etc/exports,使用戶修改/etc/exports配置文件不必重啟NFS服務(wù) )rootvm root#/showmount -e顯示hostname中/etc/exports里設(shè)定的共享目錄了解NFS共享的常用參數(shù):ro 只讀訪問(wèn)rw 讀寫(xiě)訪問(wèn)sync 所有數(shù)據(jù)在請(qǐng)求時(shí)寫(xiě)入共享async NFS在寫(xiě)入數(shù)據(jù)前可以相應(yīng)請(qǐng)求secure NFS通過(guò)1024以下的安全TCP/IP端口發(fā)送insecure NFS通過(guò)1024以上的端口發(fā)送wdelay 如果多個(gè)用戶要寫(xiě)入NFS目

10、錄,則歸組寫(xiě)入(默認(rèn))no_wdelay 如果多個(gè)用戶要寫(xiě)入NFS目錄,則立即寫(xiě)入,當(dāng)使用async時(shí),無(wú)需此設(shè)置。hide 在NFS共享目錄中不共享其子目錄no_hide 共享NFS目錄的子目錄subtree_check 如果共享/usr/bin之類的子目錄時(shí),強(qiáng)制NFS檢查父目錄的權(quán)限(默認(rèn))no_subtree_check 和上面相對(duì),不檢查父目錄權(quán)限all_squash 共享文件的UID和GID映射匿名用戶anonymous,適合公用目錄。no_all_squash 保留共享文件的UID和GID(默認(rèn))root_squash root用戶的所有請(qǐng)求映射成如anonymous用戶一樣的權(quán)

11、限(默認(rèn))no_root_squas root用戶具有根目錄的完全管理訪問(wèn)權(quán)限anonuid=xxx 指定NFS服務(wù)器/etc/passwd文件中匿名用戶的UIDanongid=xxx 指定NFS服務(wù)器/etc/passwd文件中匿名用戶的GID了解nfs相關(guān)的監(jiān)控程序:基本NFS:rpc.nfsd是NFS服務(wù)器監(jiān)控程序,它通過(guò)/etc/rc.d/init.d目錄中的nfs腳本啟動(dòng)。NFS監(jiān)控程序還啟動(dòng)rpc.mountd裝載監(jiān)控程序,并導(dǎo)出共享目錄。RPC裝載:可以用mount命令連接本地目錄或網(wǎng)絡(luò)目錄,但還需要一個(gè)裝載NFS目錄的特殊監(jiān)控程序rpc.mount端口映射器:portmap監(jiān)控

12、程序只是定向RPC通信數(shù)據(jù)流,但它對(duì)于NFS服務(wù)很重要。如果不運(yùn)行portmap,則NFS客戶機(jī)無(wú)法找到從NFS服務(wù)器共享的目錄重新啟動(dòng)與statd:當(dāng)NFS服務(wù)需要中斷或者重新啟動(dòng)時(shí),rpc.statd監(jiān)控程序和rpc.lockd在服務(wù)器重新啟動(dòng)之后使客戶機(jī)恢復(fù)NFS連接鎖定:通過(guò)共享NFS目錄打開(kāi)文件時(shí),鎖定可以使用戶不能覆蓋同一個(gè)文件。鎖定通過(guò)nfslock腳本并使用rpc.lockd監(jiān)控程序啟動(dòng)運(yùn)行。實(shí)驗(yàn)1-4 建立嵌入式開(kāi)發(fā)環(huán)境實(shí)驗(yàn)?zāi)康呐c意義通過(guò)此實(shí)驗(yàn),學(xué)員可以配置交叉開(kāi)發(fā)環(huán)境,進(jìn)行嵌入式系統(tǒng)環(huán)境下的程序設(shè)計(jì)工作。進(jìn)而掌握Linux系統(tǒng)下的環(huán)境變量設(shè)置方法?;驹砗头椒ㄔ?etc/

13、profile文件中修改PATH環(huán)境變量,添加工具鏈的路徑。實(shí)驗(yàn)內(nèi)容及步驟編輯profile文件,在export之前,添加如下一行:rootvm root#/vi /etc/profilePATH=$PATH:/ usr/local/arm/3.3.2/bin然后使新配置文件生效:rootvm root# source /etc/profile在我們的系統(tǒng)中,沒(méi)有使用/etc/profile這個(gè)全局有效的配置文件,而是使用root下的.bashrc環(huán)境變量。這樣的話,如果以非root登陸,則不會(huì)將交叉編譯器添加到PATH中。因此請(qǐng)大家注意這個(gè)區(qū)別。可以查看/root/.bashrc文件,以了解

14、其區(qū)別。實(shí)驗(yàn)1-5 下載內(nèi)核到嵌入式平臺(tái)實(shí)驗(yàn)?zāi)康呐c意義通過(guò)此實(shí)驗(yàn),學(xué)員可以熟悉利用超級(jí)終端下載系統(tǒng)內(nèi)核的方法?;驹砗头椒ㄇ度胧綉?yīng)用開(kāi)發(fā)是基于操作系統(tǒng)之上的,因此我們需要先把內(nèi)核運(yùn)行起來(lái),有多種方式下載內(nèi)核,如串口、JTAG、網(wǎng)口、USB等。前提是我們的引導(dǎo)代碼提供了相應(yīng)的驅(qū)動(dòng)。U-Boot提供了非常好的網(wǎng)絡(luò)接口支持,因此本實(shí)驗(yàn)使用U-Boot提供的網(wǎng)絡(luò)工具(tftp)下載內(nèi)核。整個(gè)下載過(guò)程通過(guò)超級(jí)終端進(jìn)行監(jiān)視。實(shí)驗(yàn)內(nèi)容及步驟查看并配置主機(jī)IP:rootvm root#/ifconfig rootvm root#ifconfig eth0 3 up查看并配置目標(biāo)機(jī)IP:確保Linux開(kāi)發(fā)主機(jī)

15、的tftp服務(wù)已經(jīng)正常工作,見(jiàn)實(shí)驗(yàn)1-3。啟動(dòng)U-Boot,進(jìn)入下載模式。在U-Boot提示符下,輸入下載命令:printenv/查看系統(tǒng)變量信息setenv ipaddr 34/設(shè)置IPsetenv serverip 3/設(shè)置服務(wù)器IPsaveenv/保存改變tftp 0 x30200000 zImage /把內(nèi)核下載到開(kāi)發(fā)板內(nèi)存的0 x30200000地址上如果看到下載進(jìn)度條,說(shuō)明下載成功;如果網(wǎng)絡(luò)有問(wèn)題(如文件沒(méi)有找到、tftp沒(méi)有啟動(dòng)),或出現(xiàn)TTTT類似的字樣。下載到內(nèi)存中后,輸入下面命令啟動(dòng)內(nèi)核:bootm 0 x30200000/啟動(dòng)內(nèi)核實(shí)驗(yàn)1-6 掛載NFS根文件系統(tǒng)實(shí)驗(yàn)?zāi)康呐c

16、意義通過(guò)此實(shí)驗(yàn),學(xué)員可以熟悉Linux內(nèi)核中NFS配置的選項(xiàng),并可以編譯一個(gè)支持NFS的內(nèi)核?;驹砗头椒ɑ驹硪?jiàn)實(shí)驗(yàn)1-3和1-4內(nèi)容。實(shí)驗(yàn)內(nèi)容及步驟確保Linux開(kāi)發(fā)主機(jī)的tftp服務(wù)和nfs服務(wù)已經(jīng)正常工作,見(jiàn)實(shí)驗(yàn)1-3和1-4。編譯內(nèi)核,并選擇NFS啟動(dòng)項(xiàng):在內(nèi)核源碼目錄中輸入:make menuconfig找到內(nèi)核命令行參數(shù)設(shè)置,配置內(nèi)核啟動(dòng)方式為NFS(圖中為實(shí)例,請(qǐng)根據(jù)實(shí)際路徑進(jìn)行調(diào)整):配置文件系統(tǒng),加入NFS選項(xiàng)(進(jìn)入Network File Systems),選中Root file system on NFS,讓我們的系統(tǒng)可以支持NFS:保存,編譯內(nèi)核:make zIm

17、age實(shí)驗(yàn)1-7 編寫(xiě)并下載應(yīng)用程序到嵌入式平臺(tái)實(shí)驗(yàn)?zāi)康呐c意義通過(guò)此實(shí)驗(yàn),學(xué)員將學(xué)習(xí)交叉編譯應(yīng)用程序和在ARM平臺(tái)上驗(yàn)證程序的方法?;驹砗头椒ㄊ褂媒徊婢幾g器編譯一個(gè)ARM平臺(tái)的應(yīng)用程序,通過(guò)NFS進(jìn)行驗(yàn)證。實(shí)驗(yàn)內(nèi)容及步驟編輯下面的c程序,使用arm-linux-的工具鏈編譯,然后在目標(biāo)板上執(zhí)行。1) 在主機(jī)上, 編寫(xiě)一個(gè)最簡(jiǎn)單的 “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)修改網(wǎng)絡(luò)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)修改系統(tǒng)中最大進(jìn)程數(shù)量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、- 設(shè)備IO端口 rootvm root#cat /proc/meminfo - 內(nèi)存信息(i.e. mem used, free, swap size) rootvm root#cat /proc/partitions - 所有設(shè)備的所有分區(qū) rootvm root#cat /proc/pci - PCI設(shè)備的信息 rootvm root#cat /proc/swaps - 所有Swap分區(qū)的信息 rootvm root#cat /proc/version - Linux的版本號(hào)實(shí)驗(yàn)2-3 使用fork、exit和exec系統(tǒng)調(diào)用編寫(xiě)多進(jìn)程程序?qū)嶒?yàn)?zāi)康呐c意義本實(shí)驗(yàn)將通過(guò)編寫(xiě)fork等系統(tǒng)調(diào)用

21、的程序,加深對(duì)系統(tǒng)進(jìn)程及其控制的了解。基本原理和方法fork后父子進(jìn)程會(huì)同步運(yùn)行,但父子進(jìn)程的返回順序是不確定的。設(shè)兩個(gè)變量global和test來(lái)檢測(cè)父子進(jìn)程共享資源的情況。同時(shí)在進(jìn)程退出時(shí)對(duì)exit和_exit的區(qū)別進(jìn)行測(cè)試和說(shuō)明。實(shí)驗(yàn)內(nèi)容及步驟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);編譯執(zhí)行,并分析結(jié)果: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可以看出父子進(jìn)程打印出了各自的進(jìn)程號(hào)和對(duì)應(yīng)變量的值,顯然global和test在父子進(jìn)程間是獨(dú)立的,其各自的操作不會(huì)對(duì)對(duì)方的值有影響。將上述代碼最后的兩行代碼替換為注釋掉的_exit(0)行,重新編譯,查看結(jié)果,解釋原因:rootlocalhost root# ./testthe test content! fork test!global=23 test=1 Child,my PID is 2771父進(jìn)程的信息沒(méi)有打印出來(lái),其原因是:_exit()函數(shù)直接使進(jìn)程停止運(yùn)行,清除其使用的內(nèi)存空間,并銷毀其在內(nèi)核中的各種數(shù)據(jù)結(jié)構(gòu);而exit()

25、函數(shù)則在這些基礎(chǔ)上作了一些包裝,在執(zhí)行退出之前加了若干道工序。exit()函數(shù)在調(diào)用exit系統(tǒng)調(diào)用之前要檢查文件的打開(kāi)情況,把文件緩沖區(qū)中的內(nèi)容寫(xiě)回文件,即會(huì) 清理I/O緩沖。若將上述_exit(0)改為exit(0),則肯定會(huì)有打印。另外,需要注意換行符n會(huì)引起IO的清理操作,若下面的語(yǔ)句printf(global=%d test%d Parent,my PID is %d,global,test,getpid(); 加上n,則調(diào)用_exit(0)的結(jié)果和調(diào)用exit(0)的結(jié)果是一樣的。2vfork的特點(diǎn)將上述代碼的pid = fork(); 改為pid = vfork();編譯后運(yùn)行結(jié)

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區(qū)別在于共享的資源不一樣,vfork調(diào)用后,子進(jìn)程先對(duì)global和test加1,父進(jìn)程運(yùn)行時(shí),在其基礎(chǔ)之上再加2,得到上述運(yùn)行結(jié)果。即vfork的特點(diǎn)是:在調(diào)用execv或者exit前子進(jìn)程對(duì)變量的修改會(huì)影響到父進(jìn)程,即他們是共享的;特別注意:父進(jìn)程等待子進(jìn)程調(diào)用execv或exit才繼續(xù)執(zhí)行。則若

27、子進(jìn)程依賴父進(jìn)程的進(jìn)一步動(dòng)作時(shí),父進(jìn)程又必須阻塞到子進(jìn)程調(diào)用execv或者exit才會(huì)往下執(zhí)行,此時(shí)就會(huì)造成“死鎖”。讀者可自己設(shè)計(jì)測(cè)試一下這種“死鎖”狀態(tài)。3execv函數(shù)族的使用注意點(diǎn):調(diào)用execv后,程序不再返回!在上述代碼基礎(chǔ)上,在子進(jìn)程的退出代碼前加入如下代碼: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);編譯運(yùn)行后結(jié)果為: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的作用是等待子進(jìn)程退出并回收其資源,同時(shí)可以通過(guò)WIFEXITED等宏調(diào)用可以檢測(cè)子進(jìn)程退出的狀態(tài)。在第一個(gè)示例fork使用的代碼基礎(chǔ)上進(jìn)行修改,添加檢測(cè)進(jìn)程退出狀態(tài)的子函數(shù),參考代碼如下: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, /且此進(jìn)程產(chǎn)生一個(gè)內(nèi)存映射文件(core dump)則返回非0 else if(WIFSTOPPED(stat) /如果子進(jìn)程暫停(stopped)則返回非0printf(!the stop code is: %d n,WSTOPSIG(stat);在父進(jìn)程處理g

31、lobal和test變量前加入如下代碼:if(waitpid(pid,&stat,0)!=pid)perror(wait error);exit_check(stat); / the status of exit check編譯運(yùn)行后結(jié)果為: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可以看出父進(jìn)程回收了退出的子進(jìn)

32、程的資源,檢測(cè)到了它的退出狀態(tài)。實(shí)驗(yàn)2-4 編寫(xiě)一個(gè)守護(hù)進(jìn)程實(shí)驗(yàn)?zāi)康呐c意義守護(hù)進(jìn)程是Linux系統(tǒng)開(kāi)發(fā)中很重要的知識(shí)點(diǎn),本實(shí)驗(yàn)要求學(xué)員編寫(xiě)一個(gè)守護(hù)進(jìn)程,通過(guò)本實(shí)驗(yàn),學(xué)員可以熟悉守護(hù)進(jìn)程的編寫(xiě)過(guò)程?;驹砗头椒ㄊ刈o(hù)進(jìn)程編寫(xiě)的主要步驟如下:1屏蔽一些有關(guān)控制終端操作的信號(hào)。防止在守護(hù)進(jìn)程沒(méi)有正常運(yùn)轉(zhuǎn)起來(lái)時(shí),控制終端受到干擾退出或掛起。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 程序進(jìn)入后臺(tái)執(zhí)行。由于守護(hù)進(jìn)程最終脫離控制終端,到后臺(tái)去運(yùn)行。方法是在進(jìn)程中調(diào)用fork使父進(jìn)程終止,讓Daemon在子進(jìn)程中后臺(tái)執(zhí)行。這就是常說(shuō)的“脫殼”。子進(jìn)程繼續(xù)函數(shù)fork()的定義如下:pid_t fork(void);脫離控制終端、登錄會(huì)話和進(jìn)程組。開(kāi)發(fā)人員如果要擺脫它們,不受它們的影響,一般使用 setsid() 設(shè)置新會(huì)話的領(lǐng)頭進(jìn)程,并與原來(lái)的登錄會(huì)話和進(jìn)程組脫離。禁止進(jìn)程重新打開(kāi)控制終端。關(guān)閉打開(kāi)的文件描述符,并重定向標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出的文件描述符。進(jìn)程從創(chuàng)建它的父進(jìn)程那里繼承了打開(kāi)的文件描述符。如果不關(guān)閉,將會(huì)浪費(fèi)

34、系統(tǒng)資源,引起無(wú)法預(yù)料的錯(cuò)誤。關(guān)閉三者的代碼如下:for (fd = 0, fdtablesize = getdtablesize();fd fdtablesize; fd+)close(fd);改變工作目錄到根目錄或特定目錄進(jìn)程活動(dòng)時(shí),其工作目錄所在的文件系統(tǒng)不能卸下處理SIGCHLD信號(hào)。SIGCHLD信號(hào)是子進(jìn)程結(jié)束時(shí),向內(nèi)核發(fā)送的信號(hào)。如果父進(jìn)程不等待子進(jìn)程結(jié)束,子進(jìn)程將成為僵尸進(jìn)程(zombie)從而占用系統(tǒng)資源。因此需要對(duì)SIGCHLD信號(hào)做出處理,回收僵尸進(jìn)程的資源,避免造成不必要的資源浪費(fèi)??梢杂萌缦抡Z(yǔ)句:signal(SIGCHLD,(void *)reap_status);

35、捕捉信號(hào)SIGCHLD,用下面的函數(shù)進(jìn)行處理:void reap_status() int pid; .程序清單:init.ctest.c實(shí)驗(yàn)內(nèi)容及步驟守護(hù)進(jìn)程實(shí)例包括兩部分:主程序test.c和初始化程序init.c。主程序每隔一分鐘向/tmp目錄中的日志test.log報(bào)告運(yùn)行狀態(tài)。初始化程序中的init_daemon函數(shù)負(fù)責(zé)生成守護(hù)進(jìn)程。讀者可以利用init_daemon函數(shù)生成自己的守護(hù)進(jìn)程。 1 init.c #include #include #include #include #include #include void init_daemon(void) int pid; in

36、t i; if(pid=fork() exit(0);/是父進(jìn)程,結(jié)束父進(jìn)程 else if(pid 0) exit(1);/fork失敗,退出 /是第一子進(jìn)程,后臺(tái)繼續(xù)執(zhí)行 setsid();/第一子進(jìn)程成為新的會(huì)話組長(zhǎng)和進(jìn)程組長(zhǎng) /并與控制終端分離 if(pid=fork() exit(0);/是第一子進(jìn)程,結(jié)束第一子進(jìn)程 else if(pid 0) exit(1);/fork失敗,退出 /是第二子進(jìn)程,繼續(xù) /第二子進(jìn)程不再是會(huì)話組長(zhǎng) for(i=0;i NOFILE;+i)/關(guān)閉打開(kāi)的文件描述符 close(i); chdir(/tmp);/改變工作目錄到/tmp umask(0);

37、/重設(shè)文件創(chuàng)建掩模 return; 2 test.c #include #include void init_daemon(void);/守護(hù)進(jìn)程初始化函數(shù) int main() FILE *fp; time_t t; init_daemon();/初始化為Daemon while(1)/每隔一分鐘向test.log報(bào)告運(yùn)行狀態(tài) 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 執(zhí)行:rootvm root#./test 查看進(jìn)程:rootvm root#ps ef 從輸出可以發(fā)現(xiàn)test守護(hù)進(jìn)程的各種特性滿足上面的要求。實(shí)驗(yàn)2-5 用消息隊(duì)列編寫(xiě)一個(gè)客戶端服務(wù)器通信的程序?qū)嶒?yàn)?zāi)康呐c意義通過(guò)此實(shí)驗(yàn),學(xué)員可以熟悉消息隊(duì)列的概念,并能夠用消息隊(duì)列編寫(xiě)一個(gè)客戶端服務(wù)器通信的程序?;驹砗头椒ū緦?shí)驗(yàn)需要用消息隊(duì)列設(shè)計(jì)一個(gè)簡(jiǎn)易的雙人聊天程序(一個(gè)服務(wù)器,兩個(gè)客戶端)。消息隊(duì)列重點(diǎn)在于消息類型的匹配,客戶端和服務(wù)端的“通信協(xié)議”的設(shè)計(jì)。設(shè)計(jì)思想如下:服務(wù)器端:接受客戶端發(fā)來(lái)的任何信息,并根據(jù)其消息類型,轉(zhuǎn)發(fā)給對(duì)應(yīng)的客戶端。同

39、時(shí),檢測(cè)是否有退出標(biāo)志,有則給所有的客戶端發(fā)送退出標(biāo)志,等待10s后,確定客戶端都退出后,刪除消息隊(duì)列,釋放空間,并退出??蛻舳耍篈和B,A給B發(fā)送信息,先發(fā)給服務(wù)器,由服務(wù)器根據(jù)自定義協(xié)議轉(zhuǎn)發(fā)該消息給B。同時(shí)B接受到消息后,經(jīng)由服務(wù)器給A一個(gè)回執(zhí)信息,以此形成簡(jiǎn)易的聊天模式。程序清單:server.c client1.c client2.c實(shí)驗(yàn)內(nèi)容及步驟編寫(xiě)服務(wù)器端程序:#define KEY_MSG 0 x101 /使用共有的IPC key#define MSGSIZE 128#include #include #include #include #include main() int m

40、sgid; struct msgbuf /定義消息結(jié)構(gòu)體:消息類型和消息數(shù)據(jù) long mtype; char mtext128; buf1, buf2; msgid = msgget( KEY_MSG, IPC_CREAT|0666 ); while( 1 ) /無(wú)限循環(huán),退出標(biāo)志則會(huì)break msgrcv( msgid, &buf1, MSGSIZE, 1L, 0 ); /接受客戶端1的消息printf( Receive client1 message: %sn, buf1.mtext ); /打印收到的消息if( buf1.mtext0 = x | buf1.mtext0 = X )

41、/若是退出標(biāo)志,則給2個(gè)客戶端都發(fā)退出信息 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的消息轉(zhuǎn)發(fā)給客戶端2 msgrcv( msgid, &buf2, MSGSIZE, 2L, 0 ); /接受客戶端2的消息printf( Receive clien

42、t2 message: %sn, buf2.mtext ); /打印收到的消息if( buf2.mtext0 = x | buf2.mtext0 = X )/若是退出標(biāo)志,則給2個(gè)客戶端發(fā)退出信息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的消息轉(zhuǎn)發(fā)給

43、客戶端1 sleep(5); /若退出,則先等待,以確??蛻舳顺绦蛲顺?msgctl( msgid, IPC_RMID, NULL ); /刪除消息隊(duì)列,釋放空間 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獲取消息并發(fā)往服務(wù)器sleep(1); /等待一秒,以確??蛻舳?已經(jīng)收到并發(fā)了回執(zhí) msgrcv( msgid, &buf2, MSGSIZE, 3L, 0 ); /準(zhǔn)備從客戶端2獲取回執(zhí)消息 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發(fā)消息 if( buf2.mtext0 = x | buf2.mtext0 = X ) printf( client2 will quit!n ); break; else printf( Receive from client1, message: %sn, buf2.mtext );sleep(1); /等待一秒,以確??蛻舳?已經(jīng)收到了回執(zhí)printf( input the msg to client1: ); gets( buf1.mtext ); buf1.mtype = 2L; msgsnd( msgid, &buf1, MSGSIZE, 0 ); /給客戶端1發(fā)送回執(zhí)

47、消息 運(yùn)行測(cè)試。先編譯運(yùn)行服務(wù)器,確保消息隊(duì)列已經(jīng)創(chuàng)建完畢,并進(jìn)入等待狀態(tài)。結(jié)果如下: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的運(yùn)行結(jié)果如下: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的運(yùn)行結(jié)果如下: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#實(shí)驗(yàn)2-6 編寫(xiě)串口通信的多進(jìn)程程序?qū)嶒?yàn)?zāi)康呐c意義通過(guò)本實(shí)驗(yàn),學(xué)員可以掌握ARM的串行口工作原理,了解ARM的UART通訊。在了解了串口編程后,擴(kuò)展到多串口同時(shí)通信,從而掌握遠(yuǎn)程主機(jī)間的進(jìn)程間通信技術(shù)?;驹砗头椒ù贑OM的讀寫(xiě)主要是對(duì)其IO屬性進(jìn)行設(shè)定,然后用read和write對(duì)其進(jìn)行操作。本實(shí)驗(yàn)設(shè)計(jì)主機(jī)1的進(jìn)程A對(duì)串口反復(fù)寫(xiě)的程序和主機(jī)2客戶進(jìn)程B從COM讀取的程序,可通過(guò)COM互連方式進(jìn)行雙機(jī)的測(cè)試,或通過(guò)交叉編譯后在嵌入式開(kāi)發(fā)板和主機(jī)之間進(jìn)程調(diào)試。注意:兩程序的串口參數(shù)設(shè)置的一致性。實(shí)驗(yàn)內(nèi)容及步驟編寫(xiě)如下代碼,并運(yùn)行調(diào)試:/*寫(xiě)串口*/#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;/*保存測(cè)試現(xiàn)有串口參數(shù)設(shè)置,在這里如果串口號(hào)等出錯(cuò),會(huì)有相關(guān)的出錯(cuò)信息*/if ( tcgetattr( fd,&oldtio) != 0) perror(SetupSerial 1);return -1;bzero( &newtio, sizeof(

51、 newtio ) );/*步驟一,設(shè)置字符大小*/newtio.c_cflag |= CLOCAL | CREAD; newtio.c_cflag &= CSIZE; /*設(shè)置停止位*/switch( nBits )case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;/*設(shè)置奇偶校驗(yàn)位*/switch( nEvent )case O: /奇數(shù)newtio.c_cflag |= PARENB;newtio.c_cflag |= PARODD;newtio.c_iflag |= (INPCK | ISTRIP

52、);break;case E: /偶數(shù)newtio.c_iflag |= (INPCK | ISTRIP);newtio.c_cflag |= PARENB;newtio.c_cflag &= PARODD;break;case N: /無(wú)奇偶校驗(yàn)位newtio.c_cflag &= PARENB;break;/*設(shè)置波特率*/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;/*設(shè)置停止位*/if( nStop = 1 )newtio.c_cflag &= CSTOPB;else if ( nStop = 2 )newtio.c_cflag |= CSTOPB;/*設(shè)置等待時(shí)間和最小接收字符*/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;/*打開(kāi)串口函數(shù)*/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);/*恢復(fù)串口為阻塞狀態(tài)*/if(fcntl(fd, F_SETFL, 0)0)printf(fcntl failed!n);elseprintf(fcntl=%dn,fcntl(fd, F_SETFL,0);/*測(cè)試是否為終端設(shè)備*/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;/*打開(kāi)串口*/if(fd=open_port(fd,1)0) perror(open_port error);return;/*設(shè)置串口*/if(i=set_opt(fd,115200,8,N,1)0) perror(se

58、t_opt error);return;printf(fd=%dn,fd);/*向串口寫(xiě)入字符串*/ for(i=0;i20;i+)nwrite=write(fd,buff,8);printf(nwrite=%dn,nwrite);sleep(1);close(fd);return;讀串口程序的有關(guān)串口屬性設(shè)置的子函數(shù)和寫(xiě)串口程序一致,這里僅給出主函數(shù),如下:/*讀串口程序*/int main(void) int fd;int nread,i;char buff=Hellon;if(fd=open_port(fd,1)0)/打開(kāi)串口perror(open_port error);return;

59、if(i=set_opt(fd,115200,8,N,1)0)/設(shè)置串口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;程序調(diào)試:調(diào)試串口寫(xiě)程序時(shí),可將主機(jī)的兩個(gè)串口用串口連接線相連,如下圖。然后主機(jī)可用串口調(diào)試工具,如串口調(diào)試精靈打開(kāi)COM2,而程序代碼打開(kāi)COM1,并往里面循環(huán)寫(xiě)數(shù)據(jù)。若程序無(wú)異常,串口調(diào)試精靈會(huì)顯示出所寫(xiě)的數(shù)據(jù)(有些主機(jī)只有一個(gè)COM時(shí)

60、,則需要兩個(gè)主機(jī)進(jìn)行配合測(cè)試)。主機(jī)COM1COM2圖 串口寫(xiě)程序的調(diào)試你也可以在開(kāi)發(fā)板和主機(jī)之間進(jìn)行程序的調(diào)試。由于開(kāi)發(fā)板一般用COM1作為顯示終端,因此開(kāi)發(fā)板的串口寫(xiě)程序要用COM2作為輸出,并將COM2與遠(yuǎn)端主機(jī)的COM進(jìn)行相連,開(kāi)發(fā)板通過(guò)NFS模式進(jìn)行程序的編譯和運(yùn)行,主機(jī)A則運(yùn)行串口的讀程序。概圖如圖2所示。Net主機(jī)A開(kāi)發(fā)板NFS Server(主機(jī)B)COM1COMCOM1COM2圖 開(kāi)發(fā)板和主機(jī)間的串口讀寫(xiě)程序調(diào)試注意:開(kāi)發(fā)板的COM2可否進(jìn)行讀寫(xiě),需要開(kāi)發(fā)板上運(yùn)行的內(nèi)核的支持。實(shí)驗(yàn)3-1 編寫(xiě)一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)通信程序(socket)實(shí)驗(yàn)?zāi)康呐c意義同過(guò)本實(shí)驗(yàn),編寫(xiě)一個(gè)簡(jiǎn)單的soc

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論