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

下載本文檔

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

文檔簡介

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

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

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

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

5、22/index.html t _blank TCP的文件傳送協(xié)議(FTP)不同,為了保持簡單和短小,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ū)動程序)都能適合只讀存儲器。Linux系統(tǒng)的服務(wù)以配置文件方法進行配置,因此要找到tftp服務(wù)的配置文件所在,并根據(jù)實際情況配置根目錄和權(quán)限等內(nèi)容

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

7、NFS服務(wù)實驗?zāi)康呐c意義通過此實驗,學(xué)員可以熟悉nfs服務(wù),了解nfs服務(wù)原理和配置方法。基本原理和方法NFS是網(wǎng)絡(luò)文件系統(tǒng)(Network File System)的簡稱,是分布式計算系統(tǒng)的一個組成部分,可實現(xiàn)在異種網(wǎng)絡(luò)上共享和裝配遠程文件系統(tǒng)。nfs的配置文件是/etc/exports,所以我們查看并修改這個文件。在該文件中增加根文件系統(tǒng)。實驗內(nèi)容及步驟安裝nfs服務(wù)器端和客戶端(如果沒有該軟件包)服務(wù)器端: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是要共享的目錄,代表允許所有的網(wǎng)絡(luò)段訪問,rw是可讀寫權(quán)限,sync是資料同步寫入內(nèi)存和硬盤,no_root_squash是NFS客戶端分享目錄使用者的權(quán)限,如果客戶端使用的是root用戶,那么對于該共享目錄而言,該客戶端就具有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 只讀訪問rw 讀寫訪問sync 所有數(shù)據(jù)在請求時寫入共享async NFS在寫入數(shù)據(jù)前可以相應(yīng)請求secure NFS通過1024以下的安全TCP/IP端口發(fā)送insecure NFS通過1024以上的端口發(fā)送wdelay 如果多個用戶要寫入NFS目

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

11、限(默認(rèn))no_root_squas root用戶具有根目錄的完全管理訪問權(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)控程序,它通過/etc/rc.d/init.d目錄中的nfs腳本啟動。NFS監(jiān)控程序還啟動rpc.mountd裝載監(jiān)控程序,并導(dǎo)出共享目錄。RPC裝載:可以用mount命令連接本地目錄或網(wǎng)絡(luò)目錄,但還需要一個裝載NFS目錄的特殊監(jiān)控程序rpc.mount端口映射器:portmap監(jiān)控

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

13、profile文件中修改PATH環(huá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)中,沒有使用/etc/profile這個全局有效的配置文件,而是使用root下的.bashrc環(huán)境變量。這樣的話,如果以非root登陸,則不會將交叉編譯器添加到PATH中。因此請大家注意這個區(qū)別??梢圆榭?root/.bashrc文件,以了解

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

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

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

17、age實驗1-7 編寫并下載應(yīng)用程序到嵌入式平臺實驗?zāi)康呐c意義通過此實驗,學(xué)員將學(xué)習(xí)交叉編譯應(yīng)用程序和在ARM平臺上驗證程序的方法?;驹砗头椒ㄊ褂媒徊婢幾g器編譯一個ARM平臺的應(yīng)用程序,通過NFS進行驗證。實驗內(nèi)容及步驟編輯下面的c程序,使用arm-linux-的工具鏈編譯,然后在目標(biāo)板上執(zhí)行。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)修改網(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)中最大進程數(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的版本號實驗2-3 使用fork、exit和exec系統(tǒng)調(diào)用編寫多進程程序?qū)嶒災(zāi)康呐c意義本實驗將通過編寫fork等系統(tǒng)調(diào)用

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

25、函數(shù)則在這些基礎(chǔ)上作了一些包裝,在執(zhí)行退出之前加了若干道工序。exit()函數(shù)在調(diào)用exit系統(tǒng)調(diào)用之前要檢查文件的打開情況,把文件緩沖區(qū)中的內(nèi)容寫回文件,即會 清理I/O緩沖。若將上述_exit(0)改為exit(0),則肯定會有打印。另外,需要注意換行符n會引起IO的清理操作,若下面的語句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的特點將上述代碼的pid = fork(); 改為pid = vfork();編譯后運行結(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)用后,子進程先對global和test加1,父進程運行時,在其基礎(chǔ)之上再加2,得到上述運行結(jié)果。即vfork的特點是:在調(diào)用execv或者exit前子進程對變量的修改會影響到父進程,即他們是共享的;特別注意:父進程等待子進程調(diào)用execv或exit才繼續(xù)執(zhí)行。則若

