文章作者:不詳
本文連接:
http://hi.baidu.com/wwwanq/ 從理論上說,任何一門語言都可以在任何一個系統上編程,只要找到該系統提供的“接口”和對系統內部機制有深
入的了解就可以了,至少我是這么認為的。正如c語言可以在windows下編程,也同樣可以在Linux上大放異彩一樣。
編程是一項很繁雜的工作,除了應用編程工具之外,了解系統本身內部工作機理非常重要,這是你寫出穩定兼容的
程序所必不可少的前提條件。你要在哪一種系統上編程就要對該系統的機制進行研究,至少你應該知道一個程序在那個
系統上是如何運行的。
一、了解Windows 內部機制
Windows 是一個“基于事件的,消息驅動的”操作系統。
在Windows下執行一個程序,只要用戶進行了影響窗口的動作(如改變窗口大小或移動、單擊鼠標等)該動作就會
觸發一個相應的“事件”。系統每次檢測到一個事件時,就會給程序發送一個“消息”,從而使程序可以處理該事件。
每個Windows 應用程序都是基于事件和消息的,而且包含一個主事件循環,它不停地、反復地檢測是否有用戶事件發
生。每次檢測到一個用戶事件,程序就對該事件做出響應,處理完再等待下一個事件的發生。
Windows 下的應用程序不斷地重復這一過程,直至用戶終止程序,用代碼來描述實際上也就是一個消息處理過程
的while循環語句。
下面便簡單介紹一下與 Windows 系統密切相關的幾個基本概念:
⒈窗口:這是我要說的第一個概念。似乎是地球人都知道的事兒了,窗口是Windows本身以及Windows 環境下的
應用程序的基本界面單位,但是很多人都誤以為只有具有標題欄、狀態欄、最大化、最小化按鈕這樣標準的方框才叫
窗口。其實窗口的概念很廣,例如按鈕和對話框等也是窗口哦,只不過是一種特殊的窗口罷了。
從用戶的角度看,窗口就是顯示在屏幕上的一個矩形區域,其外觀獨立于應用程序,事實上它就是生成該窗口
的應用程序與用戶間的直觀接口;從應用程序的角度看,窗口是受其控制的一部分矩形屏幕區。應用程序生成并控
制與窗口有關的一切內容,包括窗口的大小、風格、位置以及窗口內顯示的內容等。用戶打開一個應用程序后,程
序將創建一個窗口,并在那里默默地等待用戶的要求。每當用戶選擇窗口中的選項,程序即對此做出響應。
⒉程序:通常說的程序都是指一個能讓計算機識別的文件,接觸得最多的便是.exe型的可執行文件,這個不難
理解。
⒊進程:說到進程,學過《操作系統》的人都很清楚,所謂進程就是應用程序的執行實例(或稱一個執行程序)
需要注意的是:進程是程序動態的描述,而上面說到的程序是靜態的描述,兩者有本質的區別。舉個例子,從網上
Down了一個瑞星殺毒軟件到C盤但沒有運行,那個.exe 可執行文件叫做程序,它是一個二進制碼的文件。一旦雙擊
了exe文件圖標運行程序,那個“正在運行著的瑞星殺毒”便稱為進程,它在雙擊的那一刻被系統創建,當你關機
或者在任務欄的圖標上單擊鼠標右鍵選“退出”時,進程便消亡,徹底結束了生命。進程經歷了由“創建”到
“消亡”的生命期,而程序自始至終存在于你的硬盤上,不管你的機器是否啟動。
⒋線程:線程是進程中的一個執行單元,同一個進程中的各個線程對應于一組CPU指令、一組CPU寄存器以及一
堆棧。進程本來就具有動態的含義,然而實質上是通過線程來執行體現的,從這個意義上說,Windows 中進程的動
態性意義已經不是很明顯了,只算是給程序所占的
資源劃定一個范圍而已(個人觀點,純屬個人理解,不必引起爭
議!),真正具有動態性意義的是線程。以前在大二學習操作系統課的時候就有個同學跟筆者提起這點,筆者還跟
他駁得面紅耳赤呢!現在想想,覺得很有道理,不得不佩服那位同學對Windows內部機制了解得如此清楚。
之所以在此花那么多的篇幅說線程,是因為下面將要介紹到多線程編程技巧,如果不理解這點,那就很難應
用到實踐上,希望大家明白。
⒌消息:我們幾乎做每一個動作都會產生一個消息,在用鼠標指點江山的今天,鼠標被移動會產生WM_MOUSEMOVE
消息,鼠標左鍵被按下會產生WM_LBUTTONDOWN的消息,鼠標右鍵按下便產生WM_RBUTTONDOWN消息等等。所有的這些都
可以通過GetMessage,SendMessage等函數得到,以后的操作中我們會經常接觸到這些函數。
⒍事件:何謂事件?從它的字面意思我們就可以明白它的含義,如在程序運行的過程中改變窗口的大小或者移動
窗口等,都會觸發相應的“事件”。
⒎句柄:單單一個“柄”字便可以解釋它的意思了,我們天氣熱搖扇子的時候只要抓住扇柄便可以控制整個扇子
的運動了,在程序中也差不多是這個意思。通常一個句柄就可以傳遞我們所要做的事情。有經驗的讀者肯定清楚,編
寫程序總是要和各種句柄打交道的,句柄是系統用來標識不同對象類型的工具,如窗口、菜單等,這些東西在系統中
被視為不同類型的對象,用不同的句柄將他們區分開來。
看看C++ 教材中是如何給句柄下定義的:“在Win32里,句柄是指向一個無值型對象(void *)的指針,是一個4
字節長的數據”。雖然我對它的本質是什么還是很迷惑,但我知道句柄并不是一個真正意義上的指針。從結構上看,
句柄的確是一個指針,盡管它沒有指向用于存儲某個對象的內存位置(很多書都這么說,這正是我的迷惑所在),而
實際上句柄指向的是一個包含了對該對象進行的引用的位置。在編程時,只要抓住了對象的句柄就可以對該對象進行
操作了(我在《一個簡單木馬程序的編寫與偽裝策略》中說到的對QQ密碼的截獲就是要找到QQ登陸窗口的句柄后才開
始截密行動的)。下面再舉個例子來說明句柄的運用:編一個程序,使QQ登陸窗口的號碼框和密碼框均變黑,相關代
碼及解釋:
void __fastcall Tform1::formCreate(TObject *Sender)
{
HWND hCurWindow,HC,HE;//定義三個窗口句柄變量,hCurWindow用于存放QQ用戶登陸窗口的句柄,HC、HE分別存放
//號碼框和密碼框的句柄。
if((hCurWindow= FindWindow(NULL,"QQ用戶登錄"))!=0||(hCurWindow=FindWindow(NULL,"OICQ用戶登錄"))!=0)
{//很明顯,調用FindWindow()函數去獲得QQ登陸窗口的句柄
String str;
str.sprintf("0x%x",hCurWindow);
}
TCHAR wClassName[255];//類名變量
HC=GetWindow(hCurWindow, GW_CHILD);//得到號碼框的句柄
HE=GetWindow(HC, GW_HWNDNEXT);//接著得到密碼框的句柄
GetClassName(HE, wClassName, sizeof(wClassName));//得到類名
GetClassName(HC, wClassName, sizeof(wClassName));//得到類名
EnableWindow(HE,false);//使窗口失效
EnableWindow(HC,false);//使窗口失效
}
以上代碼在C++ Builder下編譯通過,只要運行次程序,QQ登陸窗口的號碼框和密碼框馬上變黑色,無非是
EnableWindow()函數所起的作用。
你還可以添加一個Timer控件,將上面的代碼copy到void __fastcall Tform1::Timer1Timer
(TObject *Sender)函數中,并在后邊加上這一句代碼:
SendMessage(hCurWindow,WM_CLOSE,0,0); 使QQ一啟動就關閉,讓別人永遠也用不了QQ,挺有趣兒的哦:).
⒏API與SDK:API是英文 Application Programming Interface 的簡稱,意為“應用程序接口”,泛指系
統為應用程序提供的一系列接口函數。其實質是程序內的一套函數調用,在編程的時候可以直接調用,而不必
知道其內部實現的過程,只知道它的原型和返回值就可以了,此外,手頭經常放著一本“Windows API大全”之
類的書也是必不可少的,不然你根本不知道哪些API是干什么用的,瞎編也編不出什么東西來。在后面我們會介
紹調用API編程的例子,調用API編程工作雖然煩瑣,但由于API函數都被封裝在dll庫里,程序只有在運行的時
候才調用的,因此程序的體積小而且運行效率高。
SDK是英文 Software Development Kit 的縮寫,指“軟件開發工具包”,在防火墻的設計中就經常涉及到
SDK。
有關基本的概念就談這些,那些C/C++的基本語法、什么是面向對象等知識請大家查閱相關的書,此類書
籍各大書店已汗牛充棟,不再多敘。下面直接談談語種和編程工具的選擇問題,這也是初學者們最迷惑的問題。
二、編程語言以及工具的選擇:
從上面的介紹我們對Windows 有了進一步的了解,現在就該開始行動了,選擇要學的語言和工具是第一步
,而且是非常重要的一步工作,筆者建議一切以簡單、易接受為原則,不然你會自信心大減的,何必偏要跟
自己過不去自討苦吃呢?
在開始的時候很多人都感到迷惑,目前的編程語言那么多,有c、c++、c#、java、匯編、html等等,究
竟學哪些好呢?最開始我該學什么呢?甚至有人將vc、c++ builder也列為兩種不同的語言!這些都是對編
程語言缺乏了解造成的。筆者開始的時候也犯過同樣的錯誤,曾經給自己寫過一份計劃書:先學c語言,接
著學c++、c#、java、匯編、vb、vc、c++ builder……,哪一種語言用多少時間去專攻等等,現在回想起
來覺得多么的可笑!只要學得精,一門就夠了。從實用的角度來講,C++ 是最好的選擇(個人意見,其實
每一種語言都很好),而VC和C++ Builder是其相應開發工具的兩大主流,筆者極力推薦初學者使用C++ Builder,
因為很容易上手,如果一下子就用VC的話,也許會打擊你的自信心:)。
三、談談促進編程能力提高的兩個途徑
如果你是一個黑客技術的狂熱者的話,到雅虎去搜索黑客教程的時候就會發現,很多的中文教程在談到如何
進行黑客編程時,十有八九都會介紹以下兩大最佳途徑:一、讀程序;二、寫程序,并且都提出了教程作者的看法
,下面我想談談這方面的個人觀點。
⒈讀程序:我將讀程序放在前面是有原因的。在你沒有閱讀過一份完整的
源代碼之前,你別指望能寫出有多好
的程序來!這是對每一位初學者的忠告也是警告,而且必須具備一定的語言基礎知識,這里的基礎知識主要是指語
法知識,最起碼要能讀懂別人的程序的每一行意思。有沒有程序的設計思想,在這個時期并不重要,只要具備一定
的語法基礎就可以了,思想可以通過閱讀完別人的源程序后分析得來。
記得在大一學習C語言的時候,我們都很重視語法的學習,整天都看教材、做練習,而且趕在老師的講課前預習,
課后又復習鞏固,將一些語法點記得滾瓜爛熟,可后來一到做課程設計的時候,坐在電腦面前簡直是老鼠拖雞蛋—
無從下手了,而且不斷的問自己:“我平時的努力哪去了?語法都會了呀,怎么還是做不出程序來?”相信很多人
都像筆者以前那樣,錯誤地以為學會了語法就等于掌握了編程。
編程的能力包括經驗、技巧、耐心等幾個因素,而并非想象中的那樣簡單,更不要以為編程就是簡簡單單的寫程序!
其實學一門語言并不需要刻意去記那些條條框框的語法,在看代碼的時候,遇到了不明白的地方再去查相關的
資料,一點一點補充基礎知識再配合源程序的思路,這時的理解才是最深刻的,我可以肯定地說,這個時候對語法
的接受程度絕對比你剛開始時的死記要強!
讀程序也不能單純地讀,要真正做到“俯而讀,昂而思”。好的代碼是百讀不厭的,比如Shotgun的那道構造
洪水Ping攻擊的代碼,我至少讀了20遍。筆者喜歡將從網上搜集來的代碼打印到紙上(盡管學校的打印費貴得要命
,打一份代碼就得花去十幾塊甚至幾十塊大洋~~~),然后邊看邊做好眉批,遇到一個新函數記下它的功能,一些
忘記了的知識在旁邊標出來,還可以寫上對程序的看法等等。特別是遇到了一些新的API函數,最好標出來,對你
以后編程的時候也許會用得著,最后別忘了分析一下程序的思路,這樣對你以后編寫類似的程序很有幫助的。
⒉寫程序:問題可談到點子上了,學那么多語言,讀那么多程序最終還不是為了寫程序,做出適合需要的軟件
來?“君子性非異也,善加于物也”,筆者認為一切從借鑒開始,先是修改別人的程序,等到有了一定的程度再寫
出屬于自己的程序。
剛開始寫程序,不要奢望一下子寫出很出色的程序來,“萬丈高樓平底起”,編程貴在動手,只要你動手去寫
了,就算只有一句“printf(“Hello!”);”也是一次進步!此外,還要依照自身的能力循序漸進地寫,開始的時候
寫一點功能簡單的、篇幅短小的代碼,力求簡潔、完整,“麻雀雖小,但五臟俱全”,然后在此基礎上進行擴充,
一點一點添加功能,下面筆者摘錄一位國內一流編程高手、“豪杰超級解霸”的作者梁肇新的編程心得,請大家看
看一個成功的程序員是如何寫程序的,希望對廣大菜鳥有所啟發:
寫程序的方法:在Win98的環境中,先寫主干,用最少的代碼實現最基本的功能。然后一點點添加功能,每加
一點都要調試。盡量少用動態分配、全局變量。充分利用操作系統直接提供的API。在Win98下調試通過之后,再
在Win95下調試通過,然后是Win97,WindowsME,WinNT4.0。這樣才能寫出穩定、快速的程序。
給程序員的建議:1、不要急于求成,這樣往往欲速不達。2、不要什么東西都想學,什么都沒掌握。3、每天
都要自我總結,分析自己的錯誤率和廢碼率,不斷加強自我管理。4、代碼格式很重要。代碼要規范、嚴謹,效率要高。
5、不要盲從簡單的開發工具(這點筆者不是很同意,最起碼要有一定的功底的人才敢這么說)。6、有了成果要公開,
不要舍不得,不然很快會過時的(以上兩段摘自《程序員》增值合訂本2001.上冊P18,請讀者前往參考)。
參考書籍:
《Windows C 程序設計》,清華大學出版社
《超級解霸梁肇新》,《程序員》合訂本
黑客編程的幾個基本技巧
以下將要談到的幾個基本技巧很重要,雖然對于編程高手來說這是在玩小孩子把戲,但對于一位初學者,掌握
以下幾個技巧將為你的編程掃清道路,而且很容易編寫出有趣的程序,培養你對編程的興趣。
技巧⒈學會修改注冊表。
相信大家都知道當瀏覽了一些網頁惡意代碼,IE標題、默認主頁等被改得面目全非,這就是通過改動注冊表來
更改系統設置的例子。Windows中的注冊表是個好東東,它是windows系統的靈魂,是許多軟件記錄數據的地方(當
然也包括windows本身)。windows通過它記錄大量的數據,然后在下一次啟動時再讀取相應的數據來設置系統。通
過控制注冊表就可以控制整個系統,所以很多的黑客程序都在注冊表上動手腳(尤其是木馬程序和作惡劇程序),
學會修改注冊表可以實現一些有趣而強大的功能。我們完全可以通過編程來操作注冊表,達到與手動更改注冊表
編輯器產生一樣的效果。“超級兔子”中的大部分功能就是通過修改注冊表來完成的。操作注冊表有專門的API函
數,大家可以參考有關資料,下面筆者以C++ Builder為例說明如何在程序中操作注冊表:
程序二:編程修改IE標題內容
新建一個工程,在Unit1.h文件中包含Registry單元:
#include
然后就可以在.cpp文件操作注冊表了,接著來!在窗體的OnCreate()里加入以下代碼(你可以在try{}里面加入
任何操作注冊表的代碼):
TRegistry* Registry;
Registry = new TRegistry();創建一個TRegistry類型的對象Registry,用于修改注冊表。
try{
Registry->RootKey = HKEY_CURRENT_USER;//設置主鍵,這是必不可少的,設置好主鍵后,就可以操作這個主
//鍵下所有的鍵值了。
if( Registry->OpenKey("Software\
Microsoft\Internet Explorer\Main",FALSE))//調用OpenKey()
//打開.
//括號里所指的鍵
{
Registry->WriteString("Window Title",”臺灣是中國的一部分,世界上只有一個中國!”);
//調用WriteString()往注冊表里寫入IE標題
Registry->CloseKey();//關閉該鍵
}
else
{//如果打開失敗的話
Registry->CreateKey("Software\Microsoft\Internet Explorer\Main");//就調用CreateKey()
//新建上述鍵
Registry->WriteString("Window Title","臺灣是中國的一部分,世界上只有一個中國!");//再寫入//IE標
//題內容
Registry->CloseKey();//最后關閉該鍵,這個也不能忽視,它跟上面的OpenKey成對使用的}//End of try
__finally
{//要是出錯,跳到這里處理
Registry->CloseKey();//關閉所要打開的鍵
delete Registry;//銷毀Registry對象,釋放資源。
}
編譯運行上面的代碼就可以將IE的標題改為“臺灣是中國的一部分,世界上只有一個中國!”了。筆者寫了個
小程序,可以測出當前的IE標題和默認主頁是什么,并可隨意修改他們,還可以禁止別人修改你的默認主頁和注冊
表編輯器.。
技巧⒉調用API編程
其實這是最簡單的,API是系統在DLL里為我們提供的程序接口,可以直接調用的。只要我們有一本《Windows
API大全》之類的書就足夠了,下面舉個簡單的例子:
程序三:調用API函數隱藏Windows的任務欄:
HWND WndHandle;//定義句柄類型變量
WndHandle=FindWindow("Shell_TrayWnd",NULL);//調用API函數FindWindow()獲得任務欄的句柄
ShowWindow(WndHandle,SW_HIDE);//再調用API函數ShowWindow()隱藏任務欄
大家看到,在上面調用API函數FindWindow()和ShowWindow()的過程中,只要我們知道函數的
名字和括號里的參數是什么就行了,至于實現的過程不必理會,也輪不到我們這些菜鳥去理會:)學會
調用API,你可以寫出功能強大的程序來,這一技巧對于初學者來說是必須掌握的(代碼請參考黑防光
盤)。
技巧⒊多線程編程技術
通過上一篇的介紹 ,大家都很清楚線程的概念了,它是進程內部的一個執行單元(如一個函數等),上期說
了那么多理論,現在該派上用場了。編寫多線程應用程序是指使程序在運行時創建多個線程并發地運行于同一個
進程中。今年6月份橫空出世的“中國黑客”病毒不是采用了全球獨創的“三線程技術”嗎?雖然筆者沒機會分析
它的樣本代碼,但此種病毒的工作效率如此之高是與它的多線程技術分不開的。
使用多線程技術編程有如下優點:
①提高CPU的利用率。由于多線程并發運行,可以使用戶在做一件事情的時候還可以做另外一件事。特別是在
多個CPU的情況下,更可以充分地利用硬件資源的優勢:將一個大任務分成幾個小任務,由不同的CPU來合作完成。
②采用多線程技術,可以設置每個線程的優先級,調整工作的進度。
清楚了使用多線程技術的優勢之后,下面便來談談如何在C++ Builder環境下開發多線程的應用程序,在C++
Builder 環境中,通過 TThread 類就可以很方便地編寫多線程應用程序(但不能直接使用,因此要派生新類),
具體流程如下:
從TThread 類派生出一個新的線程類->創建線程對象->設置線程對象的屬性項->掛起或喚醒線程(根據具體
情況操作)->結束線程。
要說明一點的是:在應用程序中要合理地設置線程的優先級。不要因為某些線程的優先級很高而使其他一些
線程因為等不到CPU的處理時間而被“餓死”,也不要因為線程的級別都差不多而導致的頻繁切換花費大量的CPU時
間。(本段引自《C++ Builder 5 編程實例與技巧》P284)。
技巧⒋讓程序實現后臺監控
這是一個很基本的技巧。如果你是一個木馬程序的愛好者,當你閱讀眾多的木馬源程序的時候,就會發現100%
的木馬程序都很注意自身的后臺監控本領,也就是隱身技術,面對不同的系統要施展不同的對策才能實現。很多殺
毒程序就采用了這種后臺監控技術,使程序隨著系統的啟動而運行,然后在后臺悄悄地監視系統的一舉一動,一發
現有不對路的程序就把它“揪”出來示眾。實現程序的后臺監控技術有如下幾個關鍵:
①正常運行時,不顯示程序的窗體;
②系統每次啟動都自動運行程序一次;
③程序圖標不顯示在任務欄上;
④不顯示在按Ctrl+Alt+Del 調出的任務列表中;
⑤通過熱鍵可以調出隱藏的窗體
實現方法:對于①,要不顯示窗體,我們可以編輯WinMain函數,設置ShowMainform值為False就可以隱藏程序
的窗體了。參考代碼:Application->ShowMainform = false ;對于②,可以利用技巧1所介紹的方法修改注冊表,
鍵值如下:HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun ,使用的是WriteString()
方法。這是冰河等多種舊木馬慣用的啟動手段之一(當然還有文件關聯、注入dll等方法);對于③,要使程序圖
標不顯示在任務欄上,也很簡單,調用API函數SetWindowLong 可以讓程序運行后不出現在任務欄里,不過要放在
窗體的OnCreate()里面。代碼如下:
SetWindowLong(Application->Handle,GWL_EXstyle,WS_EX_TOOLWINDOW);
對于④,調用RegisterServiceProcess API 函數將程序注冊成為一個服務模式程序,讓它運行在較高的優先級下,
就不會出現在程序列表中(對Win9X有效,WinNT/2000/XP下無效)。具體的代碼請參考筆者的《一個簡單木馬程序
的編寫與偽裝策略》一文,不在此重敘對于⑤,要先定義捕獲Windows消息WM_HOTKEY的鉤子函數,然后向Windows
加入一個全局原子,并保留其句柄,最后向Windows登記熱鍵,這個可以調用API函數RegisterHotKey來實現。
技巧⒌使用定時觸發器
在C++ Builder 環境下,定時觸發器即Timer控件,有時候我們希望程序隔一段時間重復執行相同的動作,比
如對QQ密碼截獲的時候,就要隔一段間隔尋找一次QQ登錄窗口。在C++ Builder中,只要將執行這些動作的代碼放
到一個Timer中去就OK了。
聽說“中國黑客”病毒運行幾分鐘后就自動創建一個新的線程,用于尋找OICQ的“發送消息”窗口,在10分
鐘內一直在找,一旦找到就將“去*****功”等帶有政治色彩的言論發送給受害者QQ上的好友,10分鐘后自動
結束該線程。我想在查找“發送消息”窗口的10分鐘內就運用了定時器,該病毒是用匯編開發的。可是在C++
Builder中是如何運用的呢?其實控件的出現使得編程變得很簡單,添加一個Timer控件,設置幾下控件的屬性,
雙擊Timer控件,將代碼放到里面去就行了。程序執行的時候,相隔指定的時間就重復執行里面的代碼了。實際
上筆者在上一期的“程序一”中尋找QQ登錄窗口時,就運用了定時器.
有關編程技巧的介紹到此為止,請讀者參考另類書籍,掌握更多的黑客編程技巧,編寫出受歡迎的黑客程序
來。
五、Socket 編程與網絡通信基礎
由于本文的主題是“黑客編程基礎”,而黑客是互連網上“來無影,去無蹤”的黑衣人,如冰河、網絡神偷等
黑客程序都是基于互連網的,談黑客編程離開網絡編程就會大失其味。所以,下面接著談談網絡編程,大凡基
于網絡應用的程序都離不開Socket。
Socket 為套接字之意,是作為計算機與計算機之間通信的接口。有關Socket的概念在第6期《黑客防線》
的《Socket 編程的基礎和基本過程》一文中有詳細的描述,請大家參考,不在此多敘。需要指出的是:Winsock
是訪問眾多的基層網絡協議的一種接口,在每個Win32平臺上,它都以不同的形式存在著,Winsock 是網絡編程的
接口,不是協議,這是容易弄錯的地方。
現在來談談Winsock 編程的過程,大凡在Win32平臺上的Winsock編程都要經過下列的基本步驟:定義變量->
獲得Winsock版本->加載Winsock庫->初始化->創建套接字->設置套接字選項->關閉套接字->卸載Winsock庫,
釋放所有資源。
下面以一道極其簡單的程序來說明如何進行Winsock編程。程序四:編一個程序來獲取本地機器的IP地址。
使用Winsock提供的API函數是最基本的網絡技術,為了給初學者看個清楚,筆者打算在Visual C++ 和
C++ Builder下各寫一個,便于大家區分這兩種不同的編程工具的特性(對于本程序來說,他們都差不多,而
對于某些通信程序,他們實現起來就相差很遠了,但本質是差不多的)。先來看Visual C++ 下的源程序,實
現步驟:打開Visual C++ ,從“File”菜單中的“New”新建一個工程,選中“Win 32 Console Application”
,意思是說生成的是Win32的控制臺程序。另外,初學者要注意一點:只要程序中用到了 Winsock API 函數,
都要在工程設置的Link 中增加 Ws2_32.lib 文件,不然程序將不能通過編譯,方法是:點擊“Project”菜單,
選擇“Settings... ALT+F7” ,在彈出的“Project Settings”對話框右側選“Link”標簽,再在“Project
Options”下方的編輯框中增加Ws2_32.lib文件,點“OK”就可以了。
加載好文件之后,就可以在CheckIP.cpp文件里加入以下代碼了:
//-------Begin from ------------
//包含需要使用的頭文件
#include "stdafx.h"
#include "windows.h"
#include
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void CheckIP(void) //定義CheckIP()函數,用于獲取本機IP地址
{
WORD wVersionRequested;// WORD類型變量,用于存放Winsock版本的正確值SADATA wsaData;
char name[255];//定義用于存放獲得的主機名的變量
CString ip;//定義IP地址變量
PHOSTENT hostinfo;
wVersionRequested = MAKEWORD( 2, 0 );
//調用MAKEWORD()獲得Winsock版本的正確值,用于下面的加載Winsock庫
if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) {
//現在是加載Winsock庫,如果WSAStartup()函數返回值為0,說明加載成功,程序可以繼續
//往下執行
if( gethostname ( name, sizeof(name)) == 0) {
//如果成功地將本地主機名存放入由name參數指定的緩沖區中
if((hostinfo = gethostbyname(name)) != NULL) {
//這是獲取主機名,如果獲得主機名成功的話,將返回一個指針,指向hostinfo,hostinfo
//為PHOSTENT型的變量,下面即將用到這個結構體
LPCSTR ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
//調用inet_ntoa()函數,將hostinfo結構變量中的h_addr_list轉化為標準的點分表示的IP
//地址(如192.168.0.1)
printf("%sn",ip);//輸出IP地址 } }
WSACleanup( );//卸載Winsock庫,并釋放所有資源 } }
int main(int argc, char* argv[])//主函數,程序的入口
{
CheckIP();//調用CheckIP()函數獲得、輸出IP地址
return 0;//由于main()定義為int型,所以應帶回一個int型的數值
}
下面接著來看看在C++ Builder 下如何實現,其實兩者的思想是一樣的,只是在C++ Builder下實現
的界面友好點而已,實現方法:打開C++ Builder 5,默認情況下已經新建一個工程,保存這個工程文件
就可以了,構造如下面圖4所示的界面,在相應之處添入下面的代碼即可。
程序代碼:
//包含頭文件
#include
#include
#pragma hdrstop
#include "Unit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
Tform1 *form1;
__fastcall Tform1::Tform1(TComponent* Owner)
: Tform(Owner)
{ }
void Tform1::GetHostIpAddress()
{// GetHostIpAddress()獲得本機IP地址
struct hostent *thisHost;
struct in_addr in;
char MyName[80];
char *ptr;
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if( err != 0 )
return;
if(LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 0 )
{ WSACleanup( );
return; }
if(gethostname(MyName,80)==SOCKET_ERROR)
return;
if(!(thisHost=gethostbyname(MyName)))
return;
memset((void *)&in,sizeof(in),0);
in.s_addr=*((unsigned long *)thisHost->h_addr_list[0]);
if(!(ptr=inet_ntoa(in)))
return;
WSACleanup( );
Edit1->Text=AnsiString(ptr);}
void __fastcall Tform1::formCreate(TObject *Sender)
{ GetHostIpAddress();}
void __fastcall Tform1::Button1Click(TObject *Sender)
{Close();//添加一個“確定”按鈕,點擊即關閉程序。}
程序在 C++ Builder 5 下編譯通過,通過比較你會發現他們是大同小異的,對于同一程序,
兩者工具各有秋千,至于選擇哪種由你決定,最好是兩者相得益彰。
“臨淵羨魚,不如退而結網”,雖說“通往電腦的路不止一條”,然而對于編程,道路卻
只有一條,就是:動手去做,親身實踐。