linux下的C語言開發

linux下的C語言開發(開篇)

? 在很多人的眼里,C語言和linux常常是分不開的。這其中的原因很多,其中最重要的一部分我認為是linux本身就是C語言的杰出作品。當然,linux操作系統本身對C語言的支持也是相當到位的。作為一個真正的程序員來說,如果沒有在linux下面用C語言編寫過完整的程序,那么只能說他對C語言本身的理解還相關膚淺,對系統本身的認識也不夠到位。作為程序員來說,linux系統為我們提供了很多理想的環境,這其中包括了下面幾個方面,
? ??
? ? (1)完善的編譯環境,包括gcc、as、ld等編譯、鏈接工具
? ? (2)強大的調試環境,主要是gdb工具
? ? (3)豐富的自動編譯工具,主要是make工具
? ? (4)多樣化的os選擇,ubuntu、redflag等等
? ? (5)浩瀚的開源代碼庫

? ? 當然,不管我怎么說,最終朋友們還是應該自己勇敢地跨出前進的第一步。如果還沒有過Linux編程經驗的朋友可以首先在自己的pc上面安裝一個虛擬機,然后就可以在shell下面編寫自己的C語言代碼了。

[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. ??
  3. int?main()??
  4. {??
  5. ????printf("hello!\n");??
  6. ????return?1;??
  7. }????
? ? 編寫完上面的代碼后,你需要做的就是兩個步驟:1、輸入 gcc hello.c -o hello;2、輸入./hello。如果一切正常的話,此時你應該會在屏幕上看到一行hello的打印。如果你看到了,那么恭喜你,你已經可以開始linux的c語言編程之旅了。

? ? 當然,我們不會滿足于這么簡單的打印功能。下面就可以編寫一個簡單的迭代函數,
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. ??
  3. int?iterate(int?value)??
  4. {??
  5. ????if(1?==?value)??
  6. ????????return?1;??
  7. ????return?iterate(value?-?1)?+?value;??
  8. }??
  9. ??
  10. int?main()??
  11. {??
  12. ????printf("%d\n",?iterate(10));??
  13. ????return?1;??????
  14. }??
? ? 此時,同樣我們需要重復上面的步驟:1、輸入gcc hello.c -o hello;2、輸入./hello。當然此時如果一切OK的話,你就會看到屏幕會有55這個數的輸出。本來1到10的數據之和就是55, 這說明我們的程序是正確的。

? ? 當然, 還會有一些朋友對程序的反匯編感興趣,那么他需要兩個步驟:1、gcc hello.c -g -o hello;2、objdump -S -d ./hello。之所以在gcc編譯的時候加上-g是為了添加調試信息,objdump中的-S選項是為了在顯示匯編代碼的時候同時顯示原來的C語言源代碼。
[cpp] view plaincopy
  1. int?iterate(int?value)??
  2. {??
  3. ?8048374:???????55??????????????????????push???%ebp??
  4. ?8048375:???????89?e5???????????????????mov????%esp,%ebp??
  5. ?8048377:???????83?ec?08????????????????sub????$0x8,%esp??
  6. ????if(1?==?value)??
  7. ?804837a:???????83?7d?08?01?????????????cmpl???$0x1,0x8(%ebp)??
  8. ?804837e:???????75?09???????????????????jne????8048389?<iterate+0x15>??
  9. ????????return?1;??
  10. ?8048380:???????c7?45?fc?01?00?00?00????movl???$0x1,0xfffffffc(%ebp)??
  11. ?8048387:???????eb?16???????????????????jmp????804839f?<iterate+0x2b>??
  12. ????return?iterate(value?-1)?+?value;??
  13. ?8048389:???????8b?45?08????????????????mov????0x8(%ebp),%eax??
  14. ?804838c:???????83?e8?01????????????????sub????$0x1,%eax??
  15. ?804838f:???????89?04?24????????????????mov????%eax,(%esp)??
  16. ?8048392:???????e8?dd?ff?ff?ff??????????call???8048374?<iterate>??
  17. ?8048397:???????8b?55?08????????????????mov????0x8(%ebp),%edx??
  18. ?804839a:???????01?c2???????????????????add????%eax,%edx??
  19. ?804839c:???????89?55?fc????????????????mov????%edx,0xfffffffc(%ebp)??
  20. ?804839f:???????8b?45?fc????????????????mov????0xfffffffc(%ebp),%eax??
  21. }??
  22. ?80483a2:???????c9??????????????????????leave??
  23. ?80483a3:???????c3??????????????????????ret??
  24. ???


linux下的C語言開發(makefile編寫)

? 對于程序設計員來說,makefile是我們繞不過去的一個坎。可能對于習慣Visual C++的用戶來說,是否會編寫makefile無所謂。畢竟工具本身已經幫我們做好了全部的編譯流程。但是在Linux上面,一切變得不一樣了,沒有人會為你做這一切。編代碼要靠你,測試要靠你,最后自動化編譯設計也要靠你自己。想想看,如果你下載了一個開源軟件,卻因為自動化編譯失敗,那將會在很大程度上打擊你學習代碼的自信心了。所以,我的理解是這樣的。我們要學會編寫makefile,至少會編寫最簡單的makefile。

? ? 首先編寫add.c文件,

[cpp] view plaincopy
  1. #include?"test.h"??
  2. #include?<stdio.h>??
  3. ??
  4. int?add(int?a,?int?b)??
  5. {??
  6. ????return?a?+?b;??
  7. }??
  8. ??
  9. int?main()??
  10. {??
  11. ????printf("?2?+?3?=?%d\n",?add(2,?3));??
  12. ????printf("?2?-?3?=?%d\n",?sub(2,?3));??
  13. ????return?1;??
  14. }??
? ? 再編寫sub.c文件,
[cpp] view plaincopy
  1. #include?"test.h"??
  2. ??
  3. int?sub(int?a,?int?b)??
  4. {??
  5. ????return?a?-?b;??
  6. }??
? ? 最后編寫test.h文件,
[cpp] view plaincopy
  1. #ifndef?_TEST_H??
  2. #define?_TEST_H??
  3. ??
  4. int?add(int?a,?int?b);??
  5. int?sub(int?a,?int?b);??
  6. #endif??
? ? 那么,就是這三個簡單的文件,應該怎么編寫makefile呢?
[cpp] view plaincopy
  1. test:?add.o?sub.o??
  2. ????gcc?-o?test?add.o?sub.o??
  3. ??
  4. add.o:?add.c?test.h??
  5. ????gcc?-c?add.c??
  6. ??
  7. sub.o:?sub.c?test.h??
  8. ????gcc?-c?sub.c??????
  9. ??????
  10. clean:??
  11. ????rm?-rf?test??
  12. ????rm?-rf?*.o?

linux下的C語言開發(gdb調試)

? 編寫代碼過程中少不了調試。在windows下面,我們有visual studio工具。在linux下面呢,實際上除了gdb工具之外,你沒有別的選擇。那么,怎么用gdb進行調試呢?我們可以一步一步來試試看。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. ??
  3. int?iterate(int?value)??
  4. {??
  5. ????if(1?==?value)??
  6. ????????return?1;??
  7. ??
  8. ????return?iterate(value?-?1)?+?value;??
  9. }??
  10. ??
  11. int?main()??
  12. {??
  13. ????printf("%d\n",?iterate(10));??
  14. ????return?1;??
  15. }??
? ? 既然需要調試,那么生成的可執行文件就需要包含調試的信息,這里應該怎么做呢?很簡單,輸入 gcc test.c -g -o test。輸入命令之后,如果沒有編譯和鏈接方面的錯誤,你就可以看到 可執行文件test了。

? ? 調試的步驟基本如下所示,


(01) 首先,輸入gdb test
(02) 進入到gdb的調試界面之后,輸入list,即可看到test.c源文件
(03) 設置斷點,輸入 b main?
(04) 啟動test程序,輸入run?
(05) 程序在main開始的地方設置了斷點,所以程序在printf處斷住
(06) 這時候,可以單步跟蹤。s單步可以進入到函數,而n單步則越過函數
(07) 如果希望從斷點處繼續運行程序,輸入c
(08) 希望程序運行到函數結束,輸入finish
(09) 查看斷點信息,輸入 info break
(10) 如果希望查看堆棧信息,輸入bt
(11) 希望查看內存,輸入 x/64xh + 內存地址
(12) 刪除斷點,則輸入delete break + 斷點序號
(13) 希望查看函數局部變量的數值,可以輸入print + 變量名

(14)希望修改內存值,直接輸入 print? + *地址 = 數值
(15) 希望實時打印變量的數值,可以輸入display + 變量名
(16) 查看函數的匯編代碼,輸入 disassemble + 函數名
(17) 退出調試輸入quit即可

linux下的C語言開發(AT&T 匯編語言)

? 同樣是x86的cpu,但是卻可以用不同形式的匯編語言來表示。在window上面我們使用的更多是intel格式的匯編語言,而在Linux系統上面使用的更多的常常是AT&T格式的匯編語言。那什么是AT&T格式的匯編代碼呢?我們可以寫一個試試看。
[cpp] view plaincopy
  1. .data??
  2. ????message:?.string?"hello!\n"??
  3. ????length?=?.?-?message??
  4. ??
  5. .text??
  6. .global?_start??
  7. ??
  8. _start:??
  9. ????movl?$length,?%edx??
  10. ????movl?$message,?%ecx??
  11. ????movl?$1,?%ebx??
  12. ????movl?$4,?%eax??
  13. ????int?$0x80??
  14. ??
  15. ????movl?$0,?%ebx??
  16. ????movl?$1,?%eax??
  17. ????int?$0x80??
? ? 這是一個簡單的匯編文件,我們可以分兩步進行編譯。首先,輸入 as -gstabs -o hello.o hello.s, 接著輸入ld -o hello?hello.o即可。為了驗證執行文件是否正確,可以輸入./hello驗證一下。

? ? 在as命令當中,由于我們使用了-gstabs選項,因此在hello執行文件中是包含調試信息的。所以,如果想單步調試的朋友可以輸入gdb hello進行調試。

? ? 那么,hello執行文件反匯編的代碼又是什么樣的呢?我們可以輸入objdump -S -d hello查看一下。

[cpp] view plaincopy
  1. 08048074?<_start>:??
  2. .text??
  3. .global?_start??
  4. ??
  5. _start:??
  6. ????????movl?$length,?%edx??
  7. ?8048074:???????ba?08?00?00?00??????????mov????$0x8,%edx??
  8. ????????movl?$message,?%ecx??
  9. ?8048079:???????b9?9c?90?04?08??????????mov????$0x804909c,%ecx??
  10. ????????movl?$1,?%ebx??
  11. ?804807e:???????bb?01?00?00?00??????????mov????$0x1,%ebx??
  12. ????????movl?$4,?%eax??
  13. ?8048083:???????b8?04?00?00?00??????????mov????$0x4,%eax??
  14. ????????int?$0x80??
  15. ?8048088:???????cd?80???????????????????int????$0x80??
  16. ??
  17. ????????movl?$0,?%ebx??
  18. ?804808a:???????bb?00?00?00?00??????????mov????$0x0,%ebx??
  19. ????????movl?$1,?%eax??
  20. ?804808f:???????b8?01?00?00?00??????????mov????$0x1,%eax??
  21. ????????int?$0x80??
  22. ?8048094:???????cd?80???????????????????int????$0x80??
  23. ????????ret??
  24. ?8048096:???????c3??????????????????????ret??
  25. ??????

linux下的C語言開發(靜態庫)

在我們編寫軟件的過程當中,少不了需要使用別人的庫函數。因為大家知道,軟件是一個協作的工程。作為個人來講,你不可能一個人完成所有的工作。另外,網絡上一些優秀的開源庫已經被業內廣泛接受,我們也沒有必要把時間浪費在這些重復的工作上面。

? ? 既然說到了庫函數,那么一般來說庫函數分為兩種方式:靜態庫和動態庫。兩者的區別其實很小,靜態庫是必須要鏈接到執行文件中去的,而動態庫是不需要鏈接到最后的執行文件中的。怎么理解呢?也就是說,對于最后的執行文件而言,你是否刪除靜態庫無所謂。但是,一旦你刪除了動態庫,最后的執行文件就玩不轉了。

? ? 今天我們討論的問題是靜態庫。為了顯示windows和linux創建靜態庫之間的差別,我們首先在windows上面利用Visual C++6.0創建一個靜態庫。源文件的代碼很簡單,

[cpp] view plaincopy
  1. #include?"test.h"??
  2. ??
  3. int?add(int?a,?int?b)??
  4. {??
  5. ????return?a?+?b;??
  6. }??
? ? 頭文件代碼也不難,
[cpp] view plaincopy
  1. #ifndef?_TEST_H??
  2. #define?_TEST_H??
  3. ??
  4. int?add(int?a,?int?b);??
  5. #endif??

? ? 如果你需要在windows上面創建一個靜態庫,那么你需要進行下面的操作,

(1)打開visual C++ 6.0工具,單擊【File】-> 【New】->【Projects】
(2)選擇【Win32 Static Library】,同時在【Project Name】寫上項目名稱,在【Location】選擇項目保存地址
(3)單擊【Ok】,繼續單擊【Finish】,再單擊【Ok】,這樣一個靜態庫工程就創建好了
(4)重新單擊【File】->【New】->【Files】,選擇【C++ Source Files】,
(5)選中【Add to pproject】,將源文件加入到剛才創建的工程中去,在File中輸入文件名+.c后綴
(6)重復4、5的操作,加入一個文件名+.h頭文件
(7)分別在頭文件和源文件中輸入上面的代碼,單擊F7按鈕,即可在Debug目錄中生成*.lib靜態庫文件

? ? 那么,在linux下面應該怎么運行呢?其實很簡單,兩條命令解決,
(1)首先生成*.o文件,輸入gcc -c test.c -o test.o
(2)利用ar命令生成靜態庫,輸入ar rc libtest.a test.o

? ? 此時如果還有一個hello.c文件使用到了這個靜態庫,比如說 ,
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?"test.h"??
  3. ??
  4. int?main()??
  5. {??
  6. ????printf("%d\n",?add(2,?3));??
  7. ????return?1;??
  8. }??

? ? 其實也很簡單,輸入一個簡單的命令就可以生成執行文件了,
(1)首先輸入gcc hello.c -o hello ./libtest.a

(2)輸入./hello,驗證生成的執行文件是否正確

(3)朋友們可以刪除libtest.a文件,重新輸入./hello,驗證執行文件是否可以正常運行

linux下的C語言開發(動態庫)

動態鏈接庫不是linux獨有的特性,在windows下面也存在這樣的特性。一般來說,windows下面的動態連接庫是以*.dll作為結尾的,而linux下面的動態連接庫是以*.so結尾的。和靜態鏈接庫相比,動態連接庫可以共享內存資源,這樣可以減少內存消耗。另外,動態連接是需要經過操作系統加載器的幫助才能被普通執行文件發現的,所以動態連接庫可以減少鏈接的次數。有了這個特點,我們就不難發現為什么很多軟件的補丁其實都是以動態庫發布的。

? ? 那么,在Linux上動態庫是怎么生成的呢?

[cpp] view plaincopy
  1. #include?"test.h"??
  2. ??
  3. int?add(int?a,?int?b)??
  4. {??
  5. ????return?a?+?b;??
  6. }??
? ? 頭文件格式,
[cpp] view plaincopy
  1. #ifndef??_TEST_H??
  2. #define??_TEST_H??
  3. ??
  4. int?add(int?a,?int?b);??
  5. #endif??
? ? 此時如果我們想要生成動態庫,要做的工作其實非常簡單,輸入gcc -shared -fPIC -o libtest.so test.c即可。回車后輸入ls,我們就可以發現當前目錄下面出現了libtest.so文件。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?"test.h"??
  3. ??
  4. int?main()??
  5. {??
  6. ????printf("%d\n",?add(2,?3));??
  7. ????return?1;??
  8. }??
? ? 在上面的代碼當中,我們發現使用到了add函數,那么此時如何才能生成一個執行文件呢?也很簡單,輸入gcc hello.c -o ?hello?./libtest.so。然后輸入./hello,此時可以驗證一下執行文件運行是否正確。在編寫靜態庫的時候,我說過靜態庫是匯編鏈接到執行文件當中的,而動態庫不會。朋友們可以做個小實驗,刪除libtest.so,然后輸入./hello。此時大家可以看看系統有沒有錯誤返回?
? ? 這個時候,有的朋友就會問了,那在windows下面dll應該怎么編寫呢?其實也不難,只要在test.h上面稍作改變即可。其他的步驟和靜態庫的操作是基本類似的。
[cpp] view plaincopy
  1. #ifndef??_TEST_H??
  2. #define?_TEST_H??
  3. ??
  4. #ifdef?USR_DLL??
  5. #define?DLL_API?_declspec(dllexport)??
  6. #else??
  7. #define?DLL_API?_declspec(dllimport)??
  8. #endif??
  9. ??
  10. DLL_API?int?add(int?a,?int?b);??
  11. ??
  12. #endif?

linux下的C語言開發(定時器)

定時器是我們需要經常處理的一種資源。那linux下面的定時器又是怎么一回事呢?其實,在linux里面有一種進程中信息傳遞的方法,那就是信號。這里的定時器就相當于系統每隔一段時間給進程發一個定時信號,我們所要做的就是定義一個信號處理函數。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?<time.h>??
  3. #include?<sys/time.h>??
  4. #include?<stdlib.h>??
  5. #include?<signal.h>??
  6. ??
  7. static?int?count?=?0;??
  8. static?struct?itimerval?oldtv;??
  9. ??
  10. void?set_timer()??
  11. {??
  12. ????struct?itimerval?itv;??
  13. ????itv.it_interval.tv_sec?=?1;??
  14. ????itv.it_interval.tv_usec?=?0;??
  15. ????itv.it_value.tv_sec?=?1;??
  16. ????itv.it_value.tv_usec?=?0;??
  17. ????setitimer(ITIMER_REAL,?&itv,?&oldtv);??
  18. }??
  19. ??
  20. void?signal_handler(int?m)??
  21. {??
  22. ????count?++;??
  23. ????printf("%d\n",?count);??
  24. }??
  25. ??
  26. int?main()??
  27. {??
  28. ????signal(SIGALRM,?signal_handler);??
  29. ????set_timer();??
  30. ????while(count?<?10000);??
  31. ????exit(0);??
  32. ????return?1;??
  33. }?

linux下的C語言開發(自動編譯工具)

? 在Linux下面,編寫makefile是一件辛苦的事情。因此,為了減輕程序員編寫makefile的負擔,人們發明了autoconf和automake這兩個工具,可以很好地幫我們解決這個問題。
? ? 我們可以通過一個簡單的示例來說明如何使用配置工具。

(1)首先,編寫源文件hello.c。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. ??
  3. int?main(int?argc,?char**?argv[])??
  4. {??
  5. ????printf("hello,?world!\n");??
  6. ????return?1;??
  7. }??
(2)接下來,我們需要創建一個Makefile.am,同時編寫上腳本。
[cpp] view plaincopy
  1. SUBDIRS=??
  2. ??
  3. bin_PROGRAMS=hello??
  4. hello_SOURCES=hello.c????

(3)直接輸入autoscan,生成文件configure.scan,再改名為configure.in。

修改腳本AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
為AC_INIT(hello, 1.0, feixiaoxing@163.com)

同時,在AC_CONFIG_HEADER([config.h])后面添加
AM_INIT_AUTOMAKE(hello, 0.1)

(4)依次輸入aclocal命令、autoheader命令

(5)創建4個文件,分別為README、NEWS、AUTHORS和ChangeLog

(6)依次輸入automake -a、autoconf命令

(7)輸入./configure,生成最終的Makefile

(8)如果需要編譯,輸入make;如果需要安裝, 輸入make install;如果需要發布軟件包,輸入make dist

linux下的C語言開發(進程創建)

? 在Linux下面,創建進程是一件十分有意思的事情。我們都知道,進程是操作系統下面享有資源的基本單位。那么,在Linux下面應該怎么創建進程呢?其實非常簡單,一個fork函數就可以搞定了。但是,我們需要清楚的是子進程與父進程之間除了代碼是共享的之外,堆棧數據和全局數據均是獨立的。
[cpp] view plaincopy
  1. #include?<unistd.h>??
  2. #include?<stdio.h>??
  3. #include?<stdlib.h>??
  4. #include?<math.h>??
  5. #include?<errno.h>??
  6. #include?<sys/types.h>??
  7. #include?<sys/wait.h>??
  8. ??
  9. int?main()??
  10. {??
  11. ????pid_t?pid;??
  12. ??
  13. ????if(-1?==?(pid?=?fork()))??
  14. ????{??
  15. ????????printf("Error?happened?in?fork?function!\n");??
  16. ????????return?0;??
  17. ????}??
  18. ??
  19. ????if(0?==?pid)??
  20. ????{??
  21. ????????printf("This?is?child?process:?%d\n",?getpid());??
  22. ????}??
  23. ????else??
  24. ????{??
  25. ????????printf("This?is?parent?process:?%d\n",?getpid());??
  26. ????}??
  27. ??
  28. ????return?0;??
  29. }??
  30. ????

linux下的C語言開發(進程等待)

所謂進程等待,其實很簡單。前面我們說過可以用fork創建子進程,那么這里我們就可以使用wait函數讓父進程等待子進程運行結束后才開始運行。注意,為了證明父進程確實是等待子進程運行結束后才繼續運行的,我們使用了sleep函數。但是,在linux下面,sleep函數的參數是秒,而windows下面sleep的函數參數是毫秒。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?<stdlib.h>??
  3. #include?<unistd.h>??
  4. ??
  5. int?main(int?argc,?char*?argv[])??
  6. {??
  7. ????pid_t?pid;??
  8. ??
  9. ????pid?=?fork();??
  10. ????if(0?==?pid)??
  11. ????{??
  12. ????????printf("This?is?child?process,?%d\n",?getpid());??
  13. ????????sleep(5);??
  14. ????}??
  15. ????else??
  16. ????{??
  17. ????????wait(NULL);??
  18. ????????printf("This?is?parent?process,?%d\n",?getpid());??
  19. ????}??
  20. ??
  21. ????return?1;??
  22. }??
? ? 下面,我們需要做的就是兩步,首先輸入gcc fork.c -o fork, 然后輸入./fork,就會在console下面獲得這樣的結果。
[cpp] view plaincopy
  1. [root@localhost?fork]#?./fork??
  2. This?is?child?process,?2135??
  3. This?is?parent?process,?2134?

linux下的C語言開發(信號處理)

? 信號處理是linux程序的一個特色。用信號處理來模擬操作系統的中斷功能,對于我們這些系統程序員來說是最好的一個選擇了。要想使用信號處理功能,你要做的就是填寫一個信號處理函數即可。一旦進程有待處理的信號處理,那么進程就會立即進行處理。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?<stdlib.h>??
  3. #include?<signal.h>??
  4. ??
  5. int?value?=?0;??
  6. ??
  7. void?func(int?sig)??
  8. {??
  9. ????printf("I?get?a?signal!\n");??
  10. ????value?=?1;??
  11. }??
  12. ??
  13. int?main()??
  14. {??
  15. ????signal(SIGINT,?func);??
  16. ??
  17. ????while(0?==?value)??
  18. ????????sleep(1);??
  19. ??
  20. ????return?0;??
  21. }??

? ? 為了顯示linux對signal的處理流程,我們需要進行兩個步驟。第一,輸入gcc sig.c -o sig, 然后輸入./sig即可;第二則重啟一個console窗口,輸入ps -aux | grep sig, 在獲取sig的pid之后然后輸入kill -INT 2082, 我們即可得到如下的輸出。

[cpp] view plaincopy
  1. [root@localhost?fork]#./sig??
  2. I?get?a?signal!??
  3. [root@localhost?fork]#?

linux下的C語言開發(管道通信)

? Linux系統本身為進程間通信提供了很多的方式,比如說管道、共享內存、socket通信等。管道的使用十分簡單,在創建了匿名管道之后,我們只需要從一個管道發送數據,再從另外一個管道接受數據即可。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?<unistd.h>??
  3. #include?<stdlib.h>??
  4. #include?<string.h>??
  5. ??
  6. int?pipe_default[2];????
  7. ??
  8. int?main()??
  9. {??
  10. ????pid_t?pid;??
  11. ????char?buffer[32];??
  12. ??
  13. ????memset(buffer,?0,?32);??
  14. ????if(pipe(pipe_default)?<?0)??
  15. ????{??
  16. ????????printf("Failed?to?create?pipe!\n");??
  17. ????????return?0;??
  18. ????}??
  19. ??
  20. ????if(0?==?(pid?=?fork()))??
  21. ????{??
  22. ????????close(pipe_default[1]);??
  23. ????????sleep(5);??
  24. ????????if(read(pipe_default[0],?buffer,?32)?>?0)??
  25. ????????{??
  26. ????????????printf("Receive?data?from?server,?%s!\n",?buffer);??
  27. ????????}??
  28. ????????close(pipe_default[0]);??
  29. ????}??
  30. ????else??
  31. ????{??
  32. ????????close(pipe_default[0]);??
  33. ????????if(-1?!=?write(pipe_default[1],?"hello",?strlen("hello")))??
  34. ????????{??
  35. ????????????printf("Send?data?to?client,?hello!\n");??
  36. ????????}??
  37. ????????close(pipe_default[1]);??
  38. ????????waitpid(pid,?NULL,?0);??
  39. ????}??
  40. ??
  41. ????return?1;??
  42. }??
? ? 下面我們就可以開始編譯運行了,老規矩分成兩步驟進行:(1)輸入gcc pipe.c -o pipe;(2)然后輸入./pipe,過一會兒你就可以看到下面的打印了。
[cpp] view plaincopy
  1. [test@localhost?pipe]$?./pipe??
  2. Send?data?to?client,?hello!??
  3. Receive?data?from?server,?hello!?

linux下的C語言開發(多線程編程)

? 多線程和多進程還是有很多區別的。其中之一就是,多進程是linux內核本身所支持的,而多線程則需要相應的動態庫進行支持。對于進程而言,數據之間都是相互隔離的,而多線程則不同,不同的線程除了堆棧空間之外所有的數據都是共享的。說了這么多,我們還是自己編寫一個多線程程序看看結果究竟是怎么樣的。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?<pthread.h>??
  3. #include?<unistd.h>??
  4. #include?<stdlib.h>??
  5. ??
  6. void?func_1(void*?args)??
  7. {??
  8. ????while(1){??
  9. ????????sleep(1);??
  10. ????????printf("this?is?func_1!\n");??
  11. ????}??
  12. }??
  13. ??
  14. void?func_2(void*?args)??
  15. {??
  16. ????while(1){??
  17. ????????sleep(2);??
  18. ????????printf("this?is?func_2!\n");??
  19. ????}??
  20. }??
  21. ??
  22. int?main()??
  23. {??
  24. ????pthread_t?pid1,?pid2;??
  25. ??
  26. ????if(pthread_create(&pid1,?NULL,?func_1,?NULL))??
  27. ????{??
  28. ????????return?-1;??
  29. ????}??
  30. ??
  31. ????if(pthread_create(&pid2,?NULL,?func_2,?NULL))??
  32. ????{??
  33. ????????return?-1;??
  34. ????}??
  35. ??
  36. ????while(1){??
  37. ????????sleep(3);??
  38. ????}??
  39. ??
  40. ????return?0;??
  41. }??

? ? 和我們以前編寫的程序有所不同,多線程代碼需要這樣編譯,輸入gcc thread.c -o thread -lpthread,編譯之后你就可以看到thread可執行文件,輸入./thread即可。

[cpp] view plaincopy
  1. [test@localhost?Desktop]$?./thread??
  2. this?is?func_1!??
  3. this?is?func_2!??
  4. this?is?func_1!??
  5. this?is?func_1!??
  6. this?is?func_2!??
  7. this?is?func_1!??
  8. this?is?func_1!??
  9. this?is?func_2!??
  10. this?is?func_1!??
  11. this?is?func_1!?

linux下的C語言開發(線程等待)

和多進程一樣,多線程也有自己的等待函數。這個等待函數就是pthread_join函數。那么這個函數有什么用呢?我們其實可以用它來等待線程運行結束。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?<pthread.h>??
  3. #include?<unistd.h>??
  4. #include?<stdlib.h>??
  5. ??
  6. void?func(void*?args)??
  7. {??
  8. ????sleep(2);??
  9. ????printf("this?is?func!\n");??
  10. }??
  11. ??
  12. int?main()??
  13. {??
  14. ????pthread_t?pid;??
  15. ??
  16. ????if(pthread_create(&pid,?NULL,?func,?NULL))??
  17. ????{??
  18. ????????return?-1;??
  19. ????}??
  20. ??
  21. ????pthread_join(pid,?NULL);??
  22. ????printf("this?is?end?of?main!\n");??
  23. ??
  24. ????return?0;??
  25. }??

? ? 編寫wait.c文件結束之后,我們就可以開始編譯了。首先你需要輸入gcc wait.c -o wait -lpthread,編譯之后你就可以看到wait可執行文件,輸入./wait即可。

[cpp] view plaincopy
  1. [test@localhost?thread]$?./thread??
  2. this?is?func!??
  3. this?is?end?of?main!?

linux下的C語言開發(線程互斥)

對于編寫多線程的朋友來說,線程互斥是少不了的。在linux下面,編寫多線程常用的工具其實是pthread_mutex_t。本質上來說,它和Windows下面的mutex其實是一樣的,差別幾乎是沒有。希望對線程互斥進行詳細了解的朋友可以看這里。
[cpp] view plaincopy
  1. #include?<stdio.h>??
  2. #include?<pthread.h>??
  3. #include?<unistd.h>??
  4. #include?<stdlib.h>??
  5. ??
  6. static?int?value?=?0;??
  7. pthread_mutex_t?mutex;??
  8. ??
  9. void?func(void*?args)??
  10. {??
  11. ????while(1)??
  12. ????{??
  13. ????????pthread_mutex_lock(&mutex);??
  14. ????????sleep(1);??
  15. ????????value?++;??
  16. ????????printf("value?=?%d!\n",?value);??
  17. ????????pthread_mutex_unlock(&mutex);??
  18. ????}??
  19. }??
  20. ??
  21. int?main()??
  22. {??
  23. ????pthread_t?pid1,?pid2;??
  24. ????pthread_mutex_init(&mutex,?NULL);??
  25. ??
  26. ????if(pthread_create(&pid1,?NULL,?func,?NULL))??
  27. ????{??
  28. ????????return?-1;??
  29. ????}??
  30. ??
  31. ????if(pthread_create(&pid2,?NULL,?func,?NULL))??
  32. ????{??
  33. ????????return?-1;??
  34. ????}??
  35. ??
  36. ????while(1)??
  37. ????????sleep(0);??
  38. ??
  39. ????return?0;??
  40. }??
? ? 編寫mutex.c文件結束之后,我們就可以開始編譯了。首先你需要輸入gcc mutex.c -o mutex -lpthread,編譯之后你就可以看到mutex可執行文件,輸入./mutex即可。
[cpp] view plaincopy
  1. [test@localhost?thread]$?./mutex??
  2. value?=?1!??
  3. value?=?2!??
  4. value?=?3!??
  5. value?=?4!??
  6. value?=?5!??
  7. value?=?6!?

linux下的C語言開發(網絡編程)

不管在Windows平臺下面還是在Linux平臺下面,網絡編程都是少不了的。在互聯網發達的今天,我們的生活基本上已經離不開網絡了。我們可以用網絡干很多的事情,比如說IM聊天、FTP下載、電子銀行、網絡購物、在線游戲、電子郵件的收發等等。所以說,對于一個軟件的開發者來說,如果說他不會進行網絡程序的開發,那真是難以想象的。


? ? 在開始介紹網絡編程的方法之前,我們可以回憶一下計算機網絡的相關知識。目前為止,我們使用的最多網絡協議還是tcp/ip網絡。通常來說,我們習慣上稱為tcp/ip協議棧。至于協議棧分成幾層,有兩種說法。一種是五層,一種是七層,我個人本身也比較傾向于五層的劃分方法。大家可以通過下面的圖看看協議棧是怎么劃分的。


? ? 5、應用層
? ? 4、傳輸層
? ? 3、網絡層
? ? 2、數據鏈路層
? ? 1、物理層


? ? 網絡的不同層次實現網絡的不同功能。物理層主要實現報文的成幀處理;數據鏈路層完成對報文的優先級的管理,同時實現二層轉發和流量控制;網絡層實現路由和轉發的功能,一方面它需要實現對報文的fragment處理,另外一方面它還需要對路由信息進行處理和保存;傳輸層實現報文的發送和接受,它利用計數、時序、定時器、重發等機制實現對報文的準確發送,當然這都是tcp的發送機制,而udp一般是不保證報文正確發送和接收的;應用層就是根據傳輸層的端口信息調用不同的程序來處理傳輸的內容,端口8080是http報文,端口21是ftp報文等等。上面的邏輯稍顯復雜,朋友們可以這么理解,

? ? 物理層關心的是如何把電氣信號變成一段報文;數據鏈路層關心的是mac地址、vlan、優先級等;網絡層關心的是ip地址,下一跳ip;傳輸層關心的是端口資源;應用層關心的是報文組裝、解析、渲染、存儲、執行等等。

? ? 目前關于tcp/ip完整協議棧的代碼很多,其中我認為寫得比較好的還是linux內核/net/ipv4下面的代碼。如果朋友們對ipv6的代碼感興趣,也可以看看/net/ipv6的代碼。檔案如果朋友們對整個協議棧的代碼結構理解得不是很清楚,可以參考《linux網絡分析與開發》這本書。

? ? 當然,作為應用層,我們的其實考慮的不用這么復雜。對于網絡程序編寫人員來講,所有網絡的資源只要和一個socket關聯在一起就可以了。當然在socket可用之前,我們需要為它配置端口信息和ip地址。配置完了之后,我們就可以慢慢等待報文的收發了。所以一般來說,作為服務器端口的處理流程是這樣的,

? ? a) 創建socket
? ? b) 綁定socket到特定的ip地址
? ? c) 對socket進行偵聽處理
? ? d) 接受socket,表明有客戶端和服務器連接
? ? e) 和客戶端循環收發報文
? ? f) 關閉socket


