




下載本文檔
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、linux操作系統(tǒng)下c語(yǔ)言編程入門(一)目錄介紹1)Linux程序設(shè)計(jì)入門-基礎(chǔ)知識(shí)2)Linux程序設(shè)計(jì)入門-進(jìn)程介紹3)Linux程序設(shè)計(jì)入門-文件操作4)Linux程序設(shè)計(jì)入門-時(shí)間概念5)Linux程序設(shè)計(jì)入門-信號(hào)處理6)Linux程序設(shè)計(jì)入門-消息管理7)Linux程序設(shè)計(jì)入門-線程操作8)Linux程序設(shè)計(jì)入門-網(wǎng)絡(luò)編程9)Linux下C開發(fā)工具介紹(二)具體內(nèi)容1)Linux程序設(shè)計(jì)入門-基礎(chǔ)知識(shí)Linux下C語(yǔ)言編程基礎(chǔ)知識(shí)前言:這篇文章介紹在LINUX下進(jìn)行C語(yǔ)言編程所需要的基礎(chǔ)知識(shí).在這篇文章當(dāng)中我們將會(huì)學(xué)到以下內(nèi)容:源程序編譯Makefile的編寫程序庫(kù)的鏈接程序的調(diào)試
2、頭文件和系統(tǒng)求助1 .源程序的編譯在Linux下面,如果要編譯一個(gè)C語(yǔ)言源程序,我們要使用GNU勺gcc編譯器.下面我們以一個(gè)實(shí)例來(lái)說(shuō)明如何使用gcc編譯器.假設(shè)我們有下面一個(gè)非常簡(jiǎn)單的源程序(hello.c):intmain(intargc,char*argv)printf("HelloLinuxn");要編譯這個(gè)程序,我們只要在命令行下執(zhí)行:gcc-ohellohello.cgcc編譯器就會(huì)為我們生成一個(gè)hello的可執(zhí)行文件.執(zhí)行./hello就可以看到程序的輸出結(jié)果了.命令行中g(shù)cc表示我們是用gcc來(lái)編譯我們的源程序,-o選項(xiàng)表示我們要求編譯器給我們車出的可執(zhí)行文
3、件名為hello而hello.c是我們的源程序文件.gcc編譯器有許多選項(xiàng),一般來(lái)說(shuō)我們只要知道其中的幾個(gè)就夠了.-o選項(xiàng)我們已經(jīng)知道了,表示我們要求輸出的可執(zhí)行文件名.-c選項(xiàng)表示我們只要求編譯器輸出目標(biāo)代碼,而不必要輸出可執(zhí)行文件.-g選項(xiàng)表示我們要求編譯器在編譯的時(shí)候提供我們以后對(duì)程序進(jìn)行調(diào)試的信息.知道了這三個(gè)選項(xiàng),我們就可以編譯我們自己所寫的簡(jiǎn)單的源程序了,如果你想要知道更多的選項(xiàng),可以查看gcc的幫助文檔,那里有著許多對(duì)其它選項(xiàng)的詳細(xì)說(shuō)明.2 .Makefile的編寫假設(shè)我們有下面這樣的一個(gè)程序,源代碼如下main.c#include"mytooll.h"#in
4、clude"mytool2.h"intmain(intargc,char*argv)(mytool1_print("hello");mytool2_print("hello");/*mytool1.h*/#ifndef_MYTOOL_1_H#define_MYTOOL_1_Hvoidmytool1_print(char*print_str);#endif/*mytool1.c*/#include"mytool1.h"voidmytool1_print(char*print_str)(printf("Thi
5、sismytool1print%sn",print_str);/*mytool2.h*/#ifndef_MYTOOL_2_H#define_MYTOOL_2_Hvoidmytool2_print(char*print_str);#endif/*mytool2.c*/#include"mytool2.h"voidmytool2_print(char*print_str)(printf("Thisismytool2print%sn",print_str);當(dāng)然由于這個(gè)程序是很短的我們可以這樣來(lái)編譯gcc-cmain.cgcc-cmytooll.cg
6、cc-cmytool2.cgcc-omainmain.omytooll.omytool2.o這樣的話我們也可以產(chǎn)生main程序,而且也不時(shí)很麻煩.但是如果我們考慮一下如果有一天我們修改了其中的一個(gè)文件(比如說(shuō)mytooll.c)那么我們難道還要重新輸入上面的命令?也許你會(huì)說(shuō),這個(gè)很容易解決啊,我寫一個(gè)SHELL腳本,讓她幫我去完成不就可以了.是的對(duì)于這個(gè)程序來(lái)說(shuō),是可以起到作用的.但是當(dāng)我們把事情想的更復(fù)雜一點(diǎn),如果我們的程序有幾百個(gè)源程序的時(shí)候,難道也要編譯器重新一個(gè)一個(gè)的去編譯?為此,聰明的程序員們想出了一個(gè)很好的工具來(lái)做這件事情,這就是make.我們只要執(zhí)行一下make,就可以把上面的問(wèn)
7、題解決掉.在我們執(zhí)行make之前,我們要先編寫一個(gè)非常重要的文件.-Makefile.對(duì)于上面的那個(gè)程序來(lái)說(shuō),可能的一個(gè)Makefile的文件是:#這是上面那個(gè)程序的Makefile文件main:main.omytool1.omytool2.ogcc-omainmain.omytool1.omytool2.omain.o:main.cmytool1.hmytool2.hgcc-cmain.cmytool1.o:mytool1.cmytool1.hgcc-cmytool1.cmytool2.o:mytool2.cmytool2.hgcc-cmytool2.c有了這個(gè)Makefile文件,不過(guò)我們
8、什么時(shí)候修改了源程序當(dāng)中的什么文件,我們只要執(zhí)行make命令,我們的編譯器都只會(huì)去編譯和我們修改的文件有關(guān)的文件,其它的文件她連理都不想去理的.下面我們學(xué)習(xí)Makefile是如何編寫的.在Makefile中#開始的行都是注釋行.Makefile中最重要的是描述文件的依賴關(guān)系的說(shuō)明.一般的格式是:target:componentsTABrule第一行表示的是依賴關(guān)系.第二行是規(guī)則.比如說(shuō)我們上面的那個(gè)Makefile文件的第二行main:main.omytool1.omytool2.o表示我們的目標(biāo)(target)main的依賴對(duì)象(components)是main.omytool1.omyto
9、ol2.o當(dāng)倚賴的對(duì)象在目標(biāo)修改后修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我們的上面那個(gè)Makefile第三行所說(shuō)的一樣要執(zhí)行g(shù)cc-omainmain.omytool1.omytool2.o注意規(guī)則一行中的TAB表示那里是一個(gè)TAB鍵Makefile有三個(gè)非常有用的變量.分別是$,$人,$<代表的意義分別是:$-目標(biāo)文件,$人-所有的依賴文件,$<-第一個(gè)依賴文件.如果我們使用上面三個(gè)變量,那么我們可以簡(jiǎn)化我們的Make巾le文件為:#這是簡(jiǎn)化后的Makefilemain:main.omytool1.omytool2.ogcc-o$Amain.o:main.cmytool1
10、.hmytool2.hgcc-c$<mytool1.o:mytool1.cmytooll.hgcc-c$<mytool2.o:mytool2.cmytool2.hgcc-c$<經(jīng)過(guò)簡(jiǎn)化后我們的Make巾le是簡(jiǎn)單了一點(diǎn),不過(guò)人們有時(shí)候還想簡(jiǎn)單一點(diǎn).這里我們學(xué)習(xí)一個(gè)Make巾le的缺省規(guī)則.c.o:gcc-c$<這個(gè)規(guī)則表示所有的.o文件都是依賴于相應(yīng)的.c文件的.例如mytool.o依賴于mytool.c這樣Make巾le還可以變?yōu)椋?這是再一次簡(jiǎn)化后的Makefilemain:main.omytool1.omytool2.ogcc-o$A.c.o:gcc-c$<
11、好了,我們的Makefile也差不多了,如果想知道更多的關(guān)于Makefile規(guī)則可以查看相應(yīng)的文檔.3 .程序庫(kù)的鏈接試著編譯下面這個(gè)程序/*temp.c*/#include<math.h>intmain(intargc,char*argv)(doublevalue;printf("Value:%fn",value);)這個(gè)程序相當(dāng)簡(jiǎn)單,但是當(dāng)我們用gcc-otemptemp.c編譯時(shí)會(huì)出現(xiàn)下面所示的錯(cuò)誤./tmp/cc33Kydu.o:Infunction'main':/tmp/cc33Kydu.o(.text+0xe):undefinedre
12、ferenceto'log'collect2:ldreturned1exitstatus出現(xiàn)這個(gè)錯(cuò)誤是因?yàn)榫幾g器找不到10g的具體實(shí)現(xiàn).雖然我們包括了正確的頭文件,但是我們?cè)诰幾g的時(shí)候還是要連接確定的庫(kù).在Linux下,為了使用數(shù)學(xué)函數(shù),我們必須和數(shù)學(xué)庫(kù)連接,為此我們要加入-lm選項(xiàng).gcc-otemptemp.c-lm這樣才能夠正確的編譯.也許有人要問(wèn),前面我們用printf函數(shù)的時(shí)候怎么沒有連接庫(kù)呢?是這樣的,對(duì)于一些常用的函數(shù)的實(shí)現(xiàn),gcc編譯器會(huì)自動(dòng)去連接一些常用庫(kù),這樣我們就沒有必要自己去指定了.有時(shí)候我們?cè)诰幾g程序的時(shí)候還要指定庫(kù)的路徑,這個(gè)時(shí)候我們要用到編譯器的-
13、L選項(xiàng)指定路徑.比如說(shuō)我們有一個(gè)庫(kù)在/home/hoyt/mylib下,這樣我們編譯的時(shí)候還要加上-L/home/hoyt/mylib.對(duì)于一些標(biāo)準(zhǔn)庫(kù)來(lái)說(shuō),我們沒有必要指出路徑.只要它們?cè)谄淙笔?kù)的路徑下就可以了.系統(tǒng)的缺省庫(kù)的路徑/lib/usr/lib/usr/local/lib在這三個(gè)路徑下面的庫(kù),我們可以不指定路徑.還有一個(gè)問(wèn)題,有時(shí)候我們使用了某個(gè)函數(shù),但是我們不知道庫(kù)的名字,這個(gè)時(shí)候怎么辦呢?很抱歉,對(duì)于這個(gè)問(wèn)題我也不知道答案,我只有一個(gè)傻辦法.首先,我到標(biāo)準(zhǔn)庫(kù)路徑下面去找看看有沒有和我用的函數(shù)相關(guān)的庫(kù),我就這樣找到了線程(thread)函數(shù)的庫(kù)文件(libpthread.a).當(dāng)
14、然,如果找不到,只有一個(gè)笨方法.比如我要找sin這個(gè)函數(shù)所在的庫(kù).就只好用nm-o/lib/*.so|grepsin;/sin命令,然后看/sin文件,到那里面去找了.在sin文件當(dāng)中,我會(huì)找到這樣的一行l(wèi)ibm-2.12so:00009fa0Wsin這樣我就知道了sin在libm-2.1.2.so庫(kù)里面,我用-lm選項(xiàng)就可以了(去掉前面的lib和后面的版本標(biāo)志,就剩下m了所以是-lm).如果你知道怎么找,請(qǐng)趕快告訴我,我回非常感激的.謝謝!4 .程序的調(diào)試我們編寫的程序不太可能一次性就會(huì)成功的,在我們的程序當(dāng)中,會(huì)出現(xiàn)許許多多我們想不到的錯(cuò)誤,這個(gè)時(shí)候我們就要對(duì)我們的程序進(jìn)行調(diào)試了.最常用的
15、調(diào)試軟件是gdb.如果你想在圖形界面下調(diào)試程序,那么你現(xiàn)在可以選擇xxgdb.記得要在編譯的時(shí)候加入-g選項(xiàng).關(guān)于gdb的使用可以看gdb的幫助文件.由于我沒有用過(guò)這個(gè)軟件,所以我也不能夠說(shuō)出如何使用.不過(guò)我不喜歡用gdb.跟蹤一個(gè)程序是很煩的事情,我一般用在程序當(dāng)中輸出中間變量的值來(lái)調(diào)試程序的.當(dāng)然你可以選擇自己的辦法,沒有必要去學(xué)別人的.現(xiàn)在有了許多IDE環(huán)境,里面已經(jīng)自己帶了調(diào)試器了.你可以選擇幾個(gè)試一試找出自己喜歡的一個(gè)用.5 .頭文件和系統(tǒng)求助有時(shí)候我們只知道一個(gè)函數(shù)的大概形式,不記得確切的表達(dá)式,或者是不記得這函數(shù)在那個(gè)頭文件進(jìn)行了說(shuō)明.這個(gè)時(shí)候我們可以求助系統(tǒng).比如說(shuō)我們想知道f
16、read這個(gè)函數(shù)的確切形式,我們只要執(zhí)行manfread系統(tǒng)就會(huì)輸出這函數(shù)的詳細(xì)解釋的.和這個(gè)函數(shù)所在的頭文件stdio.h說(shuō)明了.如果我們要write這個(gè)函數(shù)的說(shuō)明,當(dāng)我們執(zhí)行manwrite時(shí),輸出的結(jié)果卻不是我們所需要的.因?yàn)槲覀円氖莣rite這個(gè)函數(shù)的說(shuō)明,可是出來(lái)的卻是write這個(gè)命令的說(shuō)明.為了得到write的函數(shù)說(shuō)明我們要用man2write.2表示我們用的write這個(gè)函數(shù)是系統(tǒng)調(diào)用函數(shù),還有一個(gè)我們常用的是3表示函數(shù)是C的庫(kù)函數(shù).記住不管什么時(shí)候,man都是我們的最好助手.好了,這一章就講這么多了,有了這些知識(shí)我們就可以進(jìn)入激動(dòng)人心的Linux下的C程序探險(xiǎn)活動(dòng).2)Li
17、nux程序設(shè)計(jì)入門-進(jìn)程介紹Linux下進(jìn)程的創(chuàng)建前言:這篇文章是用來(lái)介紹在Linux下和進(jìn)程相關(guān)的各個(gè)概念.我們將會(huì)學(xué)到:進(jìn)程的概念進(jìn)程的身份進(jìn)程的創(chuàng)建守護(hù)進(jìn)程的創(chuàng)建1.進(jìn)程的概念Linux操作系統(tǒng)是面向多用戶的.在同一時(shí)間可以有許多用戶向操作系統(tǒng)發(fā)出各種命令.那么操作系統(tǒng)是怎么實(shí)現(xiàn)多用戶的環(huán)境呢?在現(xiàn)代的操作系統(tǒng)里面,都有程序和進(jìn)程的概念.那么什么是程序,什么是進(jìn)程呢?通俗的講程序是一個(gè)包含可以執(zhí)行代碼的文件,遑個(gè)靜態(tài)的文件.而進(jìn)程是一個(gè)開始執(zhí)行但是還沒有結(jié)束的程序的實(shí)例.就是可執(zhí)行文件的具體實(shí)現(xiàn).一個(gè)程序可能有許多進(jìn)程,而每一個(gè)進(jìn)程又可以有許多子進(jìn)程.依次循環(huán)下去,而產(chǎn)生子孫進(jìn)程.當(dāng)程序
18、被系統(tǒng)調(diào)用到內(nèi)存以后,系統(tǒng)會(huì)給程序分配一定的資源(內(nèi)存,設(shè)備等等)然后進(jìn)行一系列的復(fù)雜操作,使程序變成進(jìn)程以供系統(tǒng)調(diào)用.在系統(tǒng)里面只有進(jìn)程沒有程序,為了區(qū)分各個(gè)不同的進(jìn)程,系統(tǒng)給每一個(gè)進(jìn)程分配了一個(gè)ID(就象我們的身份證)以便識(shí)別.為了充分的利用資源,系統(tǒng)還對(duì)進(jìn)程區(qū)分了不同的狀態(tài).將進(jìn)程分為新建,運(yùn)行,阻塞,就緒和完成五個(gè)狀態(tài).新建表示進(jìn)程正在被創(chuàng)建,運(yùn)行是進(jìn)程正在運(yùn)行,阻塞是進(jìn)程正在等待某一個(gè)事件發(fā)生,就緒是表示系統(tǒng)正在等待CPU來(lái)執(zhí)行命令,而完成表示進(jìn)程已經(jīng)結(jié)束了系統(tǒng)正在回收資源.關(guān)于進(jìn)程五個(gè)狀態(tài)的詳細(xì)解說(shuō)我們可以看操作系統(tǒng)上面有詳細(xì)的解說(shuō)。2。進(jìn)程的標(biāo)志上面我們知道了進(jìn)程都有一個(gè)ID,那
19、么我們?cè)趺吹玫竭M(jìn)程的ID呢?系統(tǒng)調(diào)用getpid可以得到進(jìn)程的ID,而getppid可以得到父進(jìn)程(創(chuàng)建調(diào)用該函數(shù)進(jìn)程的進(jìn)程)的2.#include<unistd>pid_tgetpid(void);pid_tgetppid(void);進(jìn)程是為程序服務(wù)的,而程序是為了用戶服務(wù)的.系統(tǒng)為了找到進(jìn)程的用戶名,還為進(jìn)程和用戶建立聯(lián)系.這個(gè)用戶稱為進(jìn)程的所有者.相應(yīng)的每一個(gè)用戶也有一個(gè)用戶ID.通過(guò)系統(tǒng)調(diào)用getuid可以得到進(jìn)程的所有者的ID.由于進(jìn)程要用到一些資源,而Linux對(duì)系統(tǒng)資源是進(jìn)行保護(hù)的,為了獲取一定資源進(jìn)程還有一個(gè)有效用戶ID.這個(gè)ID和系統(tǒng)的資源使用有關(guān),涉及到進(jìn)程的
20、權(quán)限.通過(guò)系統(tǒng)調(diào)用geteuid我們可以得到進(jìn)程的有效用戶ID.和用戶ID相對(duì)應(yīng)進(jìn)程還有一個(gè)組ID和有效組ID系統(tǒng)調(diào)用getgid和getegid可以分別得到組ID和有效組ID#include<unistd>#include<sys/types.h>uid_tgetuid(void);uid_tgeteuid(void);gid_tgetgid(void);git_tgetegid(void);有時(shí)候我們還會(huì)對(duì)用戶的其他信息感興趣(登錄名等等),這個(gè)時(shí)候我們可以調(diào)用getpwuid來(lái)得到.structpasswdchar*pw_name;/*登錄名稱*/char*pw_
21、passwd;/*登錄口令*/uid_tpw_uid;/*用戶ID*/gid_tpw_gid;/*用戶組ID*/char*pw_gecos;/*用戶的真名*/char*pw_dir;/*用戶的目錄*/char*pw_shell;/*用戶的SHELL*/);#include<pwd.h>#include<sys/types.h>structpasswd*getpwuid(uid_tuid);下面我們學(xué)習(xí)一個(gè)實(shí)例來(lái)實(shí)踐一下上面我們所學(xué)習(xí)的幾個(gè)函數(shù)#include<unistd.h>#include<pwd.h>#include<sys/type
22、s.h>#include<stdio.h>intmain(intargc,char*argv)pid_tmy_pid,parent_pid;uid_tmy_uid,my_euid;gid_tmy_gid,my_egid;structpasswd*my_info;my_pid=getpid();parent_pid=getppid();my_uid=getuid();my_euid=geteuid();my_gid=getgid();my_egid=getegid();my_info=getpwuid(my_uid);printf("ProcessID:%ldn&qu
23、ot;,my_pid);printf("ParentID:%ldn",parent_pid);printf("UserID:%ldn",my_uid);printf("EffectiveUserID:%ldn",my_euid);printf("GroupID:%ld'n",my_gid);printf("EffectiveGroupID:%ldn",my_egid):if(my_info)printf("MyLoginName:%sn",my_info->pw
24、_name);printf("MyPassword:%sn",my_info->pw_passwd);printf("MyUserID:%ldn",my_info->pw_uid);printf("MyGroupID:%ldn",my_info->pw_gid);printf("MyRealName:%sn",my_info->pw_gecos);printf("MyHomeDir:%sn",my_info->pw_dir);printf("MyWorkS
25、hell:%sn",my_info->pw_shell);3。進(jìn)程的創(chuàng)建創(chuàng)建一個(gè)進(jìn)程的系統(tǒng)調(diào)用很簡(jiǎn)單.我們只要調(diào)用fork函數(shù)就可以了.#include<unistd.h>pid_tfork();當(dāng)一個(gè)進(jìn)程調(diào)用了fork以后,系統(tǒng)會(huì)創(chuàng)建一個(gè)子進(jìn)程.這個(gè)子進(jìn)程和父進(jìn)程不同的地方只有他的進(jìn)程ID和父進(jìn)程ID,其他的都是一樣.就象父進(jìn)程克隆(clone)自己一樣.當(dāng)然創(chuàng)建兩個(gè)一模一樣的進(jìn)程是沒有意義的.為了區(qū)分父進(jìn)程和子進(jìn)程,我們必須跟蹤fork的返回值.當(dāng)fork掉用失敗的時(shí)候(內(nèi)存不足或者是用戶的最大進(jìn)程數(shù)已到)fork返回-1,否則fork的返回值有重要的作用.對(duì)于
26、父進(jìn)程fork返回子進(jìn)程的ID,而對(duì)于fork子進(jìn)程返回0.我們就是根據(jù)這個(gè)返回值來(lái)區(qū)分父子進(jìn)程的.父進(jìn)程為什么要?jiǎng)?chuàng)建子進(jìn)程呢?前面我們已經(jīng)說(shuō)過(guò)了Linux是一個(gè)多用戶操作系統(tǒng),在同一時(shí)間會(huì)有許多的用戶在爭(zhēng)奪系統(tǒng)的資源.有時(shí)進(jìn)程為了早一點(diǎn)完成任務(wù)就創(chuàng)建子進(jìn)程來(lái)爭(zhēng)奪資源.一旦子進(jìn)程被創(chuàng)建,父子進(jìn)程一起從fork處繼續(xù)執(zhí)行,相互競(jìng)爭(zhēng)系統(tǒng)的資源.有時(shí)候我們希望子進(jìn)程繼續(xù)執(zhí)行,而父進(jìn)程阻塞直到子進(jìn)程完成任務(wù).這個(gè)時(shí)候我們可以調(diào)用wait或者waitpid系統(tǒng)調(diào)用.#include<sys/types.h>#include<sys/wait.h>pid_twait(int*sta
27、t_loc);pid_twaitpid(pid_tpid,int*stat_loc,intoptions);wait系統(tǒng)調(diào)用會(huì)使父進(jìn)程阻塞直到一個(gè)子進(jìn)程結(jié)束或者是父進(jìn)程接受到了一個(gè)信號(hào).如果沒有父進(jìn)程沒有子進(jìn)程或者他的子進(jìn)程已經(jīng)結(jié)束wait回立即返回.成功時(shí)(因一個(gè)子進(jìn)程結(jié)束)wait將返回子進(jìn)程的ID,否則返回-1,并設(shè)置全局變量errno.stat_loc是子進(jìn)程的退出狀態(tài).子進(jìn)程調(diào)用exit,_exit或者是return來(lái)設(shè)置這個(gè)值.為了得到這個(gè)值Linux定義了幾個(gè)宏來(lái)測(cè)試這個(gè)返回值.WIFEXITED:判斷子進(jìn)程退出值是非0WEXITSTATU第U斷子進(jìn)程的退出值(當(dāng)子進(jìn)程退出時(shí)非0
28、).WIFSIGNALED:子進(jìn)程由于有沒有獲得的信號(hào)而退出.WTERMSIGF進(jìn)程沒有獲得的信號(hào)(在WIFSIGNALEM真時(shí)才有意義).waitpid等待指定的子進(jìn)程直到子進(jìn)程返回.如果pid為正值則等待指定的進(jìn)程(pid).如果為0則等待任何一個(gè)組ID和調(diào)用者的組ID相同的進(jìn)程.為-1時(shí)等同于wait調(diào)用.小于-1時(shí)等待任何一個(gè)組ID等于pid絕對(duì)值的進(jìn)程.stat_loc和wait的意義一樣.options可以決定父進(jìn)程的狀態(tài).可以取兩個(gè)值WNOHANG:進(jìn)程立即返回當(dāng)沒有子進(jìn)程存在時(shí).WUNTACHE當(dāng)子進(jìn)程結(jié)束時(shí)waitpid返回,但是子進(jìn)程的退出狀態(tài)不可得到.父進(jìn)程創(chuàng)建子進(jìn)程后,
29、子進(jìn)程一般要執(zhí)行不同的程序.為了調(diào)用系統(tǒng)程序,我們可以使用系統(tǒng)調(diào)用exec族調(diào)用.exec族調(diào)用有著5個(gè)函數(shù).#include<unistd.h>intexecl(constchar*path,constchar*arg,.);intexeclp(constchar*file,constchar*arg,.);intexecle(constchar*path,constchar*arg,.);intexecv(constchar*path,char*constargv);intexecvp(constchar*file,char*constargv口);exec族調(diào)用可以執(zhí)行給定程
30、序.關(guān)于exec族調(diào)用的詳細(xì)解說(shuō)可以參考系統(tǒng)手冊(cè)(manexecl).下面我們來(lái)學(xué)習(xí)一個(gè)實(shí)例.注意編譯的時(shí)候要加-lm以便連接數(shù)學(xué)函數(shù)庫(kù).#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>#include<stdio.h>#include<errno.h>#include<math.h>voidmain(void)pid_tchild;intstatus;printf("Thiswilldemostratehowtogetchildstatusn
31、");if(child=fork()=-1)printf("ForkError:%sn",strerror(errno);exit(1);elseif(child=0)(inti;printf("Iamthechild:%ldn",getpid();for(i=0;i<1000000;i+)sin(i);i=5;printf("Iexitwith%dn",i);exit(i);while(child=wait(&status)=-1)&(errno=EINTR);if(child=-1)printf(&
32、quot;WaitError:%sn",strerror(errno);elseif(!status)printf("Child%ldterminatednormallyreturnstatusiszeron",child);elseif(WIFEXITED(status)printf("Child%ldterminatednormallyreturnstatusis%dn",child,WEXITSTATUS(status);elseif(WIFSIGNALED(status)printf("Child%ldterminateddu
33、etosignal%dznotcaughtn",child,WTERMSIG(status);strerror函數(shù)會(huì)返回一個(gè)指定的錯(cuò)誤號(hào)的錯(cuò)誤信息的字符串4。守護(hù)進(jìn)程的創(chuàng)建如果彳在DOS寸代編寫過(guò)程序,那么你也許知道在DOST為了編寫一個(gè)常駐內(nèi)存的程序我們要編寫多少代碼了.相反如果在Linux下編寫一個(gè)"常駐內(nèi)存"的程序卻是很容易的.我們只要幾行代碼就可以做到.實(shí)際上由于Linux是多任務(wù)操作系統(tǒng),我們就是不編寫代碼也可以把一個(gè)程序放到后臺(tái)去執(zhí)行的.我們只要在命令后面加上&符號(hào)SHELL就會(huì)把我們的程序放到后臺(tái)去運(yùn)行的.這里我們"開發(fā)"
34、一個(gè)后臺(tái)檢查郵件的程序.這個(gè)程序每隔一個(gè)指定的時(shí)間回去檢查我們的郵箱,如果發(fā)現(xiàn)我們有郵件了,會(huì)不斷的報(bào)警(通過(guò)機(jī)箱上的小喇叭來(lái)發(fā)出聲音).后面有這個(gè)函數(shù)的加強(qiáng)版本后臺(tái)進(jìn)程的創(chuàng)建思想:首先父進(jìn)程創(chuàng)建一個(gè)子進(jìn)程.然后子進(jìn)程殺死父進(jìn)程(是不是很無(wú)情?).信號(hào)處理所有的工作由子進(jìn)程來(lái)處理.#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<errno.h>#include<fcntl.h>#include<s
35、ignal.h>/*Linux的默任個(gè)人的郵箱地址是/var/spool/mail/用戶的登錄名*/#defineMAIL"/var/spool/mail/hoyt"/*睡眠10秒鐘*/#defineSLEEP_TIME10main(void)pid_tchild;if(child=fork()=-1)printf("ForkError:%sn",strerror(errno);exit(1);elseif(child>0)while(1);if(kill(getppid(),SIGTERM)=-1)printf("KillPare
36、ntError:%sn",strerror(errno);exit(1);intmailfd;while(1)if(mailfd=open(MAIL,O_RDONLY)!=-1)fprintf(stderr,"%s","007");close(mailfd);)sleep(SLEEP_TIME);)你可以在默認(rèn)的路徑下創(chuàng)建你的郵箱文件,然后測(cè)試一下這個(gè)程序.當(dāng)然這個(gè)程序還有很多地方要改善的.我們后面會(huì)對(duì)這個(gè)小程序改善的,再看我的改善之前你可以嘗試自己改善一下.比如讓用戶指定郵箱的路徑和睡眠時(shí)間等等.相信自己可以做到的.動(dòng)手吧,勇敢的探險(xiǎn)者.好了
37、進(jìn)程一節(jié)的內(nèi)容我們就先學(xué)到這里了.進(jìn)程是一個(gè)非常重要的概念,許多的程序都會(huì)用子進(jìn)程.創(chuàng)建一個(gè)子進(jìn)程是每一個(gè)程序員的基本要求!3)Linux程序設(shè)計(jì)入門-文件操作Linux下文件的操作前言:我們?cè)谶@一節(jié)將要討論linux下文件操作的各個(gè)函數(shù).文件的創(chuàng)建和讀寫文件的各個(gè)屬性目錄文件的操作管道文件1.文件的創(chuàng)建和讀寫我假設(shè)你已經(jīng)知道了標(biāo)準(zhǔn)級(jí)的文件操作的各個(gè)函數(shù)(fopen,fread,fwrite等等).當(dāng)然如果你不清楚的話也不要著急.我們討論的系統(tǒng)級(jí)的文件操作實(shí)際上是為標(biāo)準(zhǔn)級(jí)文件操作服務(wù)的.當(dāng)我們需要打開一個(gè)文件進(jìn)行讀寫操作的時(shí)候,我們可以使用系統(tǒng)調(diào)用函數(shù)open.使用完成以后我們調(diào)用另外一個(gè)cl
38、ose函數(shù)進(jìn)行關(guān)閉操作.#include<fcntl.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);intclose(intfd);open函數(shù)有兩個(gè)形式.其中pathname是我們要打開的文件名(包含路彳5名稱,缺省是認(rèn)為在當(dāng)前路徑下面).flags可以去下面的一個(gè)值或者是幾個(gè)值的組合.O_RDONLW
39、只讀的方式打開文件o_wronlw只寫的方式打開文件O_RDWRU賣寫的方式打開文件.O_APPENM追加的方式打開文件.O_CREA醐建一個(gè)文件.O_EXEC$果使用了O_CREA而且文件已經(jīng)存在,就會(huì)發(fā)生一個(gè)錯(cuò)誤.O_NOBLOC粗非阻塞的方式打開一個(gè)文件.O_TRUN或果文件已經(jīng)存在,則刪除文件的內(nèi)容.前面三個(gè)標(biāo)志只能使用任意的一個(gè).如果使用了O_CREAT標(biāo)志,那么我們要使用open的第二種形式.還要指定mode標(biāo)志,用來(lái)表示文件的訪問(wèn)權(quán)限.mode可以是以下情況的組合.S_IRUSR用戶可以讀S_IWUSR用戶可以寫S_IXUSR用戶可以執(zhí)行S_IRWXU用戶可以讀寫執(zhí)行S_IRGR
40、P組可以讀S_IWGRP組可以寫S_IXGRP組可以執(zhí)行S_IRWXG組可以讀寫執(zhí)行S_IROTH其他人可以讀S_IWOTH其他人可以寫S_IXOTH其他人可以執(zhí)行S_IRWXO其他人可以讀寫執(zhí)行S_ISUID設(shè)置用戶執(zhí)行IDS_ISGID設(shè)置組的執(zhí)行ID我們也可以用數(shù)字來(lái)彳t表各個(gè)位的標(biāo)志.Linux總共用5個(gè)數(shù)字來(lái)表示文件的各種權(quán)限00000.第一位表示設(shè)置用戶ID.第二位表示設(shè)置組ID,第三位表示用戶自己的權(quán)限位,第四位表示組的權(quán)限,最后一位表示其他人的權(quán)限.每個(gè)數(shù)字可以取1(執(zhí)行權(quán)限),2(寫權(quán)限),4(讀權(quán)限),0(什么也沒有)或者是這幾個(gè)值的和.比如我們要?jiǎng)?chuàng)建一個(gè)用戶讀寫執(zhí)行組沒有
41、權(quán)限,其他人讀執(zhí)行的文件.設(shè)置用戶ID位那么我們可以使用的模式是-1(設(shè)置用戶ID)0(組沒有設(shè)置)7(1+2+4)0(沒有權(quán)限,使用缺?。?(1+4)即10705:open("temp",O_CREAT,10705);如果我們打開文件成功,open會(huì)返回一個(gè)文件描述符.我們以后對(duì)文件的所有操作就可以對(duì)這個(gè)文件描述符進(jìn)行操作了.當(dāng)我們操作完成以后,我們要關(guān)閉文件了,只要調(diào)用close就可以了,其中fd是我們要關(guān)閉的文件描述符.文件打開了以后,我們就要對(duì)文件進(jìn)行讀寫了.我們可以調(diào)用函數(shù)read和write進(jìn)行文件的讀寫.#include<unistd.h>ssiz
42、e_tread(intfd,void*buffer,size_tcount);ssize_twrite(intfd,constvoid*buffer,size_tcount);fd是我們要進(jìn)行讀寫操作的文件描述符,buffer是我們要寫入文件內(nèi)容或讀出文件內(nèi)容的內(nèi)存地址.count是我們要讀寫的字節(jié)數(shù).對(duì)于普通的文件read從指定的文件(fd)中讀取count字節(jié)到buffer緩沖區(qū)中(記住我們必須提供一個(gè)足夠大的緩沖區(qū)),同時(shí)返回count.如果read讀到了文件的結(jié)尾或者被一個(gè)信號(hào)所中斷,返回值會(huì)小于count.如果是由信號(hào)中斷引起返回,而且沒有返回?cái)?shù)據(jù),read會(huì)返回-1,且設(shè)置errn
43、o為EINTR.當(dāng)程序讀到了文件結(jié)尾的時(shí)候,read會(huì)返回0.write從buffer中寫count字節(jié)到文件fd中,成功時(shí)返回實(shí)際所寫的字節(jié)數(shù).下面我們學(xué)習(xí)一個(gè)實(shí)例,這個(gè)實(shí)例用來(lái)拷貝文件.#include<fcntl.h>#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<string.h>#defineBUFFER_SIZE1024intmain(intargc,char*argv)intfrom_fd,
44、to_fd;intbytes_read,bytes_write;charbufferBUFFER_SIZE;char*ptr;if(argc!=3)fprintf(stderr,"Usage:%sfromfiletofilena",argv0);exit(1);/*打開源文件*/if(from_fd=open(argv1,O_RDONLY)=-1)fprintf(stderr,"Open%sError:%sn",argv1,strerror(errno);exit(1);/*創(chuàng)建目的文件*/if(to_fd=open(argv2,O_WRONLY|O_C
45、REAT,S_IRUSR|S_IWUSR)=-1)fprintf(stderr,"Open%sError:%sn",argv2,strerror(errno);exit(1);/*以下代碼是一個(gè)經(jīng)典的拷貝文件的代碼*/while(bytes_read=read(from_fd,buffer,BUFFER_SIZE)(/*一個(gè)致命的錯(cuò)誤發(fā)生了*/if(bytes_read=-1)&&(errno!=EINTR)break;elseif(bytes_read>0)(ptr=buffer;while(bytes_write=write(to_fd,ptr,b
46、ytes_read)/*一個(gè)致命錯(cuò)誤發(fā)生了*/if(bytes_write=-1)&&(errno!=EINTR)break;/*寫完了所有讀的字節(jié)*/elseif(bytes_write=bytes_read)break;/*只寫了一部分,繼續(xù)寫*/elseif(bytes_write>0)ptr+=bytes_write;bytes_read-=bytes_write;/*寫的時(shí)候發(fā)生的致命錯(cuò)誤*/if(bytes_write=-1)break;close(from_fd);close(to_fd);exit(0);2。文件的各個(gè)屬性文件具有各種各樣的屬性,除了我們上
47、面所知道的文件權(quán)限以外,文件還有創(chuàng)建時(shí)間,大小等等屬性.有時(shí)侯我們要判斷文件是否可以進(jìn)行某種操作(讀,寫等等).這個(gè)時(shí)候我們可以使用access函數(shù).#include<unistd.h>intaccess(constchar*pathname,intmode);pathname:是文件名稱,mode是我們要判斷的屬性.可以取以下值或者是他們的組合.R_OKC件可以讀,W_OKt件可以寫,X_OK文件可以執(zhí)行,F(xiàn)_OK文件存在.當(dāng)我們測(cè)試成功時(shí),函數(shù)返回0,否則如果有一個(gè)條件不符時(shí),返回-1.如果我們要獲得文件的其他屬性,我們可以使用函數(shù)stat或者fstat.#include<
48、;sys/stat.h>#include<unistd.h>intstat(constchar*file_name,structstat*buf);intfstat(intfiledes,structstat*buf);structstatdev_tst_dev;/*設(shè)備*/ino_tst_ino;/*節(jié)點(diǎn)*/mode_tst_mode;/*模式*/nlink_tst_nlink;/*硬連接*/uid_tst_uid;/*用戶ID*/gid_tst_gid;/*組ID*/dev_tst_rdev;/*設(shè)備類型*/off_tst_off;/*文件字節(jié)數(shù)*/unsignedlon
49、gst_blksize;/*塊大小*/unsignedlongst_blocks;/*塊數(shù)*/time_tst_atime;/*time_tst_mtime;/*time_tst_ctime;/*最后一次訪問(wèn)時(shí)間*/最后一次修改時(shí)間*/最后一次改變時(shí)間(指屬性)*/);stat用來(lái)判斷沒有打開的文件,而fstat用來(lái)判斷打開的文件.我們使用最多的屬性是st_mode.通過(guò)這屬性我們可以判斷給定的文件是一個(gè)普通文件還是一個(gè)目錄,連接等等.可以使用下面幾個(gè)宏來(lái)判斷.S_ISLNK(st_mode):是否是一個(gè)連接.S_ISREG是否是一個(gè)常規(guī)文件.S_ISDIR是否是一個(gè)目錄S_ISCHR是否是一
50、個(gè)字符設(shè)備.S_ISBLK是否是一個(gè)塊設(shè)備S_ISFIFO是否是一個(gè)FIFO文件.S_ISSOCK是否是一個(gè)SOCKETt件.我們會(huì)在下面說(shuō)明如何使用這幾個(gè)宏的.3。目錄文件的操作在我們編寫程序的時(shí)候,有時(shí)候會(huì)要得到我們當(dāng)前的工作路徑。C庫(kù)函數(shù)提供了getcwd來(lái)解決這個(gè)問(wèn)題。#include<unistd.h>char*getcwd(char*buffer,size_tsize);我們提供一個(gè)size大小的buffer,getcwd會(huì)把我們當(dāng)前的路徑考到buffer中.如果buffer太小,函數(shù)會(huì)返回-1和一個(gè)錯(cuò)誤號(hào).Linux提供了大量的目錄操作函數(shù),我們學(xué)習(xí)幾個(gè)比較簡(jiǎn)單和常用
51、的函數(shù).#include<dirent.h>#include<unistd.h>#include<fcntl.h>#include<sys/types.h>#include<sys/stat.h>intmkdir(constchar*path,mode_tmode);DIR*opendir(constchar*path);structdirent*readdir(DIR*dir);voidrewinddir(DIR*dir);off_ttelldir(DIR*dir);voidseekdir(DIR*dir,off_toff);int
52、closedir(DIR*dir);structdirentlongd_ino;off_td_off;unsignedshortd_reclen;chard_nameNAME_MAX+1;/*文件名稱*/mkdir很容易就是我們創(chuàng)建一個(gè)目錄,opendir打開一個(gè)目錄為以后讀做準(zhǔn)備.readdir讀一個(gè)打開的目錄.rewinddir是用來(lái)重讀目錄白和我們學(xué)的rewind函數(shù)一樣.closedir是關(guān)閉一個(gè)目錄.telldir和seekdir類似與ftee和fseek函數(shù).下面我們開發(fā)一個(gè)小程序,這個(gè)程序有一個(gè)參數(shù).如果這個(gè)參數(shù)是一個(gè)文件名,我們輸出這個(gè)文件的大小和最后修改的時(shí)間,如果是一個(gè)目錄
53、我們輸出這個(gè)目錄下所有文件的大小和修改時(shí)間#include<unistd.h>#include<stdio.h>#include<errno.h>#include<sys/types.h>#include<sys/stat.h>#include<dirent.h>include<time.h>staticintget_file_size_time(constchar*filename)structstatstatbuf;if(stat(filename,&statbuf)=-1)printf("
54、;Getstaton%sError:%sn",filename,strerror(errno);return(-1);if(S_ISDIR(statbuf.st_mode)return;if(S_ISREG(statbuf.st_mode)printf("%ssize:%ldbytestmodifiedat%s",filename,statbuf.st_size,ctime(&statbuf.st_mtime);return(0);intmain(intargc,char*argv)DIR*dirp;structdirent*direntp;intstat
55、s;if(argc!=2)printf("Usage:%sfilenamena",argv0);exit(1);if(stats=get_file_size_time(argv1)=0)|(stats=-1)exit(1);if(dirp=opendir(argv1)=NULL)printf("OpenDirectory%sError:%sn",argv1,strerror(errno);exit(1);while(direntp=readdir(dirp)!=NULL)if(get_file_size_time(direntp-<d_name)=
56、-1)break;closedir(dirp);exit(1);4。管道文件Linux提供了許多的過(guò)濾和重定向程序,比如morecat等等.還提供了<>|<<等等重定向操作符.在這些過(guò)濾和重定向程序當(dāng)中,都用到了管道這種特殊的文件.系統(tǒng)調(diào)用pipe可以創(chuàng)建一個(gè)管道.#include<unistd.h>intpipe(intfildes2);pipe調(diào)用可以創(chuàng)建一個(gè)管道(通信緩沖區(qū)).當(dāng)調(diào)用成功時(shí),我們可以訪問(wèn)文件描述符fildes0,fildes1.其中fildes0是用來(lái)讀的文件描述符,而fildes1是用來(lái)寫的文件描述符.在實(shí)際使用中我們是通過(guò)創(chuàng)建一個(gè)子
57、進(jìn)程,然后一個(gè)進(jìn)程寫,一個(gè)進(jìn)程讀來(lái)使用的.關(guān)于進(jìn)程通信的詳細(xì)情況請(qǐng)查看進(jìn)程通信#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<errno.h>#include<sys/types.h>#include<sys/wait.h>#defineBUFFER255intmain(intargc,char*argv)(charbufferBUFFER+1;intfd2;if(argc!=2)(fprintf(s
58、tderr,"Usage:%sstringna",argv0);exit(1);if(pipe(fd)!=0)(fprintf(stderr,"PipeError:%sna",strerror(errno);exit(1);if(fork()=0)(close(fd0);printf("Child%dWritetopipena",getpid();snprintf(buffer,BUFFER,"%s",argv1);write(fd1,buffer,strlen(buffer);printf("Child%dQuitna",getpid();exit(0);else(close(fd1);printf("Parent%dReadfrompipena",getpid();memset(buffer,''0',BUFFER+1);read(fd0,buffer,BUFFER);printf("Parent%dRead:%sn",getpid(),buffe
溫馨提示
- 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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 食葵購(gòu)銷合同
- 網(wǎng)絡(luò)游戲賬號(hào)買賣合作協(xié)議
- 體育健身行業(yè)私教課程訓(xùn)練免責(zé)協(xié)議
- 鋼結(jié)構(gòu)廠房抗震設(shè)計(jì)施工措施
- 無(wú)接觸物流合作協(xié)議書
- 《語(yǔ)文經(jīng)典詩(shī)文欣賞教學(xué)教案》
- 情感認(rèn)知視角下革命紀(jì)念館的展示設(shè)計(jì)研究-以郝家橋革命紀(jì)念館為例
- 面向金融模型的數(shù)據(jù)安全存儲(chǔ)與置亂檢索系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)
- 活性CeO2納米微粒的制備、摩擦學(xué)性能及與齒輪油典型添加劑的配伍性能研究
- 核心素養(yǎng)視域下的初中數(shù)學(xué)單元作業(yè)設(shè)計(jì)研究
- 圖書館消防安全培訓(xùn)課件
- 2024年江蘇國(guó)信集團(tuán)有限公司招聘筆試參考題庫(kù)含答案解析
- 中小型會(huì)計(jì)師事務(wù)所發(fā)展策略
- 非國(guó)有資金投資工程項(xiàng)目直接發(fā)包備案表
- 《拼多多運(yùn)營(yíng)方案》課件
- 常見腫瘤AJCC分期手冊(cè)第八版(中文版)
- 委托第三方代收款協(xié)議書x
- 數(shù)字化人才管理
- 會(huì)計(jì)學(xué)-中小企業(yè)財(cái)務(wù)報(bào)表分析-以廣州中大中鳴科技有限公司為例
- 交通運(yùn)輸安全生產(chǎn)監(jiān)管監(jiān)察信息平臺(tái)解決方案
- W公司的客戶滿意度研究論文
評(píng)論
0/150
提交評(píng)論