27、子進程依賴父進程的進一步動作時,父進程又必須阻塞到子進程調(diào)用execv或者exit才會往下執(zhí)行,此時就會造成“死鎖”。讀者可自己設(shè)計測試一下這種“死鎖”狀態(tài)。3execv函數(shù)族的使用注意點:調(diào)用execv后,程序不再返回!在上述代碼基礎(chǔ)上,在子進程的退出代碼前加入如下代碼: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);編譯運行后結(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的作用是等待子進程退出并回收其資源,同時可以通過WIFEXITED等宏調(diào)用可以檢測子進程退出的狀態(tài)。在第一個示例fork使用的代碼基礎(chǔ)上進行修改,添加檢測進程退出狀態(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, /且此進程產(chǎn)生一個內(nèi)存映射文件(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編譯運行后結(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可以看出父進程回收了退出的子進

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

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

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

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

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

39、時,檢測是否有退出標(biāo)志,有則給所有的客戶端發(fā)送退出標(biāo)志,等待10s后,確定客戶端都退出后,刪除消息隊列,釋放空間,并退出??蛻舳耍篈和B,A給B發(fā)送信息,先發(fā)給服務(wù)器,由服務(wù)器根據(jù)自定義協(xié)議轉(zhuǎn)發(fā)該消息給B。同時B接受到消息后,經(jīng)由服務(wù)器給A一個回執(zhí)信息,以此形成簡易的聊天模式。程序清單:server.c client1.c client2.c實驗內(nèi)容及步驟編寫服務(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 ) /無限循環(huán),退出標(biāo)志則會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個客戶端都發(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個客戶端發(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 ); /刪除消息隊列,釋放空間 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); /等待一秒,以確保客戶端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、消息 運行測試。先編譯運行服務(wù)器,確保消息隊列已經(jīng)創(chuàng)建完畢,并進入等待狀態(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的運行結(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的運行結(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#實驗2-6 編寫串口通信的多進程程序?qū)嶒災(zāi)康呐c意義通過本實驗,學(xué)員可以掌握ARM的串行口工作原理,了解ARM的UART通訊。在了解了串口編程后,擴展到多串口同時通信,從而掌握遠程主機間的進程間通信技術(shù)。基本原理和方法串口COM的讀寫主要是對其IO屬性進行設(shè)定,然后用read和write對其進行操作。本實驗設(shè)計主機1的進程A對串口反復(fù)寫的程序和主機2客戶進程B從COM讀取的程序,可通過COM互連方式進行雙機的測試,或通過交叉編譯后在嵌入式開發(fā)板和主機之間進程調(diào)試。注意:兩程序的串口參數(shù)設(shè)置的一致性。實驗內(nèi)容及步驟編寫如下代碼,并運行調(diào)試:/*寫串口*/#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;/*保存測試現(xiàn)有串口參數(shù)設(shè)置,在這里如果串口號等出錯,會有相關(guān)的出錯信息*/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è)置奇偶校驗位*/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: /無奇偶校驗位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è)置等待時間和最小接收字符*/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;/*打開串口函數(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);/*測試是否為終端設(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;/*打開串口*/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);/*向串口寫入字符串*/ for(i=0;i20;i+)nwrite=write(fd,buff,8);printf(nwrite=%dn,nwrite);sleep(1);close(fd);return;讀串口程序的有關(guān)串口屬性設(shè)置的子函數(shù)和寫串口程序一致,這里僅給出主函數(shù),如下:/*讀串口程序*/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)/設(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)試串口寫程序時,可將主機的兩個串口用串口連接線相連,如下圖。然后主機可用串口調(diào)試工具,如串口調(diào)試精靈打開COM2,而程序代碼打開COM1,并往里面循環(huán)寫數(shù)據(jù)。若程序無異常,串口調(diào)試精靈會顯示出所寫的數(shù)據(jù)(有些主機只有一個COM時

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

溫馨提示

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

評論

0/150

提交評論