? ? 作為服務器程序而言,它要對特定的端口進行綁定和偵聽處理,這樣稍顯復雜。但是如果是編寫客戶端的程序,一切的一切就變得非常簡單了,

? ? a) 創建socket
? ? b) 鏈接服務器端地址
? ? c) 和服務器端的socket收發報文


? ? 上面只是對網絡編程做了一個基本的介紹,但是好多的東西還是沒有涉及到,比如說:(1) 什么時候該使用udp,什么時候該使用tcp?(2) 如何把多線程和網絡編程聯系在一起? (3) 如何把多進程和網絡編程聯系在一起? (4) 如何利用select函數、epoll_create機制、非阻塞函數提高socket的并發處理效率? (5) linux內核是怎么實現tcp/ip協議的? (6) 我們自己是否也可以實現協議的處理流程等等?

? ? 關于這些內容,我們會重新開辟一個主題,逐步進行分析和仿真處理。敬請期待。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449819.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449819.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449819.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sql語法學習

本人數據庫目前使用的是sql&#xff0c;主要是使用python語言&#xff0c;然后用pandas調用&#xff08;真的很方便&#xff09;。所以就總結一下&#xff0c;也為自己以后調用數據查找方便使用。 導入包 from sqlalchemy import create_engine import pymssql連接數據庫 con…

