zzfrom水木-Linux环境学习和开发心得(作者:lunker)
轉(zhuǎn)自水木lunker,非常好的文章,在此鳴謝之。
?
本人水平有限,如果有錯(cuò)誤和遺漏,或者有更好的建議,請(qǐng)大家認(rèn)真的拍。
強(qiáng)烈建議: 文中涉及的圖書最好入手一個(gè)英文版的,如果實(shí)在閱讀有困難,可以在電腦中準(zhǔn)備一個(gè)中文版的進(jìn)行參考,但要強(qiáng)迫自己循序漸進(jìn)的脫離使用中文版。
1. 書目
注:文中對(duì)所有書籍的引用都會(huì)使用開頭的編號(hào), 或者簡(jiǎn)稱。
<1> "The C Programming Language", 2nd edition, by Brian Kernighan & Dennis Ritchie
-- C語(yǔ)言最經(jīng)典的教材,閱讀前最好有一點(diǎn)編程的基礎(chǔ)。本書簡(jiǎn)稱K&R。
<2> "Computer Systems: A Programmer's Perspective", 2nd edition, by David R. O'Hallaron
-- 以匯編和C程序作為例子,從程序員而不是設(shè)計(jì)者的角度,講解計(jì)算機(jī)系統(tǒng)軟硬件體系結(jié)構(gòu)的書。很有想法的書。
<3> "Advanced Programming in the UNIX environment", 2nd edition, by W. Richard Stevens and Stephen A. Rago
-- Unix/Linux 環(huán)境編程的最好教材,把操作系統(tǒng)的原理,unix的接口和設(shè)計(jì)思路,以及C程序?qū)嵗@三者很好的結(jié)合在了一起,不可多得的好書。本書簡(jiǎn)稱 APUE2
<4> "Linux Kernel Development", 3rd edition, by robert love
-- Linux kernel 入門的書籍,深入淺出,很適合新人入門。簡(jiǎn)稱 LKD3
<5> "Linux Device Drivers", 3rd Edition, by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman
-- 教給你寫linux驅(qū)動(dòng)的書,有實(shí)例,有框架,有細(xì)節(jié),把和驅(qū)動(dòng)沾邊的知識(shí)都講得很細(xì)致。簡(jiǎn)稱LDDR3。 下載: http://lwn.net/Kernel/LDD3/
<6> "Understanding the Linux Kernel", 3rd edition, by Marco Cesati Ph.D.
-- 講解linux kernel的實(shí)現(xiàn),包括設(shè)計(jì)思路,調(diào)用關(guān)系圖,數(shù)據(jù)結(jié)構(gòu),算法,以及一些kernel編程技巧。簡(jiǎn)稱 ULK3。
<7> "TCP/IP Illustrated, Vol. 1,2,3", by W. Richard Stevens
-- 講解TCP/IP協(xié)議的經(jīng)典書,第一卷介紹協(xié)議,必讀,有大量的tcpdump實(shí)例,跟著操作和分析很有樂趣。第二卷介紹BSD上面的實(shí)現(xiàn),第三卷介紹了HTTP等其他的協(xié)議。
<8> "Unix Network Programming, Vol. 1,2", 3rd edition, by W. Richard Stevens, Bill Fenner, Andrew M. Rudoff
-- 第一卷介紹了unix環(huán)境下的socket編程,還是有實(shí)例,很好的結(jié)合了協(xié)議,還涉及了一些實(shí)現(xiàn)原理。第二卷介紹了unix IPC,似乎和APUE有重復(fù)之嫌,我沒有看過這卷。
<9> "Understanding Linux Network Internals", Christian Benvenuti
-- 詳細(xì)介紹了linux網(wǎng)絡(luò)協(xié)議棧的實(shí)現(xiàn)細(xì)節(jié)。可惜沒有涉及tcp的實(shí)現(xiàn)和netfilter。
?
2. 目標(biāo)
本文假設(shè)讀者要成為linux環(huán)境系統(tǒng)程序員,涉及l(fā)inux用戶空間編程,網(wǎng)絡(luò)編程和linux 驅(qū)動(dòng)編程。
本文講述的是我自己的學(xué)習(xí)和工作體會(huì),希望大家能批判的理解,最終找到自己的路。
?
3. K&R 和 開發(fā)環(huán)境
K&R 當(dāng)然是一切的基礎(chǔ),必須認(rèn)真學(xué)好,對(duì)于沒有編程經(jīng)驗(yàn)的人來說,拿這本書入門有點(diǎn)難度,必須認(rèn)真完成書里的習(xí)題,能額外找些習(xí)題練手當(dāng)然更好。有C語(yǔ)言經(jīng)驗(yàn)的同學(xué)學(xué)起來輕松一些,抓重點(diǎn)難點(diǎn)看,書中關(guān)于指針的介紹很好,言簡(jiǎn)意賅。學(xué)通透之后,K&R 還可以成為手冊(cè),忘記了翻看一下還是必要的,這書要一直留著。
在學(xué)習(xí) K&R 的時(shí)候,同學(xué)就可以弄一個(gè)linux的主機(jī)玩一下了,(推薦debian, ubuntu)裝個(gè)基本系統(tǒng),把開發(fā)包裝一下,這些教程網(wǎng)上都有,自己查查吧,K&R里邊的例子最好在linux上面跑,學(xué)學(xué)gcc,make,vim的基本用法,不要太深入的學(xué),先夠用就可以了。
到這里,總體上還是輕松愉快的,我們開始找到一點(diǎn)入門的感覺了,但其實(shí)和入門還有很大的距離,繼續(xù)努力吧。
?
4. APUE 的考驗(yàn)?
經(jīng)常看到一些同學(xué)沒有看過APUE就開始學(xué)寫driver,這其實(shí)是不太合適的,如果說K&R是基礎(chǔ)的話,那么 APUE就是我們學(xué)習(xí)過程的核心,APUE不單純介紹接口,編程這些東西,書里邊涉及的思想,方法,會(huì)貫穿程序員的整個(gè)生涯,比如,書里邊談到了policy和mechanism這兩個(gè)unix系統(tǒng)重要的概念,并且用實(shí)例闡述它們,對(duì)我們理解unix系統(tǒng)有重要的意義。因此,我們要好好讀,反復(fù)讀這本書。
當(dāng)然,書里邊涉及過多的知識(shí),新手往往感覺很困難;因此,我們要注意方法。
(1) 必須把書里的實(shí)例在linux上面跑一下,Richard的書都是很有操作性的,建議同學(xué)最好用手敲的方式,把里邊一些短小的程序編譯執(zhí)行一下,如果能改改功能,調(diào)試調(diào)試那就更好了。APUE里的許多知識(shí)點(diǎn)必須是在實(shí)踐中才能理解和掌握的。
(2) 切忌貪多,貪快,不要想一口氣把書都讀完,最好先攻讀一些重點(diǎn)的章節(jié): File I/O, Process, Signal, IPC等等,適當(dāng)展開,多練習(xí)練習(xí),對(duì)于不太懂的概念,多google百度一下。
(3) 產(chǎn)生迷惑和疑問的時(shí)候,多和別人討論一下,發(fā)貼子問一下,交流很重要。
當(dāng)我們?cè)趯W(xué)習(xí)APUE的過程中,感到應(yīng)接不暇比較苦惱的時(shí)候,我建議同學(xué)要放慢節(jié)奏,弄一弄 gcc makefile gdb vim linux命令 bash編程這些, google一些教程來學(xué)習(xí),學(xué)寫一些復(fù)雜的例子。同時(shí),google一些簡(jiǎn)單的項(xiàng)目, 或者復(fù)雜的C練習(xí)題做做,盡量用到上面的工具,增加熟練度。
這個(gè)過程是一個(gè)略顯漫長(zhǎng)的學(xué)習(xí)過程,是程序員面臨的第一個(gè)坎,需要堅(jiān)持不懈。等跨過去之后,就海闊天空了。
另外,就我個(gè)人而言,我會(huì)在閱讀和學(xué)習(xí)的過程中,把一些重要的知識(shí)點(diǎn),tips, trick,重要的例程都整理成一個(gè)文檔,方便將來查閱使用,這個(gè)習(xí)慣保持整個(gè)學(xué)習(xí)和開發(fā)生活始終。?
5. 學(xué)習(xí)實(shí)際項(xiàng)目的源碼
經(jīng)常看到有人建議通過閱讀一些簡(jiǎn)單的開源項(xiàng)目來提高自己,我覺得這個(gè)做法很好,但是要注意時(shí)機(jī):
(1) 至少精讀過一遍APUE的重要章節(jié)
(2) 能看懂makefile,了解autoconf,比較熟練的使用vim, gcc, gdb, strace等工具(不會(huì)的google一下教程)。
好吧,這個(gè)時(shí)候,有些同學(xué)已經(jīng)辛苦的精讀過APUE所有的重要章節(jié)了(注意,不一定是全部的章節(jié)),看看,這個(gè)時(shí)候,堅(jiān)持手敲APUE實(shí)例代碼的同學(xué)就有優(yōu)勢(shì)了,他們vim相對(duì)會(huì)熟練一些:)那我們還等什么,趕緊開始吧,其實(shí),我們還差一個(gè)事情需要準(zhǔn)備,
(3) 學(xué)會(huì)使用 cscope, 不知道這個(gè)是什么?google去吧。,vim+cscope 看代碼,誰用誰知道。本文不想涉及工具之爭(zhēng)(vim或emacs), IDE之爭(zhēng),無論你選什么都可以,只要好用就行。
準(zhǔn)備就緒,選擇什么項(xiàng)目開始呢?我建議從簡(jiǎn)單的開始,coreutils
源碼可以從這里下載: http://www.gnu.org/software/coreutils/
是什么呢?對(duì),部分linux命令的源碼,從簡(jiǎn)單的(一般size比較小)開始學(xué)起,看看庫(kù)函數(shù)和系統(tǒng)調(diào)用怎樣相互配合,完成一個(gè)linux命令的功能。
我們可能發(fā)現(xiàn)源碼里邊宏定義特別多,影響閱讀,或者縮進(jìn)風(fēng)格詭異,看著費(fèi)勁,沒有辦法,慢慢適應(yīng)吧,vim有命令可以收起展開宏里邊的代碼,或者美化代碼縮進(jìn),自己查查怎么用。還有一些函數(shù)沒見過,setlocal()等等,沒關(guān)系查查APUE,或者 google,能把一個(gè)簡(jiǎn)單的源文件徹底搞明白,你會(huì)收獲很多。同時(shí),你對(duì)APUE的理解也會(huì)更進(jìn)一步,你越來越體會(huì)出這個(gè)書的寶貴,也越來越離不開它。
經(jīng)過一段時(shí)間的探索,你也許會(huì)感覺這些源碼也不過如此,不那么神秘了,恭喜你,現(xiàn)在你算是入門了。從現(xiàn)在開始,你已經(jīng)可以開始干活了。?
?6. 開始干活
我覺得,只學(xué)不干是嘴把式,只干不學(xué)是傻把式,兩者必須結(jié)合。
有項(xiàng)目的同學(xué)或者上班族可以去爭(zhēng)取一些簡(jiǎn)單的工作了,沒有項(xiàng)目的同學(xué),只能自己給自己找活干了。
在干活之前,有必要進(jìn)行一下準(zhǔn)備:
(1) 把工具和開發(fā)環(huán)境準(zhǔn)備好,有些項(xiàng)目需要特定的工具,比如subversion, git, SecureCRT, Cuteftp, 等等,一定要弄會(huì)了,多問問學(xué)長(zhǎng)同事什么的。
(2) 確定代碼風(fēng)格,無論是linux kernel的,還是windows的,都可以,但要風(fēng)格統(tǒng)一。
(3) 搞清楚任務(wù)目標(biāo),需求,還有期限。這點(diǎn)是最重要的,由于新手一般接手的工作比較簡(jiǎn)單,別人分配給你任務(wù)的時(shí)候往往不會(huì)特別用心,這時(shí)需要你多主動(dòng)提問,把細(xì)節(jié)問清楚。
干活的幾個(gè)重要階段:
(1) 分析和設(shè)計(jì)階段,這個(gè)時(shí)候不要著急編寫代碼,先分析一下需求,確定一下方法,畫畫流程圖,最好找個(gè)有經(jīng)驗(yàn)的人帶著做,會(huì)少走一些彎路,讓他幫著審核最終方案。
(下段 WaterMonster 網(wǎng)友補(bǔ)充)
其實(shí)unix下大部分的你能想到的程序都有人寫過一遍了,問題只是別人寫出來的軟件未必符合你工作下的實(shí)際需要。 設(shè)計(jì)之前,在開源界搜一搜,有沒有和你想法差不多的人,他們的實(shí)現(xiàn)是怎么樣的,整體的架構(gòu)是否合理,對(duì)比自己的思路走一走。
(2) 開始寫代碼了,不要一開始就想寫個(gè)高大全,先根據(jù)設(shè)計(jì)方案寫個(gè)盡量簡(jiǎn)單的程序,把框架搭起來,主要流程理順,最好能夠編譯執(zhí)行。無法完成功能也無所謂,我們?cè)俾倪M(jìn)它。
(3) 添加細(xì)部的功能,最好有適量的改動(dòng)就編譯執(zhí)行一下看看,這樣可以省去最后完整調(diào)試的時(shí)間。
(4) 調(diào)試(看log,gdb,strace,這里就不展開了),修改bug, 完善代碼。
改代碼盡量做到一下幾點(diǎn):
(a) 合理規(guī)劃文件, .h 文件放什么內(nèi)容,.c 文件放什么內(nèi)容,是用多個(gè).c文件,還是只用一個(gè)。這些問題需要經(jīng)驗(yàn),不能閉門造車,該問別人就問,或者找一些項(xiàng)目已有的代碼來參考,或者google,或者論壇發(fā)帖,不要指望一次能夠搞定,發(fā)現(xiàn)不合適的地方,隨時(shí)調(diào)整。
(b) 檢查代碼風(fēng)格,添加合理的注釋,一定要養(yǎng)成這個(gè)習(xí)慣。
(c) 添加合理的debug log,要有debug開關(guān),比如通過 -DDEBUG 編譯選項(xiàng)開打開debug。
OK, 到這里,我們主要的任務(wù)就完成了,如果驗(yàn)收通過了,是不是很有成就感?
等等,其實(shí)有些有追求的同學(xué)發(fā)現(xiàn),他的代碼和項(xiàng)目已有的代碼或者開源項(xiàng)目的代碼還是有差距,但是具體怎么改進(jìn)呢?從另外的角度講,都驗(yàn)收通過了,還改進(jìn)它干什么?
我認(rèn)為,"一個(gè)優(yōu)秀程序員的基本特質(zhì)就是,始終不遺余力的完善自己的代碼",我們不能以驗(yàn)收作為自己的最終目標(biāo),我們要成為優(yōu)秀的程序員,這個(gè)才是我們的目標(biāo)。
如果能達(dá)成這個(gè)共識(shí),請(qǐng)繼續(xù)看下去。
?
7 反思,梳理,制定計(jì)劃
我們有了項(xiàng)目經(jīng)驗(yàn)了,我們開始干活了,往往這個(gè)時(shí)候,我們也開始膨脹了。具體表現(xiàn)是,等著上面放任務(wù)干活,沒活可干的時(shí)候就玩,也不看書了,覺得自己就是大牛了,在bbs上還能給新新手回答一些問題了(注意,這時(shí)候往往會(huì)給出錯(cuò)誤的答案),一些程序員就是在這個(gè)階段停滯不前的,很可惜。
這個(gè)時(shí)候,我覺得可以開始給自己新的任務(wù)了,學(xué)習(xí)kernel也許是不錯(cuò)的選擇,不過,下一步怎么做不是最重要的,最重要的是,要在思想上清楚的認(rèn)識(shí)到,自己其實(shí)是剛剛?cè)腴T,對(duì)于linux kernel/driver 還沒有入門,我還有很多的坎需要邁。這個(gè)心態(tài)需要同學(xué)們好好體會(huì).
另外, 在繼續(xù)學(xué)習(xí)之前,有必要梳理一下之前的學(xué)習(xí)心得,整理筆記,甚至重讀一下APUE,往往你還會(huì)有新的收獲:你會(huì)發(fā)現(xiàn),在linux環(huán)境下面學(xué)習(xí)和工作的方法逐漸清晰了起來;你也許會(huì)偶而靈光一閃一個(gè)念頭,然后迫不及待的寫個(gè)小程序驗(yàn)證它。這些方法和習(xí)慣會(huì)在今后的學(xué)習(xí)和工作中慢慢完善,形成linux程序員特有的風(fēng)格。
這個(gè)時(shí)候,由于我們也許參與大的項(xiàng)目了,下一步的學(xué)習(xí)計(jì)劃需要結(jié)合自己的實(shí)際情況,并沒有固定的套路。對(duì)于本文涉及的領(lǐng)域來說,有兩個(gè)方向: linux driver和網(wǎng)絡(luò)編程。對(duì)于其他的方向,肯定還有,但是本文并不涉及。
后文會(huì)根據(jù)這兩個(gè)方向分別進(jìn)行闡述。
8. 網(wǎng)絡(luò)協(xié)議和搭建實(shí)驗(yàn)環(huán)境
在進(jìn)行網(wǎng)絡(luò)編程之前,先要了解tcp/ip協(xié)議;想學(xué)習(xí)網(wǎng)絡(luò)協(xié)議棧的實(shí)現(xiàn),一定要把網(wǎng)絡(luò)編程搞熟;想學(xué)習(xí)alsa驅(qū)動(dòng),先要熟悉使用asla庫(kù)調(diào)用;類似這些學(xué)習(xí)的順序,大家要注意。
在展開對(duì)<7>"TCP/IP Illustrated, Vol. 1"學(xué)習(xí)之前,我們需要考慮搭建網(wǎng)絡(luò)環(huán)境的問題,找一臺(tái)內(nèi)存大些的PC,裝虛擬機(jī)就搞定了(最好VMware,其他的我不確定是否可行), 具體的拓?fù)浣Y(jié)構(gòu)參考書里開頭就給出的網(wǎng)絡(luò),不需要百分百?gòu)?fù)制,體會(huì)精神就行。有2個(gè)router,2-3個(gè)host,1個(gè)gateway,這是必須的吧,等學(xué)習(xí)內(nèi)容變化的時(shí)候,拓?fù)淇梢愿淖儭?
這里再?gòu)?qiáng)調(diào)一下Richard書的學(xué)習(xí)方法,如果不能跟上實(shí)驗(yàn)操作,單純看書效果差多了。即使有條件接觸實(shí)際復(fù)雜網(wǎng)絡(luò)的同學(xué)也要建一套虛擬機(jī)的環(huán)境,不能影響別人是不。
書沒啥好說的,講得很好,我們關(guān)注一下 tcpdump:這是學(xué)習(xí)網(wǎng)絡(luò)的核心工具,大家要隨著書中的例子好好學(xué)習(xí)這個(gè)工具的使用,爭(zhēng)取在看完之后機(jī)能熟練掌握tcpdump的用法。對(duì)于書里稍復(fù)雜一些的知識(shí)點(diǎn),比如 tcp 的慢啟動(dòng),超時(shí)重傳等等要用 tcpdump 的結(jié)果去印證,加深印象。
另外,wireshark 也是一個(gè)不錯(cuò)的工具,提供了圖形化的界面,比tcpdump友好一些,而且用tcpdump保存下來的raw data是可以用 wireshark 進(jìn)行分析的,這兩個(gè)工具可以配合著用。
(annals網(wǎng)友: 還ethereal,用wireshark已經(jīng)很久了)
經(jīng)過APUE的煎熬,讀協(xié)議簡(jiǎn)直就是一種享受,各種念頭通達(dá),稍微復(fù)雜的例子也可以配合tcpdump來理解,可這只是開始,重頭戲在后面。
9. 網(wǎng)絡(luò)編程 UNP
學(xué)習(xí)UNP的方法和APUE差不多,看書,練習(xí)例子。如果能加上tcpdump的分析,那就更好了。經(jīng)過一段時(shí)間,你會(huì)發(fā)現(xiàn)UNP就是對(duì)APUE的復(fù)習(xí)嘛,信號(hào),線程,系統(tǒng)調(diào)用這些都要用到,而且比APUE上的講法要更實(shí)際,更有操作性。
書里經(jīng)常會(huì)用不同的方法去實(shí)現(xiàn)同一個(gè)功能,或者把一個(gè)簡(jiǎn)單的例子逐漸添加血肉,變成復(fù)雜的例子。這些都是Linux著作常用的方法,注意體會(huì),將來自己寫文章或許可以用到;寫程序的時(shí)候,也可以遵循先簡(jiǎn)單后復(fù)雜的過程,符合認(rèn)識(shí)規(guī)律。
書里邊的例子也很經(jīng)典,比如 select(), poll() 的例子,同學(xué)可以敲一遍多跑跑,整理到文檔里,將來要寫這種程序的時(shí)候,拿來就用,方便快哉。
有了APUE的基礎(chǔ),UNP的進(jìn)展應(yīng)該比較順利,下面就是用具體的項(xiàng)目代碼入手了。
?
10. hping 上
我們通過學(xué)習(xí)hping的用法及其源碼,鞏固對(duì)協(xié)議的認(rèn)識(shí)和熟悉網(wǎng)絡(luò)編程。hping3可以在這里得到: http://www.hping.org/hping3-20051105.tar.gz
看看這個(gè)工具是干嘛的,注意README里邊提到,這是一個(gè)學(xué)習(xí)tcp/ip絕佳工具(It's also really a good didactic tool to learn TCP/IP), 這個(gè)版本還支持tcl腳本了,比我那個(gè)時(shí)候強(qiáng)大了嘛:)
哎,同學(xué),不要著急看源碼啊,忘了順序了嘛?不先熟悉一下hping3的命令,怎么能上來就看代碼呢?還是先build一下把,這次講得稍微復(fù)雜一些:
一般 linux 源碼包的編譯過程一般是
$ ./configure
$ make
$ make install
hping也不例外
$ ./configure
$ make
這個(gè)時(shí)候,我這邊報(bào)錯(cuò)了
gcc -c -O2 -Wall -g main.c
main.c:29:18: error: pcap.h: No such file or directory
main.c:169: error: expected ‘=’, ‘,’, ‘;’, ‘a(chǎn)sm’ or ‘__attribute__’ before ‘*’ token
main.c:170: error: ‘PCAP_ERRBUF_SIZE’ undeclared here (not in a function)
make: *** [main.o] Error 1
有經(jīng)驗(yàn)的同學(xué)可能知道,這是缺少pcap開發(fā)包了,如果不知道也沒關(guān)系,google一下就能找到答案了,另外,或許還會(huì)缺少tcl-dev包,請(qǐng)?jiān)谙旅娴膗rl找到相應(yīng)的源碼包,或者自行尋找和發(fā)行版對(duì)應(yīng)的二進(jìn)制包,這里就不詳細(xì)展開了。
http://www.tcpdump.org/release/libpcap-1.1.1.tar.gz
http://www.tcl.tk/
繼續(xù)make,開頭過去了,不過又一個(gè)錯(cuò)誤:
libpcap_stuff.c:20:21: error: net/bpf.h: No such file or directory
libpcap_stuff.c: In function ‘pcap_recv’:
libpcap_stuff.c:61: warning: pointer targets in assignment differ in signedness
make: *** [libpcap_stuff.o] Error 1
這次又需要google一下了,用關(guān)鍵自 net/bpf.h 搜索一下,很快找到解決方法:
$ ln -snf /usr/include/pcap-bpf.h /usr/include/net/bpf.h
然后順利通過:
$ make
$ make install
大功告成。
11. hping 下
可以看看 hping3 的文檔,如果感覺不太直觀,google一下別人的教程(推薦 http://wiki.hping.org)。練習(xí)一些簡(jiǎn)單的命令, 如果在教程里發(fā)現(xiàn)什么idle scanning, Packet crafting等字眼,請(qǐng)大家自動(dòng)過濾,我什么都沒說過, 什么都沒說過......
hping有兩種工作模式,script和command line模式。
這里給一個(gè)command line模式簡(jiǎn)單的例子,用hping發(fā)一個(gè)icmp包到指定的host
$ hping -V -1 www.google.com
這個(gè)時(shí)候,也可以用tcpdump抓包看看:
$ tcpdump -n -i ethX icmp
下面是script模式的例子,用hping發(fā)一個(gè)icmp包到指定的服務(wù)器。
$ hping # 進(jìn)入腳本解釋器
hping3> hping resolve wiki.hping.org
109.74.203.151
hping3> hping send {ip(daddr=109.74.203.151)+icmp(type=8,code=0)}
我們也可先編寫腳本(例如xxx.tcl),然后用下面的命令執(zhí)行:
$ hping exec xxx.tcl
wiki.hping.org上面有很復(fù)雜的腳本示例,這種方法本讓hacker從C程序的繁重工作解脫出來,通過簡(jiǎn)單易用的腳本可以實(shí)現(xiàn)靈活強(qiáng)大的功能。
看源碼的話,可以從main()函數(shù)看起,看看command line模式下的代碼流程。
從hping_script()這個(gè)函數(shù)調(diào)用開始,會(huì)進(jìn)入到script模式的處理code,不建議新手學(xué)習(xí)。
hping使用SOCK_RAW發(fā)送各種類型的包tcp/udp/icmp等等,并統(tǒng)一使用pcap庫(kù)來捕捉返回包,要注意和使用SOCK_STREAM時(shí)的思路是不同的,前者需要自己構(gòu)造ip包頭,對(duì)照著協(xié)議閱讀整個(gè)過程是必要的。
當(dāng)同學(xué)對(duì)hping的腳本和源碼有了一定的了解,你也就對(duì)網(wǎng)絡(luò)編程開始入門了,同時(shí),隨著Linux環(huán)境下的學(xué)習(xí)和工作方法的逐步成熟,你會(huì)發(fā)現(xiàn)學(xué)習(xí)效率在提高,信心在增強(qiáng),通過耐心的分析研究,這些開源項(xiàng)目的源碼不在話下。
補(bǔ):等寫完了發(fā)現(xiàn),并沒有給出一個(gè)client/server類的例子供大家學(xué)習(xí),iperf 不知是否合適,請(qǐng)大家自行編譯執(zhí)行分析。如果大家有時(shí)間,可以考慮自行設(shè)計(jì)一個(gè)復(fù)雜一點(diǎn)的程序,client/server模式的,用到信號(hào),多線程,socket,select,文件I/O,IPC 等等,算是一個(gè)總結(jié),后邊開始進(jìn)入kernel space的世界。
12. 從LKD開始
我們打開參考書<4>"Linux Kernel Development", 書的作者Robert love是kernel的設(shè)計(jì)者之一,但他并沒有把書寫得深?yuàn)W難懂,分寸把握的很好,僅僅400頁(yè)的篇幅,就講解了Kernel的絕大多數(shù)要點(diǎn),重點(diǎn)突出,細(xì)枝末節(jié)一筆帶過,決不拖泥帶水。書的篇幅少也和引用的代碼少有關(guān),不湊字?jǐn)?shù),相當(dāng)有料。
盡管篇幅有限,但本書開頭還是不厭其煩的給出了一些如何build kernel的說明,還對(duì)源碼樹各部分進(jìn)行了說明;這從側(cè)面表明了作者的態(tài)度,看書的時(shí)候也得動(dòng)手啊。
在 http://www.kernel.org/ 得到kernel的源碼,然后編譯
$ cd linux-source-dir/
$ make menuconfig
$ make
關(guān)于menuconfig選項(xiàng),升級(jí)kernel image,grub install的方法,這里就不贅述了,請(qǐng)同學(xué)自行解決,多練習(xí)練習(xí)沒壞處。
盡管書寫得比較易懂,但可能對(duì)于剛開始接觸kernel的人還是有點(diǎn)難度,尤其是對(duì)于非科班出身的同學(xué),沒學(xué)習(xí)過體系結(jié)構(gòu)和操作系統(tǒng)原理,先自行了解基本概念還是必要的。
橫看成嶺側(cè)成峰,讓我們從幾個(gè)不同的角度來認(rèn)識(shí)認(rèn)識(shí)kernel同學(xué):
1) 從原教旨主義的角度看,linux kernel就是一大坨文件目錄樹,主要由C/匯編源文件,腳本,配置文件,文檔,以及某些二進(jìn)制文件組成。由全球的志愿者(包括商業(yè)公司)在Linux社區(qū)開發(fā)維護(hù)。
2) 從存在主義的角度看,linux kernel就是一個(gè)二進(jìn)制文件,從上面這些源文件編譯生成,一般長(zhǎng)期保存在PC的硬盤中,使用時(shí),這個(gè)二進(jìn)制文件會(huì)被加載到內(nèi)存,CPU會(huì)執(zhí)行里邊的機(jī)器代碼。
3) 從經(jīng)典講義的角度看,linux kernel上安application,下?lián)醜ardware:給app提供api讓其訪問hardware,同時(shí)給hardware提供driver來讓其能正常工作。
4) 從發(fā)行版的角度看,linux kernel就是個(gè)悲劇,連自己的名分都保不住,用戶只知道redhat, ubuntu不知道kernel是神馬玩意。
5) 從我的角度看,kernel就是一個(gè)進(jìn)程而已。
?
13 Kernel是一個(gè)進(jìn)程
為什么這么講呢?咱們看一下系統(tǒng)啟動(dòng)的過程:PC上電了,bootloader首先被執(zhí)行,做完一些初始化工作,它把kernel image加載到了內(nèi)存里,讓CPU執(zhí)行kernel的代碼,這個(gè)時(shí)候kernel是PC上跑的第一個(gè),也是唯一的一個(gè)進(jìn)程,它一下就奪過對(duì)CPU的控制權(quán),把CPU,內(nèi)存,clock,中斷控制器等等先調(diào)教了一番,又初始化了內(nèi)部的一些算法和數(shù)據(jù)結(jié)構(gòu),它給自己起名字叫"swapper", 數(shù)字0是他的終身代號(hào),然后,它就寂寞了......
swapper從硬盤上面又找了一個(gè)二進(jìn)制文件,叫做init,加載到內(nèi)存,代號(hào)1,允許CPU執(zhí)行他的代碼。然后它又創(chuàng)建了幾個(gè)內(nèi)核線程來分擔(dān)它的工作,這些線程有自己獨(dú)特的名字和代號(hào)。而kernel也從單獨(dú)的一個(gè)進(jìn)程,變成了由多個(gè)內(nèi)核線程組成的大進(jìn)程。
init并不是這個(gè)大進(jìn)程的成員,但它努力產(chǎn)崽,有了許多子子孫孫進(jìn)程,我們統(tǒng)稱它們叫用戶進(jìn)程,這些進(jìn)程訪問資源的權(quán)限受到嚴(yán)格限制,盡管優(yōu)先級(jí)有時(shí)可以調(diào)整到很高。
kernel線程也不停創(chuàng)建同類,但他們互相不稱父子,因?yàn)樗麄冇泄餐纳眢w,他們的權(quán)限不受限制。
這些用戶進(jìn)程和kernel線程在調(diào)度算法的指揮下,輪番取得對(duì)cpu的控制權(quán),執(zhí)行自己的代碼。
而swapper呢?他其實(shí)算是第一個(gè)內(nèi)核線程,不過它低調(diào)的調(diào)低自己的優(yōu)先級(jí),深居簡(jiǎn)出,當(dāng)所有的進(jìn)程線程都無事可做的時(shí)候,才會(huì)出來主持局面,取得cpu控制權(quán),這時(shí)候系統(tǒng)處于idle狀態(tài)。只要它發(fā)現(xiàn)其他進(jìn)程有事可做,就會(huì)立刻交出CPU控制權(quán)。
面對(duì)swapper前輩轉(zhuǎn)身離去時(shí)那落寞的背影,眾kernel線程都是唏噓不已,只有init進(jìn)程在背后默默豎起中指,表達(dá)當(dāng)初在權(quán)限上受到不公待遇的憤恨, 待續(xù)......
評(píng)論:
不考慮中斷異常以及技術(shù)細(xì)節(jié),本文從進(jìn)程的角度讓同學(xué)體會(huì)了kernel的存在感,kernel沒有那么神秘,不是超然的造物主,僅僅是一個(gè)進(jìn)程而已,只不過子線程們承擔(dān)了很多特殊的管理任務(wù)而已,這些管理任務(wù)的詳情和省掉的技術(shù)細(xì)節(jié)我們可以慢慢了解,找尋答案,但是對(duì)kernel的整體把握要有,頭腦中始終有清晰的認(rèn)識(shí),無論系統(tǒng)跑到何時(shí),我們都要知道身處何地(處于哪個(gè)進(jìn)程或者中斷服務(wù)程序)。
中斷和異常表面上看起來優(yōu)先級(jí)太高,執(zhí)行過程過于霸道,但其實(shí)并沒有破壞進(jìn)程間調(diào)度輪番取得CPU控制權(quán)的工作模式,這點(diǎn)我不打算詳細(xì)闡述了,書里邊對(duì)中斷異常描述的很好,同學(xué)們可以自己好好感悟一下。
從現(xiàn)在開始越來越不好寫了啊,壓力很大,不過我會(huì)加油的。
?
14 閱讀思路
上文描述的啟動(dòng)過程涉及的源文件如下:
init/main.c
arch/x86/kernel/process_32.c
其實(shí)應(yīng)該還包括更多的源文件,但 init/main.c 里的start_kernel()是啟動(dòng)過程的核心,只要抓住這個(gè)地方,我們很容易就可以按圖索驥找到其他的源文件,同學(xué)要體會(huì)這個(gè)思路。
在看LKD的時(shí)候,同學(xué)除了要把概念原理算法弄清楚,還要像上面這樣,根據(jù)書中提供的線索,把每個(gè)知識(shí)點(diǎn)對(duì)應(yīng)的源文件名找出來,記錄到筆記里,等將來需要的時(shí)候,我們?cè)俾芯考?xì)節(jié)。
我們?cè)倥e系統(tǒng)調(diào)用(system call)的例子:
看過LKD里關(guān)于system call的描述,有如下的問題:
1) 為什么要有system call,system call有什么功能?
2) Usersapce通過什么指令調(diào)用kernel的system call,傳遞了什么信息?
3) kernel怎么建立system call number和具體實(shí)現(xiàn)函數(shù)的對(duì)應(yīng)關(guān)系?
4) system call在執(zhí)行的時(shí)候處于什么上下文?
5) 實(shí)現(xiàn)system call handler的主要源文件在哪里?
6) 除了書中給出的例子,再找一個(gè)system call的實(shí)現(xiàn)。
對(duì)于初次閱讀的我們,知道這些已經(jīng)不錯(cuò)了,最好把答案整理到筆記里。等讀完這本書,我們應(yīng)該對(duì)基本概念有了了解,整體上對(duì)kernel有了把握。盡管對(duì)算法,實(shí)現(xiàn)細(xì)節(jié)不太了解,但是我們大體知道努力的方向了:后續(xù)深入的研究源碼。對(duì)于開發(fā)人員,優(yōu)先選擇和我們的工作關(guān)系密切的部分深入鉆研吧。?
15 內(nèi)存管理
想要從整體上理解linux的內(nèi)存管理,我們需要理解內(nèi)存管理的兩個(gè)大的功能:
1) 幫助MMU正常工作,實(shí)現(xiàn)物理地址和虛擬地址的轉(zhuǎn)換(paging)
2) 對(duì)物理內(nèi)存進(jìn)行管理,分配,回收,共享等等
相應(yīng)的,這兩個(gè)功能分別對(duì)應(yīng)下面兩個(gè)核心table:
1) page table
2) page frame descriptor table, 源碼中的名稱 mem_map
我們順著這個(gè)脈絡(luò),對(duì)兩者進(jìn)行比較,同時(shí)也就理順了內(nèi)存管理的大體思路:
從分配回收方面比較:
1) page table 用來作paging,每個(gè)進(jìn)程各有一份(我們把kernel看作一個(gè)大進(jìn)程), kernel 的 page table 叫做 swapper_pg_dir, 是在啟動(dòng)的時(shí)候創(chuàng)建的,每個(gè)進(jìn)程在出生的時(shí)候會(huì) 以swapper_pg_dir為藍(lán)本建立各自的page table,進(jìn)程死亡的時(shí)候kernel會(huì)回收他的page table,page table 一般采用多級(jí)結(jié)構(gòu),最后一級(jí)page table的每個(gè)entry都對(duì)應(yīng)一個(gè)page大小的內(nèi)存,每個(gè)entry的size一般是4個(gè)字節(jié)。(arch/x86/kernel/head_32.S, setup_arch()@init/main.c, paging_init()@arch/x86/mm/init_32.c)
2) mem_map 用來管理物理內(nèi)存,在啟動(dòng)的時(shí)候創(chuàng)建的,只有一個(gè),永不釋放,mem_map和物理內(nèi)存一一對(duì)應(yīng),每個(gè)entry管理了一個(gè)page的物理內(nèi)存,每個(gè)entry的size為40個(gè)字節(jié)左右。(free_area_init_nodes()@mm/page_alloc.c)
具體過程:以x86體系結(jié)構(gòu)為例
1) Linux啟動(dòng)之后,指令中的地址必須是虛擬的,MMU負(fù)責(zé)轉(zhuǎn)為物理地址,轉(zhuǎn)化的過程就是查詢更新TLB緩存,檢索page table的過程。進(jìn)程在運(yùn)行時(shí),會(huì)把頂級(jí)page table的首地址保存在CR3寄存器中,MMU根據(jù)CR3的值才得以找到正確的page table。進(jìn)程切換的時(shí)候,需要更新CR3。
2) Kernel使用buddy算法對(duì)mem_map進(jìn)行管理,申請(qǐng)釋放內(nèi)存的size必須是2的n次冪page大小,在buddy之上,kernel還使用了slab算法(或slub)對(duì)內(nèi)存進(jìn)行再次管理,可以提供更小單位的申請(qǐng)釋放和cache功能,讓內(nèi)存的使用更有效率,速度更快。(mm/page_alloc.c)
理解了這兩個(gè)table,我們就抓住了內(nèi)存管理的核心,其中涉及的技術(shù)細(xì)節(jié)請(qǐng)自行了解,其他一些概念也很重要,如memory layout,zone,mm_struct, memory area management等,這里不展開了。
16 驅(qū)動(dòng)程序概述
同學(xué)通過LKD對(duì)linux kernel進(jìn)行了基礎(chǔ)的理解,對(duì)于驅(qū)動(dòng)方向的同學(xué)來講,可以開始看LDD3,進(jìn)行下一步對(duì)重點(diǎn)方向和任務(wù)的學(xué)習(xí),本文給出一些重點(diǎn)需要關(guān)注的知識(shí)點(diǎn)。
從最簡(jiǎn)單的模型上看,kernel的職責(zé)就是管理hardware,給app提供訪問接口。CPU, 內(nèi)存,外設(shè)這些都是hardware;每個(gè)外設(shè)都有相應(yīng)的驅(qū)動(dòng)進(jìn)行管理;從某種意義上講,CPU和內(nèi)存也有著相應(yīng)的驅(qū)動(dòng)進(jìn)行管理。
* 把驅(qū)動(dòng)的功能抽象一下看,無非要完成下面的工作:
1) 初始化工作:檢測(cè)/PnP,供電,設(shè)置clock,設(shè)置register,及其他操作。
2) I/O工作:讓app能夠讀,寫,或控制hardware, 或許同時(shí)要提供多用戶共享,訪問保護(hù),狀態(tài)恢復(fù)等功能。
3) power management
* 驅(qū)動(dòng)程序框架
LDD 的14章詳細(xì)闡述了linux kernel model,這個(gè)是看驅(qū)動(dòng)代碼,寫驅(qū)動(dòng)程序的基礎(chǔ),需要好好揣摩,核心是這3個(gè)概念:device,driver,bus
大多數(shù)的驅(qū)動(dòng)都要實(shí)現(xiàn)driver里邊的函數(shù)指針(open, read, write等等),然后注冊(cè)給上層,提供app訪問的接口。這是kernel里邊常見的思路:定義結(jié)構(gòu),實(shí)現(xiàn)指針,注冊(cè)接口;我們也可借鑒到自己平時(shí)的程序中。
另外還要了解kobj,sysfs的一些用法,我們?cè)趯懗绦虻臅r(shí)候盡量用這個(gè)接口替換procfs。
另外,為了讓我們的driver越來越簡(jiǎn)單,同時(shí)減少冗余的代碼,kernel往往會(huì)把不同廠商的驅(qū)動(dòng)中一些公共的代碼抽出來,建立一套框架和公共接口。具體例子有:
input設(shè)備的驅(qū)動(dòng)框架(drivers/input/input.c);
Video設(shè)備的驅(qū)動(dòng)框架V4L2(drivers/media/video/videobuf-core.c);
音頻設(shè)備的框架(sound/sound_core.c)。
* 在驅(qū)動(dòng)編程中,我們要熟悉下面這些東西:
kernel的重要概念:
irq, irq handler, dma
softirq, tasklet, timer
work queue, wait queue, kernel thread
debug相關(guān)
printk, oprofile, ftrace, oops, kdb, procfs, sysfs, errno
一些常用的api:
list操作 include/linux/list.h
lock操作 include/linux/spinlock.h
mutex操作 include/linux/mutex.h
semaphore操作 include/linux/semaphore.h
bit操作 include/asm-generic/bitops/atomic.h
atomic操作 include/asm-generic/atomic.h
kfifo操作 include/linux/kfifo.h
alloc_page操作 include/linux/gfp.h
readX/writeX include/asm-generic/io.h
ioremap(), remap_pfn_range(), kmalloc(), vmalloc()
schedule_timeout()
在書中對(duì)上面的知識(shí)點(diǎn)有大量的講解,源碼中也有很好的示例,我們要深刻理解,這里就不是掌握整體了,而是熟練掌握。
17 驅(qū)動(dòng)開發(fā)任務(wù)
了解知識(shí)只是基礎(chǔ),還是要以任務(wù)為核心,找到解決問題的思路。我們?cè)谧鲵?qū)動(dòng)開發(fā)的時(shí)候,一般會(huì)面臨下面幾種任務(wù):
1) 維護(hù)現(xiàn)成的驅(qū)動(dòng)代碼,改bug;負(fù)責(zé)寫用戶空間的接口庫(kù)或者測(cè)試程序。
2) 從別的平臺(tái)上移植驅(qū)動(dòng)到linux上。
3) 從頭開發(fā)一個(gè)驅(qū)動(dòng),我們可能只有硬件手冊(cè)上面的偽代碼參考。
對(duì)于1),任務(wù)簡(jiǎn)單,往往是給新手的活,前幾章的學(xué)習(xí)過程往往也是在執(zhí)行這個(gè)任務(wù)的時(shí)候進(jìn)行的,例如:組長(zhǎng)給新員工分配了寫測(cè)試程序的活,他需要學(xué)學(xué)類似APUE這樣的書,分配修bug的任務(wù)時(shí),他需要學(xué)學(xué)kernel和driver基礎(chǔ)。
當(dāng)我們經(jīng)過了前幾章的大量練習(xí),可以很輕松的完成測(cè)試程序的任務(wù),但是我們是有追求的程序員,我們需要給自己更高的要求,就像第六章提到的那樣,不停的改進(jìn)自己的測(cè)試程序,多參考開源代碼成熟的例子,體會(huì)更好的編程技巧。
通過測(cè)試程序,有了對(duì)驅(qū)動(dòng)接口直觀的了解之后,我們開始詳細(xì)的學(xué)習(xí)驅(qū)動(dòng)的代碼,只有完整的了解了驅(qū)動(dòng)的方方面面,后邊解bug的時(shí)候才能游刃有余。我們需要做到:
a) 仔細(xì)閱讀硬件參考手冊(cè),了解硬件工作的原理,流程,時(shí)序圖,寄存器介紹。
b) 了解對(duì)應(yīng)的驅(qū)動(dòng)框架,比如前文提到的input,alsa,V4L2等,看看你負(fù)責(zé)的驅(qū)動(dòng)是否工作于一個(gè)框架下,涉及的內(nèi)核基本知識(shí)要確保都能搞懂。
c) 分析驅(qū)動(dòng)代碼,不光是看,要把debug打開,跑跑測(cè)試程序,看看log,流程自然就清晰了,分析代碼會(huì)快上許多,如果用示波器或者邏輯分析儀抓抓波形,可更好的加深印象。
能做到以上這些,解bug就是很容易的事情,把前文提到的debug方法熟悉一下是必要的。debug工作本身還是有一些技巧的,需要在實(shí)踐中多總結(jié),注意觀察有經(jīng)驗(yàn)同事的做法。有時(shí)驅(qū)動(dòng)的bug是硬件造成的,接線錯(cuò)了,少了個(gè)電阻電容,這些都是常有的事,大家不要抱怨,溝通的時(shí)候注意技巧,想辦法證明自己的代碼沒有問題,這樣才能讓硬件工程師甘心改板子。
為什么對(duì)任務(wù)1)費(fèi)這么多口舌呢?因?yàn)?#xff0c;這個(gè)例子契合了本系列寫作的初衷:完事開頭難,我們要花大力氣把開頭的工作做好做精,基礎(chǔ)打牢,掌握好的方法,樹立信心,培養(yǎng)興趣,后邊的工作就會(huì)水到渠成,游刃有余。
對(duì)于任務(wù)2),步驟和1)幾乎一樣,只需要額外注意2點(diǎn):
a) 分析好原平臺(tái)的代碼,移植的時(shí)候多參考linux里邊現(xiàn)有的例子
b) 測(cè)試程序盡早編寫,集成和修bug工作離不開它。
對(duì)于任務(wù)3),我覺得這里不需要再給出任何提示,一路走來的同學(xué)你自己琢磨吧。
有意思,講驅(qū)動(dòng)的文章,卻不討論如何從頭編寫驅(qū)動(dòng)。其實(shí),任何看起來復(fù)雜的任務(wù)都經(jīng)不起推敲和分解,當(dāng)分解成一個(gè)個(gè)小塊的時(shí)候,我們就看到了當(dāng)年做過的大量基礎(chǔ)練習(xí)。我們要好好練習(xí)推敲和分解,掌握自己的思路。
18 網(wǎng)絡(luò)進(jìn)階
為了內(nèi)容結(jié)構(gòu)的完整性,寫一下網(wǎng)絡(luò)的問題,我已經(jīng)很久不搞了,別說細(xì)節(jié),給輪廓都很難了。
網(wǎng)絡(luò)始終是一個(gè)實(shí)踐性特別強(qiáng)的部分,理論如果不聯(lián)系著實(shí)際理解,會(huì)學(xué)得非常痛苦。
一般我們有了kernel和網(wǎng)絡(luò)編程的基礎(chǔ)之后,可以開始學(xué)習(xí)協(xié)議棧的實(shí)現(xiàn),也就是參考書<9>,在虛擬機(jī)上面把kernel 網(wǎng)絡(luò)部分的log打開,跟著書里描述的過程,大致了解一下網(wǎng)絡(luò)協(xié)議棧。觀察協(xié)議棧如何傳遞skbuf這個(gè)指針是很有意思的一個(gè)看點(diǎn)。
要想深入了解,可以從netfilter入手,它是目前國(guó)內(nèi)網(wǎng)絡(luò)方向的重點(diǎn)。
先從練習(xí)iptables命令開始,在虛擬機(jī)上面實(shí)現(xiàn)一個(gè)NAT網(wǎng)關(guān)還是不難的吧,最好把iproute這個(gè)包也安裝一下,了解一下ip命令,這是配置路由表的工具,有了這兩個(gè)工具的使用基礎(chǔ),你就會(huì)有了直觀的概念。 如夠看看iptable和ip的源碼,了解一下網(wǎng)絡(luò)層的用戶接口,當(dāng)然更好了。
進(jìn)入到了解netfilter具體框架的階段,我們要在頭腦中深刻的建立這個(gè)圖的印象:
http://upload.wikimedia.org/wikipedia/commons/8/8f/Diagrama_linux_netfilter_iptables.gif
閱讀代碼,找到圖中每個(gè)關(guān)鍵點(diǎn)的位置,了解相關(guān)概念。當(dāng)然,還要實(shí)踐一下,添加一個(gè)自己的netfilter module,這都是必須的。
linux的路由選擇過程也要徹底理解,這和netfiler也是息息相關(guān)的。
netfilter往往還需要配合流量控制,先學(xué)習(xí)tc這個(gè)用戶空間的工具,然后在看kernel的實(shí)現(xiàn)。
ebtables是設(shè)置網(wǎng)橋規(guī)則的工具,也需要了解。
這章也得簡(jiǎn)單潦草,算是一個(gè)草稿,等將來再改進(jìn)吧。
19 自我認(rèn)知
曾經(jīng)一位很很有經(jīng)驗(yàn)的工程師和我講過要學(xué)會(huì)對(duì)事情分類:
1) 重要且緊急的事情
2) 不重要且緊急的事情
3) 重要不緊急的事情
4) 不重要不緊急的事情
要按照這個(gè)順序展開工作,這使我第一次思考除了技術(shù)以外的一些事情。
在工作開頭的幾年,我在打基礎(chǔ)的同時(shí),也經(jīng)歷著一個(gè)自我認(rèn)知和行業(yè)認(rèn)知的過程。
在浮躁的社會(huì)背景下,開發(fā)工作不是一個(gè)經(jīng)濟(jì)效益很高的選擇,而且行業(yè)整體的競(jìng)爭(zhēng)比較激烈,新陳代謝比較快,而且業(yè)內(nèi)普遍追求急功近利,重營(yíng)銷,不重技術(shù)等等。
在這樣的背景下,開發(fā)人員對(duì)未來進(jìn)行選擇很不容易,有些人天生對(duì)社會(huì)有很好的適應(yīng)能力,他們很容易轉(zhuǎn)型到非技術(shù)崗位,找到合適自己的方向,經(jīng)濟(jì)效益也不錯(cuò),這是一個(gè)值得考慮的選擇。
有些人不喜歡這個(gè)行業(yè)和自己的工作,于是選擇了轉(zhuǎn)行,
有些人也不喜歡但選擇了硬挺,為了生存和家庭。
不管怎樣,經(jīng)歷了最初的幾年,每個(gè)人都要思考自己未來的職業(yè)生涯了,該怎么選擇自己的道路?這是沒有標(biāo)準(zhǔn)答案的問題,因?yàn)槊總€(gè)人的追求和價(jià)值觀是不同的。
但對(duì)于那些踏實(shí),勤奮,熱愛開發(fā)的geek工程師們,你們不能迷茫,你們要好好的把握住自己的未來。你們需要迫切解決下面這兩個(gè)問題:
成為一名優(yōu)秀的工程師
在一個(gè)好的團(tuán)隊(duì)中找到適合自己的位置。
達(dá)成了這兩個(gè)目標(biāo),你的職業(yè)生涯豁然開朗,你的生活既充實(shí)有愜意,這也會(huì)給你帶來出色的表現(xiàn),其他方方面面的問題也會(huì)迎刃而解。
?
20 成為牛人
剛走向社會(huì)的同學(xué)往往喜歡打聽別人的薪水,羨慕別人的職位,但并不關(guān)注別人奮斗的過程和成長(zhǎng)的體會(huì);羨慕朋友所在的公司上市,卻不關(guān)心他的團(tuán)隊(duì)運(yùn)作和管理。我們是不是應(yīng)該豐富一下關(guān)注的點(diǎn)?
我遇到過輾轉(zhuǎn)進(jìn)入心儀的大公司,拿到豐厚薪水,但抱怨生活不如意的
我遇到過拿到高薪,高職位,空有才干,卻整天無所事事的
我也遇到過畢業(yè)就留在二線城市的小公司,至今做大,成為公司高管的
我也遇到過勤勤肯肯鉆研技術(shù),筆耕不輟,成為IT行業(yè)知名作家和創(chuàng)業(yè)公司CTO的
我也遇到過從編程轉(zhuǎn)行做買賣發(fā)財(cái)?shù)?
上面這些人都是傳統(tǒng)意義上的"牛人",都有自己的性格特點(diǎn)和興趣點(diǎn),每個(gè)人的軌跡都不能簡(jiǎn)單的復(fù)制,但總體來說:牛人需要付出很大的辛苦,同時(shí)在工作中表現(xiàn)得也很好,其中比較幸運(yùn)的在付出的同時(shí)也在享受自己的事業(yè)。
我不想做什么熱愛工作的勵(lì)志教育,我只是想說牛人是沒有模板的,誰都有機(jī)會(huì),希望同學(xué)們?cè)诖蚵犘剿?#xff0c;能夠多了解一下背后的故事,體會(huì)一下別人的辛勤付出,找到自己的路,即使你要混黑社會(huì)也要敬業(yè)不是。?
轉(zhuǎn)載于:https://www.cnblogs.com/uhasms/archive/2011/11/15/2250474.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的zzfrom水木-Linux环境学习和开发心得(作者:lunker)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VSS (Visual Source S
- 下一篇: watir添加新标签