C 溫故知新 之 指針:數組指針、字符串指針、函數指針

一、數組指針 1.指向數組元素的指針 1、定義&#xff1a;還是那句話通俗的說指針就是地址   數組指針 &#xff1a;數組的起始地址 數組元素指針&#xff1a;數組元素的地址 2、定義一個指向數組元素的指針變量的方法&#xff0c;與之前介紹的指針變量相同。 例如&#…

mysql 查找配置文件 my.ini 位置方法

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 個人備注&#xff1a;不顯示文件類型時&#xff0c;my.ini 文件名就叫作 my&#xff0c; 文件屬性才顯示 ini。 找到 my 文件看屬性就知…

嵌入式操作系統內核原理和開發

嵌入式操作系統內核原理和開發&#xff08;開篇&#xff09; 操作系統是很多人每天必須打交道的東西&#xff0c;因為在你打開電腦的一剎那&#xff0c;隨著bios自檢結束&#xff0c;你的windows系統已經開始運行了。如果問大家操作系統是什么&#xff1f;可能有的人會說操作…

Java中對象比較

在Java之中不僅僅存在兩個數字與兩個字符串之間的比較&#xff0c;還存在兩個對象之間的比較。 眾所周知&#xff0c;兩個數字之間的比較我們使用“”&#xff0c;兩個字符串之間的比較我們使用“equals()”&#xff0c;那么兩個對象之間如何進行比較呢&#xff1f;既然要進行兩…

如何安裝pfbprophet

最近facebook出來了一個軟件包&#xff0c;可以用于時序數據預測&#xff0c;但是安裝上&#xff0c;遇到問題不小&#xff0c;本人也在安裝中遇到大大小小各種問題&#xff0c;然后查了各種資料&#xff0c;進行研究&#xff0c;終于找到一個最簡單的辦法。 不廢話&#xff0…

JeeSite 4.0 (1.0)開發環境部署運行

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 環境要求 1、Java SDK 1.8 下載 2、Eclipse IDE for Java EE Mars 2 (4.5.2) 下載&#xff08;依Eclipse舉例&#xff0c;IDEA雷同。&…

dojo 七 DOM dojo/dom

官方教程&#xff1a;Dojo DOM Functions對dom的使用&#xff0c;需要引用包dojo/dom。1.獲取節點&#xff0c;dom.byIdbyId中既可以傳遞一個字符串&#xff0c;也可以傳遞一個節點對象 require(["dojo/dom", "dojo/domReady!"], function(dom) {function …

quantaxis中使用docker安裝,出現的問題

本人在使用docker安裝quantaxis時&#xff0c;經常發生docker報錯&#xff0c;原因是與 wsl2沖突。之前不知道原因&#xff0c;直接就是卸載重裝&#xff0c;累死我了。現在知道后&#xff0c;將解決方案記下&#xff0c;幫助后來者繼續前行。 管理員打開cmd&#xff0c;輸入 …

并發編程(多進程1)

一 multiprocessing模塊介紹 python中的多線程無法利用多核優勢&#xff0c;如果想要充分地使用多核CPU的資源&#xff08;os.cpu_count()查看&#xff09;&#xff0c;在python中大部分情況需要使用多進程。Python提供了multiprocessing。 multiprocessing模塊用來開啟子進…

LInux 下文件包的使用

1 .deb   http://wiki.ubuntu.org.cn/MySQL%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97 2 .rpm

@RequiresPermissions 注解說明

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 RequiresAuthentication 驗證用戶是否登錄&#xff0c;等同于方法subject.isAuthenticated() 結果為true時。 RequiresUser 驗證用戶…

千位分隔符轉換為數字

最近下載了akshare里面的數據&#xff0c;然后發現有些數據格式為1,300這種格式&#xff0c;為str格式&#xff0c;但是又無法直接強制轉換之類方式&#xff0c;特地尋求答案&#xff0c;并做筆記&#xff0c;留待自己與后來者一起避坑。 from locale import * atof(123,456)…

一本通1629聰明的燕姿

1629&#xff1a;聰明的燕姿 時間限制: 1000 ms 內存限制: 524288 KB【題目描述】 城市中人們總是拿著號碼牌&#xff0c;不停尋找&#xff0c;不斷匹配&#xff0c;可是誰也不知道自己等的那個人是誰。 可是燕姿不一樣&#xff0c;燕姿知道自己等的人是誰&#xff0c;…

IT職場人生系列之二十四:程序員如何增加收入

這是IT職場人生系列的第二十四篇。&#xff08;序言&#xff0c;專欄目錄&#xff09; 程序員的收入是廣受關注的問題&#xff0c;很多人從業3&#xff5e;5年之后就會遇到這個收入瓶頸。盡管物價不斷上漲&#xff0c;程序員尤其是初、中級程序員的收入不升反降。即使上次在某…

ASP 代碼當前記錄集不支持更新問題的解決辦法。

錯誤類型&#xff1a;ADODB.Recordset (0x800A0CB3)當前記錄集不支持更新。這可能是提供程序的限制&#xff0c;也可能是選定鎖定類型的限制。 /Model/manage/Admin_Admin.asp, 第 35 行 找到放在數據庫文件的--- 右鍵--》屬性---》安全----》添加IIS來賓用戶---》權限為&#…

@PathVariable 注解 說明

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 PathVariable 映射 URL 綁定的占位符 帶占位符的 URL 是 Spring3.0 新增的功能&#xff0c;該功能在SpringMVC 向 REST 目標挺進發展過…

數據清洗,篩選

本人在私募&#xff0c;負責數據收集以及清洗&#xff0c;就是包括收集數據&#xff0c;按照領導要求&#xff0c;選出滿足條件的數據&#xff0c;用于校驗策略是否正確。 現在就在這進行代碼上傳&#xff0c;即用于自己總結整理&#xff0c;也用于供大家學習了解&#xff0c;實…

JS媒體查詢

樣式的改變使用C3的媒體查詢 行為和功能的改變使用JS的媒體查詢 matchMedia()方法參數可寫任何一個CSSmedia規則&#xff0c;返回的是新的MediaQueryList對象&#xff0c;該對象有兩個屬性 media&#xff1a;查詢語句的內容matches&#xff1a;檢查查詢結果&#xff0c;返回boo…

Ruby初步介紹

Ruby是腳本語言,與傳統的C, Java不同的是,它不需要經過編譯,而是直接可以被執行 Ubuntu下執行第一個ruby腳本 print("Hello David, This is your first Ruby script.\n") davidubuntu:~/RubyTrain/Basic$ ruby Hello.rb 運行結果: Hello David, This is your first R…