




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、人民郵電出版社 第7章 網(wǎng)絡(luò)程序設(shè)計入門8/25/202217.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.1什么是網(wǎng)絡(luò)應(yīng)用軟件?人們常將應(yīng)用軟件分為單機版的和網(wǎng)絡(luò)版,單機版應(yīng)用軟件就是一般程序設(shè)計語言教科書重點講述的,在單機環(huán)境下使用的軟件,這種軟件的特點是結(jié)構(gòu)簡單,易于學(xué)習(xí)與設(shè)計。另一種應(yīng)用軟件是需要安裝在網(wǎng)絡(luò)環(huán)境中使用的,網(wǎng)絡(luò)中不同主機上安裝的軟件需要進(jìn)行相互通信才能完成其功能,這就是網(wǎng)絡(luò)應(yīng)用軟件,這種軟件的特點是結(jié)構(gòu)較為復(fù)雜,軟件設(shè)計者不但要掌握程序設(shè)計的一般知識,還要掌握網(wǎng)絡(luò)系統(tǒng)的有關(guān)知識與理解網(wǎng)絡(luò)通信協(xié)議。由于計算機網(wǎng)絡(luò)的廣泛應(yīng)用,目前軟件開發(fā)的主流是設(shè)計這類網(wǎng)絡(luò)環(huán)境下的應(yīng)用軟件。7.1有
2、關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.2網(wǎng)絡(luò)中兩個通信程序如何相互識別對方在操作系統(tǒng)中我們知道,同一個系統(tǒng)中不同的兩個進(jìn)程間進(jìn)行通信時,通過系統(tǒng)分配的進(jìn)程號(process ID)就可以惟一標(biāo)識一個進(jìn)程,也就是說兩個相互通信的進(jìn)程,只要知道知識對方的進(jìn)程號就可以進(jìn)行通信。而網(wǎng)絡(luò)情況下進(jìn)程間的通信問題,就要復(fù)雜得多,不能只簡單的用進(jìn)程號來標(biāo)識不同的進(jìn)程。首先要解決如何識別網(wǎng)絡(luò)中不同的主機問題,其次因為各個主機系統(tǒng)中都獨立地進(jìn)行進(jìn)程號分配,并且不同系統(tǒng)中進(jìn)程號的產(chǎn)生與分配策略也不同,所以在網(wǎng)絡(luò)環(huán)境中不能再通過進(jìn)程號來簡單的識別兩個相互通信的進(jìn)程了。那么,在網(wǎng)絡(luò)環(huán)境中,兩個相互通信的進(jìn)程,如何識別對方呢?
3、7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.2網(wǎng)絡(luò)中兩個通信程序如何相互識別對方在網(wǎng)絡(luò)中為了標(biāo)識通信的進(jìn)程,首先要標(biāo)識網(wǎng)絡(luò)中進(jìn)程所在的主機,其次要標(biāo)識主機上不同的進(jìn)程。關(guān)于網(wǎng)絡(luò)環(huán)境下不同主機的識別問題,在講傳輸層協(xié)議時,我們知道為了完成端到端進(jìn)程之間的通信,在互聯(lián)網(wǎng)中使用IP地址來標(biāo)識不同的主機。關(guān)于主機上不同的進(jìn)程問題,在前面講端口號時已經(jīng)說明過,在網(wǎng)絡(luò)協(xié)議中使用端口號來標(biāo)識主機上的不同進(jìn)程。還有一個問題,就是前面我們討論的都是在TCP/IP協(xié)議下,端到端進(jìn)程的標(biāo)識問題,其實網(wǎng)絡(luò)應(yīng)用程序由于不同的主機可能使用不同的網(wǎng)絡(luò)協(xié)議,其工作方式不同,地址的表示格式也不同,因此,網(wǎng)絡(luò)中進(jìn)程的通信還要解決多種
4、協(xié)議的識別問題。這樣為了惟一的標(biāo)識網(wǎng)絡(luò)中通信的一個進(jìn)程(即通信的某一方)就要使用一個如下的三元組:(本地協(xié)議,本地IP地址,本地端口號)7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.2網(wǎng)絡(luò)中兩個通信程序如何相互識別對方這樣一個三元組由于它只指定了通信時一條連接的半個部分,即通信的一方,所以叫一個半相關(guān)(half-association)。如果要完整的表示網(wǎng)絡(luò)中進(jìn)行通信的兩個進(jìn)程,那么就要使用一個如下結(jié)構(gòu)的六元組:(本地協(xié)議,本地地址,本地端口號,遠(yuǎn)地協(xié)議,遠(yuǎn)地地址,遠(yuǎn)地端口號)7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.2網(wǎng)絡(luò)中兩個通信程序如何相互識別對方下面我們仔細(xì)分析一下這樣一個六元組,在互聯(lián)網(wǎng)中通
5、信的兩臺主機在網(wǎng)絡(luò)層都只能使用IP協(xié)議,但在網(wǎng)絡(luò)層之上可以選擇使用TCP協(xié)議或UDP協(xié)議。這樣就可能得到以下四種類型的相關(guān)六元組:(本地TCP協(xié)議,本地IP地址,本地端口號,遠(yuǎn)程TCP協(xié)議,遠(yuǎn)程IP地址,遠(yuǎn)程端口號)(本地UDP協(xié)議,本地IP地址,本地端口號,遠(yuǎn)程UDP協(xié)議,遠(yuǎn)程IP地址,遠(yuǎn)程端口號)(本地TCP協(xié)議,本地IP地址,本地端口號,遠(yuǎn)程UDP協(xié)議,遠(yuǎn)程IP地址,遠(yuǎn)程端口號)(本地UDP協(xié)議,本地IP地址,本地端口號,遠(yuǎn)程TCP協(xié)議,遠(yuǎn)程IP地址,遠(yuǎn)程端口號)7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.2網(wǎng)絡(luò)中兩個通信程序如何相互識別對方如果通信的兩端使用不同的協(xié)議,即上面第3和第4種情
6、況,根據(jù)前面我們所學(xué)的知識,由于TCP協(xié)議和UDP協(xié)議使用的協(xié)議格式大不相同,因此通信時雙方在傳輸層不能相互識別對方送來的數(shù)據(jù),也就不可能進(jìn)行正常的通信,因此上面說的后兩種情況是不存在的。換句話說,通信的兩個進(jìn)程在端到端的傳輸層只能使用相同的協(xié)議,因此一個完整的主機間的通信,可以簡單的用一個五元組來標(biāo)識通信的兩個進(jìn)程:(協(xié)議,本地IP地址,本地端口號,遠(yuǎn)程IP地址,遠(yuǎn)程端口號)綜上所述,這樣一個五元組可以惟一標(biāo)識網(wǎng)絡(luò)中兩個通信的進(jìn)程或一條連接,因此叫做一個相關(guān)(association)。為了在進(jìn)程間進(jìn)行正確的通信,只有兩個協(xié)議相同的半相關(guān)才能組合成一個可用的相關(guān)。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概
7、念7.1.3Windows Sockets介紹1.Windows Sockets的概念Windows Sockets顧名思義,它就是在Windows環(huán)境下使用的一套網(wǎng)絡(luò)編程機制(或規(guī)范),常常簡稱為Winsock。該規(guī)范是在上個世紀(jì)90年代初制定的。這套規(guī)范是在Windows操作系統(tǒng)下得到廣泛應(yīng)用的、開放的、支持多種協(xié)議的網(wǎng)絡(luò)編程接口。該規(guī)范從1991年的1.0版到1997年的2.2.1版,經(jīng)過不斷完善并在Intel、Microsoft、Sun、SGI、Informix、Novell等公司的大力支持下,現(xiàn)在已經(jīng)成為Windows環(huán)境下網(wǎng)絡(luò)編程事實上的標(biāo)準(zhǔn)。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1
8、.3Windows Sockets介紹2.Windows Sockets的來源Sockets本來是UNIX操作系統(tǒng)下流行的一種網(wǎng)絡(luò)編程接口(API),它是1983年在Berkeley(加州大學(xué)伯克利分校)4.2 BSD操作系統(tǒng)中被首先引入的,因此被稱為“Berkeley Socket API”。在剛開始時它只支持TCP/IP協(xié)議,后來在4.3 BSD操作系統(tǒng)中增加了對國際標(biāo)準(zhǔn)化組織ISO制定的開放系統(tǒng)互聯(lián)參考模型OSI網(wǎng)絡(luò)協(xié)議的支持。由于BSD操作系統(tǒng)做為一種主流的UNIX操作系統(tǒng)被廣泛使用,因此“Berkeley Socket API”這個模型就成了TCP/IP網(wǎng)絡(luò)的編程接口標(biāo)準(zhǔn)。從4.2
9、BSD開始,Berkeley套接口API在不斷地完善和發(fā)展,一直到1995年的4.4 BSD-Lite2為止。Windows網(wǎng)絡(luò)應(yīng)用程序編程接口Windows Sockets API就是在1991年根據(jù)4.3 BSD操作系統(tǒng)的“Berkeley Socket API”制定的。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.3Windows Sockets介紹3.Windows Sockets的版本目前常用的Winsock有兩個版本:一個是16位的Winsock 1.1,由動態(tài)鏈接庫WINSOCK.DLL提供支持;另一個是32位的Winsock 2.2,由動態(tài)鏈接庫WSOCK32.DLL提供支持。前者主
10、要用在Windows早期的版本中,如Windows 95等版本中,后者主要用在Windows2000和Windows XP等版本中。另外說明一下,本書所講的Windows下TCP/IP編程接口為Winsock 2.2,與低版本的Winsock 1.1相比它主要是擴充了對其它協(xié)議(如IPX、NETBIOS等)的支持。由于Winsock 2.2與Winsock 1.1規(guī)格中所有的函數(shù)調(diào)用完全兼容,所以低版本的Winsock應(yīng)用程序在Winsock 2庫加載的情況下也能夠正常運行。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.3Windows Sockets介紹4.Winsock API函數(shù)的分類在Win
11、sock規(guī)范中把Winsock API函數(shù)集分為與BSD Socket(用在UNIX中)相兼容的基本函數(shù)、網(wǎng)絡(luò)數(shù)據(jù)信息檢索函數(shù)和Windows專用擴展函數(shù)三類。由此可以看出,Winsock來源于BSD Socket API,但它又根據(jù)Windows操作系統(tǒng)的特點進(jìn)行了擴充。因此,Winsock規(guī)范的核心內(nèi)容是符合Berkeley Socket風(fēng)格的庫函數(shù),但為了使程序員能充分地利用Windows消息驅(qū)動機制進(jìn)行編程,也定義開發(fā)了一組針對Windows的擴展庫函數(shù)。這份規(guī)范定義了應(yīng)用程序開發(fā)者能夠使用,并且網(wǎng)絡(luò)軟件供應(yīng)商能夠?qū)崿F(xiàn)的一套庫函數(shù)調(diào)用和相關(guān)語義。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.
12、3Windows Sockets介紹5.Windows Sockets對多線程的支持Windows Sockets支持多線程的Windows進(jìn)程。一個進(jìn)程可以包含一個(在Windows 3.1非多線程版本中,一個任務(wù)對應(yīng)了一個僅具有單個線程的進(jìn)程)或多個同時執(zhí)行的線程。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.4套接口的概念Windows Sockets API依靠套接口(Socket)進(jìn)行通訊,那么什么是套接口(Socket)呢?對于初學(xué)網(wǎng)絡(luò)程序設(shè)計的人們來說,套接口是一個既抽象且又很重要的概念。因此要注意對于套接口這個概念的理解與體會。套接口可以看成是兩個網(wǎng)絡(luò)應(yīng)用程序進(jìn)行通信時,各自通信連接
13、中的一個端點,這個端點是一個邏輯上的概念。通信時其中的一個網(wǎng)絡(luò)應(yīng)用程序?qū)⒁獋鬏數(shù)囊欢涡畔懭胨谥鳈C的Socket中,該Socket通過與網(wǎng)絡(luò)接口卡(Network Interface Cards, NIC)相連的傳輸介質(zhì)將這段信息發(fā)送到另外一臺主機的Socket中,使這段信息能傳送到其他程序中,如圖7-1所示。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念程序A程序B主機A主機B網(wǎng)絡(luò)接口卡(NIC)基于TCP/IP的網(wǎng)絡(luò)網(wǎng)絡(luò)管理軟件SocketSocket圖7-1套接口通信工作原理圖7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念為了滿足不同的通信程序?qū)νㄐ刨|(zhì)量和性能的要求,一般的網(wǎng)絡(luò)系統(tǒng)提供了三種不同類型的套接口,以
14、供用戶在設(shè)計網(wǎng)絡(luò)應(yīng)用程序時根據(jù)不同的要求來選擇。這三種套接口分別是:流式套接口(SOCK_STREAM):它提供了一種可靠的、面向連接的雙向數(shù)據(jù)傳輸服務(wù)。實現(xiàn)了數(shù)據(jù)的無差錯、無重復(fù)地發(fā)送。內(nèi)設(shè)流量控制,被傳輸?shù)臄?shù)據(jù)看作是無記錄邊界的字節(jié)流。在TCP/IP協(xié)議族中,使用TCP協(xié)議來實現(xiàn)字節(jié)流的傳輸,當(dāng)用戶想要發(fā)送大批量的數(shù)據(jù),或者對數(shù)據(jù)的傳輸有較高的要求時使用流式套接口。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念數(shù)據(jù)報套接口(SOCK_DGRAM):它提供了一種無連接、不可靠的雙向數(shù)據(jù)傳輸服務(wù)。數(shù)據(jù)包以獨立的包形式被發(fā)送,并且保留了記錄邊界,不提供可靠性保證。數(shù)據(jù)在傳輸過程中可能會丟失或重復(fù),并且不能保證
15、在接收端數(shù)據(jù)按發(fā)送順序接收。在TCP/IP協(xié)議族,使用UDP協(xié)議(Winsock 2也支持其它的協(xié)議)來實現(xiàn)數(shù)據(jù)報套接口。在同一臺計算機上或負(fù)載較輕的LAN上,因為出現(xiàn)差錯的可能性較小,可以使用數(shù)據(jù)報套接口進(jìn)行數(shù)據(jù)傳輸,這樣通信的質(zhì)量可以得到保證,并且通信的效率較高。另外,在前面的章節(jié)中我們已經(jīng)說過,UDP還可以實現(xiàn)廣播通信。原始套接口(SOCK_RAW):該套接口允許對較低層協(xié)議(如IP或ICMP)進(jìn)行直接訪問。常用于檢驗新的網(wǎng)絡(luò)協(xié)議實現(xiàn),也可用于測試新配置或安裝的網(wǎng)絡(luò)設(shè)備。要說明的是Windows Sockets規(guī)范并沒有規(guī)定Windows Sockets DLL必須支持原始套接口。套接口
16、在編程時對于用戶來說是可見的,應(yīng)用程序一般僅在同一類型的套接口間通訊。不過只要底層的通訊協(xié)議允許,不同類型的套接口間也照樣可以通訊(一般很少這樣做)。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.5套接口編程原理為了便于讀者理解套接口的工作機制,我們舉一個日常生活中的例子。電話服務(wù)系統(tǒng)與面向連接的套接口機制非常相似。電信局提供的普通電話服務(wù)(比如114提供查號服務(wù)功能)類似于服務(wù)器(Server),普通電話用戶類似于客戶(Client)。比如有客戶要查某單位的電話號碼,于是就開始了一次查號的通信過程,該過程可以分為以下幾個階段(對于下面提到的函數(shù),只要知道其大概的含義就可以了,在后面將要專門介紹這些
17、函數(shù)的用法):首先電信局必須要有一個電話總機,相當(dāng)于套接口通信機制中提供服務(wù)的服務(wù)器,在Socket中通過調(diào)用socket()函數(shù)來開啟一個服務(wù),也就是說要創(chuàng)建一個提供服務(wù)的套接口。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.5套接口編程原理電信局必須給電話總機分配一個號碼(如114,意思是查號服務(wù)的號碼是114),以便用戶通過撥該號碼得到電話服務(wù),同時接入該電信局的用戶必須知道該總機的號碼。同樣,在服務(wù)器端也要為啟動的服務(wù)指定一端口號,并且要連接到該服務(wù)器的客戶必須要知道該端口號(如客戶要查詢電話號碼時,必須要知道查號臺是114)。這在Socket中通過調(diào)用bind()函數(shù)把一個端口與一個特寫服
18、務(wù)聯(lián)系起來(叫綁定)。電信局的114查號臺下會開設(shè)一些自動服務(wù)的分機,但是它們的數(shù)量是有限的??倷C開通后就一直在監(jiān)聽(listen)用戶的撥號,用戶撥打114時,可能撥通,得到服務(wù);也可能撥不通,就會聽到忙音。同樣地,我們在建立一個socket服務(wù)時,也會調(diào)用listen()函數(shù)來監(jiān)聽客戶的請求。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.5套接口編程原理對于用戶來說,如果知道電信局的查號號碼,在想得到查號服務(wù)時就可以撥打114,請求得到電信局的服務(wù),這相當(dāng)于在客戶端要進(jìn)行的操作。同樣在Socket通信中,在客戶端也要先用socket()函數(shù)建立一個請求服務(wù)的套接口,然后調(diào)connect()函數(shù)進(jìn)
19、行連接與服務(wù)器進(jìn)行連接。當(dāng)然和電話一樣,用戶可能連通得到服務(wù),也可連不通,請求的服務(wù)失敗。電信局的總機接受了某用戶撥打的電話后,負(fù)責(zé)把用戶與一個分機連通,而總機本身則又回到等待的狀態(tài),以等待其它客戶的請求。在Socket通信中這個相當(dāng)于服務(wù)器調(diào)用accept()函數(shù)進(jìn)入監(jiān)聽處理過程。服務(wù)器端建立一個新的套接口來對此連接提供服務(wù),而原先的套接口則又回到監(jiān)聽狀態(tài),等待新客戶的請求。服務(wù)器與客戶之間通信時,使用recv()函數(shù)接收套接口數(shù)據(jù),使用send()函數(shù)向套接口發(fā)送數(shù)據(jù)。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.5套接口編程原理服務(wù)完成后,掛上電話,線路斷開,一次服務(wù)過程結(jié)束,不然的話則該線路
20、一直被占用,浪費了通信資源。在服務(wù)器和客戶之間,最后也要使用closesocket()函數(shù)關(guān)閉套接口,釋放該套接口上的有關(guān)資源,這可以由通信的任何一方或雙方同時提出。上面提到的Winsock API函數(shù)是使用套接口編程時所使用的最基本的一些函數(shù),幾乎每一個使用套接口編程的網(wǎng)絡(luò)應(yīng)用程序都要使用這些函數(shù),后面我們將詳細(xì)介紹這些函數(shù)的功能和用法。用戶編寫網(wǎng)絡(luò)應(yīng)用程序時,錯誤的出現(xiàn)是不能可避免的,因此對錯誤的檢查和控制是至關(guān)重要的,一個好的或者說成功的Winsock應(yīng)用程序應(yīng)該盡可能地檢測和處理各種錯誤。由于下面我們接觸到的所有函數(shù)都有調(diào)用成功與不成功兩種情況,因此,我們打算先為大家介紹Winsock
21、中錯誤檢查和控制的方法。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.5套接口編程原理對Winsock函數(shù)來說,返回錯誤是非常常見的。與大多數(shù)系統(tǒng)調(diào)用類似,Winsock函數(shù)發(fā)生的錯誤也有兩種。多數(shù)情況下發(fā)生的錯誤都是無關(guān)緊要的,通信仍可在套接口上進(jìn)行,但有些錯誤是致命性的,使應(yīng)用程序無法繼續(xù)執(zhí)行。不成功的Winsock函數(shù)調(diào)用返回的最常見的值是宏定義SOCKET_ERROR,在Winsock的頭文件中(如Winsock 2.h),它的數(shù)值是-1。實際上,如果調(diào)用一個Winsock函數(shù)時,發(fā)生了錯誤,我們應(yīng)該進(jìn)一步使用WSAGetLastError()函數(shù),以獲得對這一錯誤詳細(xì)的說明,該函數(shù)的使用非
22、常簡單,它的格式如下:int WSAGetLastError ( void );7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.6網(wǎng)絡(luò)字節(jié)順序不同的主機對字節(jié)值的存儲順序不同。在存儲由多個字節(jié)組成的一個字時,有的計算機在起始地址處存放低整數(shù)的低序號字節(jié),這種存儲格式叫“小序在前”(little-endian)。而有的計算機在起始地址處存放整數(shù)的高序號字節(jié),這種存儲格式叫“大序在前”(big-endian)。每種計算機究竟采用那種字節(jié)存儲順序由各自的設(shè)計決定,如Windows系列的操作系統(tǒng)使用的是小序在前的存儲方式,而Sun OS和Solaris等采用的大序在前的存儲方式。在計算機中,TCP/IP協(xié)議使
23、用的16位整數(shù)(如端口號)和32位整數(shù)(如IP地址)是按計算機各自的“主機字節(jié)”(host-byte)來表示的。在網(wǎng)絡(luò)中,為了保證數(shù)據(jù)的正確性,在網(wǎng)絡(luò)通信協(xié)議中必須指定網(wǎng)絡(luò)字節(jié)順序。如果在網(wǎng)絡(luò)中使用IP地址和端口號,按“互聯(lián)網(wǎng)聯(lián)網(wǎng)標(biāo)準(zhǔn)”的要求,指定的多字節(jié)值必須用“大序在前”的形式來表示,一般稱之為“網(wǎng)絡(luò)字節(jié)”(network-byte)順序。7.1有關(guān)網(wǎng)絡(luò)程序設(shè)計的一些概念7.1.6網(wǎng)絡(luò)字節(jié)順序在Winsock中有一系列的函數(shù)可用于多字節(jié)數(shù)的轉(zhuǎn)換,把它們從主機字節(jié)順序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序,反之亦然。下面四個API函數(shù)便將一個數(shù)從主機字節(jié)順序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序:htonl():參數(shù)是主機字節(jié)順序
24、的一個4字節(jié)數(shù),函數(shù)返回網(wǎng)絡(luò)字節(jié)順序的數(shù)。WSAHtonl)():參數(shù)是主機字節(jié)順序的一個4字節(jié)數(shù),函數(shù)返回網(wǎng)絡(luò)字節(jié)順序的數(shù)。htons():參數(shù)是主機字節(jié)順序的一個2字節(jié)數(shù),函數(shù)返回網(wǎng)絡(luò)字節(jié)順序的數(shù)。WSAHtons():參數(shù)是主機字節(jié)順序的一個2字節(jié)數(shù),函數(shù)返回網(wǎng)絡(luò)字節(jié)順序的數(shù)。7.2網(wǎng)絡(luò)程序工作模型 7.2.1網(wǎng)絡(luò)程序要考慮的幾個問題網(wǎng)絡(luò)程序與單機環(huán)境下運行的程序有較大的區(qū)別,程序員在設(shè)計網(wǎng)絡(luò)程序時應(yīng)該了解與注意這些問題,才能設(shè)計出高質(zhì)量的網(wǎng)絡(luò)應(yīng)用程序。1.并發(fā)環(huán)境下的網(wǎng)絡(luò)編程我們常用的操作系統(tǒng)Windows和Linux等都支持多進(jìn)程(或線程)的并發(fā)執(zhí)行,多進(jìn)程應(yīng)用程序,由于涉及到資源共
25、享、進(jìn)程之間的同步等問題,其編程要比單進(jìn)程環(huán)境復(fù)雜得多。7.2網(wǎng)絡(luò)程序工作模型 7.2.1網(wǎng)絡(luò)程序要考慮的幾個問題在多進(jìn)程編程環(huán)境中,使用的系統(tǒng)調(diào)用或函數(shù)必須是可重入的。哪些系統(tǒng)調(diào)用或系統(tǒng)函數(shù)是可重入的,這在不同的系統(tǒng)中是不同的。一般的系統(tǒng)都會對其進(jìn)行詳細(xì)說明。在多線程應(yīng)用中,對系統(tǒng)調(diào)用或函數(shù)的使用有很多限制,因此在編程時應(yīng)該注意的是對于那些不可重入的調(diào)用或函數(shù),系統(tǒng)如果不提供多線程安全的版本,則應(yīng)用編程人員需要避免使用或自己編寫相應(yīng)的函數(shù)。例如在Solaris操作系統(tǒng)中,在一個線程中關(guān)閉另一個線程下在使用的網(wǎng)絡(luò)端口會導(dǎo)致應(yīng)用程序“死掉”,而這種情況在Digiatl Unix中則不會出現(xiàn)。7.
26、2網(wǎng)絡(luò)程序工作模型 7.2.1網(wǎng)絡(luò)程序要考慮的幾個問題2.異構(gòu)環(huán)境下的網(wǎng)絡(luò)編程在網(wǎng)絡(luò)中,通常在異構(gòu)環(huán)境下進(jìn)行程序之間的通信。因此網(wǎng)絡(luò)程序必須要考慮不同平臺之間的異構(gòu)性,這種異構(gòu)性主要表現(xiàn)在不同平臺上數(shù)據(jù)表示格式的差異性上,這種差異性主要表現(xiàn)在以下幾個方面:(1)字節(jié)順序即前一節(jié)介紹的網(wǎng)絡(luò)字節(jié)順序。作為程序員必須要清楚所用系統(tǒng)的字節(jié)順序。在網(wǎng)絡(luò)應(yīng)用程序中,傳輸?shù)耐ㄐ艛?shù)據(jù)主要包含兩個部分,一部分是分組中協(xié)議的首部,另一個部分是程序中要使用的數(shù)據(jù)。這兩個部分?jǐn)?shù)據(jù)都要考慮字節(jié)順序問題。(2)字的長度不同的系統(tǒng)中,對于相同的數(shù)據(jù)類型可能用不同的長度表示。例如在64位的操作系統(tǒng)中和32位的操作系統(tǒng)中對于l
27、ong int類型的長度表示是不一樣的。7.2網(wǎng)絡(luò)程序工作模型 7.2.1網(wǎng)絡(luò)程序要考慮的幾個問題(3)字節(jié)定界問題不同的平臺上給結(jié)構(gòu)(struct)或聯(lián)合(union)打包的方式也是不同的,這取決于所用數(shù)據(jù)類型的位數(shù)及機器的定界限制。一般情況下,操作系統(tǒng)在分配內(nèi)存時,數(shù)據(jù)結(jié)構(gòu)以4字節(jié)定界。例如,在很多系統(tǒng)中,默認(rèn)情況下結(jié)構(gòu)structchar a; int b的長度為8而不是5。只有在1字節(jié)定界的情況下其長度才為5。對于字節(jié)的定界問題,對于具有相同字節(jié)順序的平臺,通信雙方均經(jīng)單字節(jié)定界,對于具不同字節(jié)順序的平臺間通信,可以顯式的定義其格式(位數(shù)、字節(jié)順序類型),也可以將需要發(fā)送信息的結(jié)構(gòu)變換
28、成一種統(tǒng)一的格式(如轉(zhuǎn)換成一個字符數(shù)組),到達(dá)接收方后再執(zhí)行相反的轉(zhuǎn)換過程。對于數(shù)據(jù)結(jié)構(gòu)中有比特變量的情況,處理起來比較復(fù)雜,因此建議在實際網(wǎng)絡(luò)編程中,盡量不要使用比特類型的變量。另外要注意,在很多網(wǎng)絡(luò)協(xié)議的設(shè)計中,常常需要填充一些無用的字節(jié),以滿足4字節(jié)定位的要求,從而簡化協(xié)議的實現(xiàn)。7.2網(wǎng)絡(luò)程序工作模型 7.2.1網(wǎng)絡(luò)程序要考慮的幾個問題3.阻塞與非阻塞通信在網(wǎng)絡(luò)編程中,可以將通信分為阻塞與非阻塞兩種模式。在進(jìn)行網(wǎng)絡(luò)編程時,選擇通信模式也是一件很重要的事情。對于不同的協(xié)議,阻塞通信和非阻塞通信有不同的表現(xiàn)。以套接口編程為例,在阻塞模式下,利用TCP協(xié)議發(fā)送一個報文時,如果低層協(xié)議沒有可用
29、空間來存放用戶數(shù)據(jù),則應(yīng)用進(jìn)程將阻塞(即進(jìn)行等待),直到有可用的空間。而在非阻塞模式下,調(diào)用將直接返回而不需要等待。在應(yīng)用進(jìn)程調(diào)用接收函數(shù)接收報文時,如果是在阻塞模式下,若沒有到達(dá)的數(shù)據(jù),則調(diào)用將一直阻塞直到有數(shù)據(jù)到達(dá)或出錯為止,而在非阻塞模式下,將直接返回而不需要等待。對于UDP協(xié)議而言,因為UDP沒有發(fā)送緩沖,所有UDP協(xié)議即使在阻塞模式下也不會發(fā)生阻塞。7.2網(wǎng)絡(luò)程序工作模型 7.2.1網(wǎng)絡(luò)程序要考慮的幾個問題對于面向連接的協(xié)議,在連接建立階段,阻塞與非阻塞也表現(xiàn)不一樣。在阻塞模式下,如果沒有連接請求到達(dá),則等待連接調(diào)用將阻塞直到有請求到達(dá);但在非阻塞模式下,如果沒有連接請求到達(dá),等待連
30、接調(diào)用將直接返回。在連接建立階段,不管是阻塞還是非阻塞模式,發(fā)起連接請求的一方總是會使調(diào)用它的進(jìn)程阻塞,阻塞間隔最少等于到達(dá)服務(wù)器的一次往返時間。通信模式對應(yīng)用程序的設(shè)計方法也有直接的影響。在非阻塞模式下,應(yīng)用程序不斷地輪詢查看是否有數(shù)據(jù)到達(dá)或有連接請求到達(dá)。這種輪詢方式比其他技術(shù)耗費更多的CPU時間,因此要盡量避免使用這種技術(shù)。而在阻塞模式下。不存在這一問題。但是阻塞模式的缺點是進(jìn)程在執(zhí)行I/O操作時將被阻塞而不能執(zhí)行其他的工作,因此在單進(jìn)程或單線程應(yīng)用中不能使用這種模式。在多線程應(yīng)用中比較適合采用阻塞模式,一個線程被阻塞不影響其他線程的工作。7.2網(wǎng)絡(luò)程序工作模型 7.2.1網(wǎng)絡(luò)程序要考慮
31、的幾個問題另外,通信模式的選擇與操作系統(tǒng)的類型也有關(guān)系,例如在非搶占式的Windows操作系統(tǒng)中,應(yīng)用程序應(yīng)盡量不要使用阻塞模式工作。4.服務(wù)類型的選擇從通信的角度來說,網(wǎng)絡(luò)協(xié)議棧中的各層所提供的服務(wù)可以分為兩大類:面向連接服務(wù)與無連接服務(wù)。對于面向連接的通信,由于兩個對等實體為進(jìn)行數(shù)據(jù)通信要建立連接。面向連接服務(wù)的要求是:在數(shù)據(jù)交換之前,必須先建立連接;當(dāng)數(shù)據(jù)交換結(jié)束后,則應(yīng)該終止這個連接。例如,我們前面已經(jīng)介紹過,在TCP/IP協(xié)議棧中,TCP協(xié)議提供的就是這種面向連接的服務(wù)。對于在一段時間間隔內(nèi),要向同一目的地發(fā)送許多提出報文的情況,就適合使用面向連接的服務(wù)。7.2網(wǎng)絡(luò)程序工作模型 7.
32、2.2網(wǎng)絡(luò)程序工作模型使用TCP/IP協(xié)議的網(wǎng)絡(luò),其協(xié)議核心內(nèi)容在層次結(jié)構(gòu)的低三層,即網(wǎng)絡(luò)接口層、IP層和傳輸層,而這三層的功能一般是由操作系統(tǒng)內(nèi)核來實現(xiàn)的。操作系統(tǒng)為了保證其安全性和可靠性,其內(nèi)核部分一般是不能由用戶直接進(jìn)行操作和使用的,但這并不等于說用戶就不能在其應(yīng)用程序中使用TCP/IP了。那么用戶如何在網(wǎng)絡(luò)應(yīng)用程序中使用中TCP/IP協(xié)議呢?很顯然,同操作系統(tǒng)提供的其它功能一樣,用戶雖然不能直接使用操作系統(tǒng)的內(nèi)核,但操作系統(tǒng)給用戶提供了使用內(nèi)核功能的接口,用戶就可以通過系統(tǒng)功能調(diào)用等方式間接的使用這些功能。同樣,用戶可以通過系統(tǒng)提供的網(wǎng)絡(luò)應(yīng)用程序編程接口使用TCP/IP。如圖7-2所示
33、的是兩臺主機通過網(wǎng)絡(luò)編程接口,進(jìn)程間進(jìn)行通信的原理圖。7.2網(wǎng)絡(luò)程序工作模型 7.2.2網(wǎng)絡(luò)程序工作模型網(wǎng)絡(luò)應(yīng)用程序編程接口客戶應(yīng)用程序服務(wù)器應(yīng)用程序圖7-2TCP/IP應(yīng)用程序工作模型TCP/IP核心協(xié)議物理傳輸介質(zhì)物理傳輸介質(zhì)TCP/IP核心協(xié)議網(wǎng)絡(luò)應(yīng)用程序編程接口7.2網(wǎng)絡(luò)程序工作模型 7.2.2網(wǎng)絡(luò)程序工作模型圖7-2所示的是使用TCP/IP協(xié)議網(wǎng)絡(luò)的典型應(yīng)用方式,即客戶-服務(wù)器模式(見7.3節(jié)內(nèi)容)。除物理傳輸介質(zhì)外,其它的各對等層之間都要進(jìn)行虛通信,所以圖7-2中用虛線表示。從圖7-2中還可以看出,程序員不直接面對網(wǎng)絡(luò)協(xié)議進(jìn)行編程,但它通過網(wǎng)絡(luò)應(yīng)用程序編程接口間接的使用了網(wǎng)絡(luò)協(xié)議各
34、層提供的服務(wù)。這樣做的好處除了可以保證系統(tǒng)的安全可靠性外,還可以簡化網(wǎng)絡(luò)應(yīng)用程序的開發(fā)。通過圖7-2用戶還要明白一個問題,網(wǎng)絡(luò)程序設(shè)計其實是使用系統(tǒng)提供的網(wǎng)絡(luò)協(xié)議完成用戶程序的功能,也就是說在我們的網(wǎng)絡(luò)應(yīng)用程序中如何去使用網(wǎng)絡(luò)協(xié)議提供的服務(wù),而不是讓用戶去實現(xiàn)網(wǎng)絡(luò)協(xié)議各層的功能。綜上所述,用戶在進(jìn)行TCP/IP程序設(shè)計時,最關(guān)鍵的問題是要熟悉所用平臺提供的網(wǎng)絡(luò)編程界面(網(wǎng)絡(luò)編程API)。在Windows環(huán)境下的網(wǎng)絡(luò)應(yīng)用程序編程接口叫Windows Sockets,其Socket在中文資料中的譯名有好幾種,如“接口”、“插口”、“套接口”等,本書中使用各種資料中較為常用的“套接口”。7.3一個簡
35、單的客戶機/服務(wù)器程序編寫一個服務(wù)器端程序,該程序的功能是只要有客戶提出請求連接,服務(wù)器就接受連接,在連接成功后,服務(wù)器就向請求連接的客戶發(fā)送“Hello! I am a server.”的信息。如果服務(wù)器向客戶機正確發(fā)送了上述信息,則在服務(wù)器端顯示客戶機的IP地址和端口號,并輸出所發(fā)送的字節(jié)數(shù)。編寫一個客戶端程序,該程序的功能是向服務(wù)器發(fā)出連接請求,在連接成功后,接收并顯示從服務(wù)器收到的信息。該程序中通信協(xié)議使用的是面向連接的TCP協(xié)議(SOCK_STREAM,該內(nèi)容在第8章中要詳細(xì)介紹,在這里讀者只要了解該知識就可以了)。7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.1 加載協(xié)議棧(
36、WSAStartup)在使用Winsock API編制網(wǎng)絡(luò)應(yīng)用程序時,要使用大量系統(tǒng)已經(jīng)實現(xiàn)的網(wǎng)絡(luò)功能函數(shù),在調(diào)用任何一個Winsock API函數(shù)之前,都必須先檢查協(xié)議棧的安裝情況,也就是檢查系統(tǒng)中是否有Windows Sockets的實現(xiàn)庫。通過調(diào)用WSAStartup()函數(shù)便可檢測系統(tǒng)中有沒有一個或多個Windows Sockets的實現(xiàn),本函數(shù)必須是應(yīng)用程序或DLL調(diào)用的第一個Windows Sockets函數(shù),它允許應(yīng)用程序或DLL指明Windows Sockets API的版本號及獲得特定Windows Sockets實現(xiàn)的細(xì)節(jié)。應(yīng)用程序或DLL只能在一次成功的WSAStartu
37、p()調(diào)用之后,才能進(jìn)一步調(diào)用其它的Winsock API函數(shù)。7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.1 加載協(xié)議棧(WSAStartup)1.函數(shù)格式int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);2.函數(shù)參數(shù)說明WSAStartup函數(shù)有兩個參數(shù),其含義是:7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.1 加載協(xié)議棧(WSAStartup)wVersionRequested:第一個參數(shù)是一個WORD型(雙字節(jié)型)數(shù)值,它指定準(zhǔn)備在應(yīng)用程序中要使用的Winsock庫的版本號。其中用高位字節(jié)指定副版本,而
38、低位字節(jié)則指定主版本。就目前的常用的Win32平臺而言,Winsock 2庫的版本是2.2(在早期的Windows 95等版本中為Winsock 1.1)。如果需要加載Winsock 2.2版,則應(yīng)指定這個值為(0 x0202),也可使用宏MAKEWORD(X,Y),其中X為高位字節(jié),Y為低位字節(jié),如MAKEWORD(2,2)。LpWSAData:第二個參數(shù)是一個指向WSADATA結(jié)構(gòu)的指針。當(dāng)該函數(shù)被調(diào)用時,它返回關(guān)于Windows Sockets實現(xiàn)的詳細(xì)信息,該結(jié)構(gòu)的定義如下:7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.1 加載協(xié)議棧(WSAStartup)typedef str
39、uct WSADataWORD wVersion;WORD wHighVersion;Char szDescriptionWSADESCRIPTION_LEN+1;Char szSystemStatusWSASYS_STATUS_LEN+1;unsigned short iMaxSockets;unsigned short iMaxUdpDg;char FAR * lpVendorInfo; WSADATA,F(xiàn)AR *LPWSADATA;7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.1 加載協(xié)議棧(WSAStartup)該結(jié)構(gòu)各字段的含義說明如下:wVersion:調(diào)用者希望使用的Win
40、sock版本號。wHighVersion:加載的Winsock庫所支持的最高Winsock版本號,通常和第1個分量wVersion的值相同。szDescription:系統(tǒng)加載的Winsock庫的說明字符串,如“Winsock 2.0”。szSystemStatus:系統(tǒng)狀態(tài)或配置信息的說明字符串。iMaxSockets:套接口的最大編號(該字段被Winsock 2或其后的版本所忽略)。iMaxUdpDg:UDP數(shù)據(jù)報的最大容量(該字段被Winsock 2或其后的版本所忽略)。7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.1 加載協(xié)議棧(WSAStartup)lpVendorInfo:廠
41、商專有信息(該字段被Winsock 2或其后的版本所忽略)。該結(jié)構(gòu)中,WSAStartup()函數(shù)返回的比較有用的信息是wVersion和wHighVersion,這是兩個關(guān)于Winsock版本號的字段,其它字段則很少使用。其中最后3個字段在Winsock 2中只是為了保持與低版本的Winsock兼容性而保留的字段,實際已經(jīng)不使用這3個字段了。3.函數(shù)返回信息WSAStartup()函數(shù)的返回值是一個整數(shù),如果調(diào)用成功則返回0。WSAStartup()函數(shù)調(diào)用不成功時返回如下的錯誤信息:WSASYSNOTREADY:在Winsock的頭文件Winsock 2.h中,該錯誤代碼定義的數(shù)值為100
42、91,它表明加載的Winsock DLL不存在或底層的網(wǎng)絡(luò)子系統(tǒng)無法使用。7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.1 加載協(xié)議棧(WSAStartup)WSAVERNOTSUPPORTED:該代碼的數(shù)值為10092,所需的Windows Sockets API的版本未由特定的Windows Sockets實現(xiàn)提供。如果由wVersion返回的版本用戶不能接受,則要調(diào)用WSACleanup()函數(shù)清除對Winsock的加載。WSAEINVAL:該代碼的數(shù)值為10022,說明應(yīng)用程序指出的Windows Sockets版本不能被該Winsock DLL的實現(xiàn)所支持。WSAEINPROG
43、RESS:該代碼的數(shù)值為10036,說明一個阻塞的Winsock調(diào)用正在進(jìn)行中。WSAEPROCLIM:該代碼的數(shù)值為10067,說明已經(jīng)達(dá)到了Windows Sockets實現(xiàn)所支持的任務(wù)數(shù)量的極限。WSAEFAULT:該代碼數(shù)值為10014,說明lpWSAData參數(shù)是一個無效的指針。7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.2創(chuàng)建套接口(socket或WSASocket)應(yīng)用程序在使用套接口通信之前,必須要擁有一個套接口。在Winsock中,要使用Socket()或WSASocket()函數(shù)來給一個網(wǎng)絡(luò)應(yīng)用程序創(chuàng)建一個套接口。函數(shù)格式在Winsock 1中提供的格式是:SOCK
44、ET socket(int af,int type,int protocol);7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.2創(chuàng)建套接口(socket或WSASocket)在Winsock 2中提供的擴展格式是:SOCKET WSASocket(int af,int type,int protocol,LPWSAPROTOCOL_INFO lpProtocolInfo,Group g,int iFlags);7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.3地址綁定(bind)當(dāng)用socket()創(chuàng)建了一個套接口后,該套接口還是不能直接使用的,因為它只存在于一個名字空間(地址族)中
45、,也就是說它只確定了通信所希望使用的服務(wù)類型,并沒有與該主機上提供服務(wù)的某端口聯(lián)系在一起,這樣的套接口可以叫未命名的套接口。bind()函數(shù)通過給一個未命名的套接口分配一個本地名字,來為套接口建立本地綁定(即把一個套接口與一個主機地址和端口號聯(lián)系起來)。本函數(shù)適用于數(shù)據(jù)報或流類套接口。函數(shù)格式int bind(SOCKET s,const struct sockaddr FAR* name,int namelen);7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.4服務(wù)器端監(jiān)聽連接(listen)當(dāng)在一個服務(wù)器端程序中,用socket()函數(shù)成功創(chuàng)建了一個套接口,并用bind()函數(shù)和一個
46、指定的地址關(guān)聯(lián)(即綁定)在一起后,就要指示該套接口進(jìn)入監(jiān)聽連接請求的狀態(tài),可以接收由客戶端發(fā)出的連接請求,這時就要用Winsock API函數(shù)listen()。函數(shù)格式int listen(SOCKET s,int backlog);7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.5客戶端請求連接(connect或WSAConnect)當(dāng)服務(wù)器端建立好套接口并與一個本地地址綁定后,就進(jìn)入監(jiān)聽狀態(tài),等待客戶發(fā)出連接請求,從而為客戶提供服務(wù)。在客戶端當(dāng)套接口建立好之后,就要調(diào)用connect()函數(shù),提出與一個服務(wù)器建立連接的請求,如果服務(wù)器接受請求,就可以在服務(wù)器的遠(yuǎn)程套接口與客戶端的本地套接口之間建立一條連接。函數(shù)格式在Winsock 1中提供的格式是:int connect(SOCKET s,const struct sockaddr FAR* name,int namelen);7.4Winsock中建立連接的函數(shù)及其應(yīng)用7.4.6服務(wù)器端接受連接(accept或WSAAccept)在服務(wù)器端通過listen()函數(shù)調(diào)用表示服務(wù)器進(jìn)入監(jiān)聽客戶的連接請求狀態(tài),而在服務(wù)器端調(diào)用accept()函數(shù)表示可以接收來自客戶端由connect()發(fā)出的
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 疏干井與降水井施工方案
- 混合開發(fā)模式探索-深度研究
- 阿比朵爾膠囊合成工藝優(yōu)化-深度研究
- 資產(chǎn)設(shè)備管理工作總結(jié)
- ICU常用藥物課件
- 2025-2030中國停車場模型RV行業(yè)市場現(xiàn)狀供需分析及投資評估規(guī)劃分析研究報告
- 2025-2030中國保溫材料檢測行業(yè)市場發(fā)展現(xiàn)狀及供給需求與前景趨勢研究報告
- 2025-2030中國便攜式紫外線燈行業(yè)市場現(xiàn)狀分析及競爭格局與投資發(fā)展研究報告
- 2025-2030中國便攜式交流行業(yè)市場發(fā)展趨勢與前景展望戰(zhàn)略研究報告
- 2025-2030中國體重管理行業(yè)市場發(fā)展趨勢與前景展望戰(zhàn)略研究報告
- 舊設(shè)備安全拆除施工方案范本
- 居住區(qū)規(guī)劃設(shè)計案例分析1535793655
- 廣東省通用安裝工程綜合定額(2018)Excel版
- 思想道德與法治2023版教學(xué)設(shè)計第二章 追求遠(yuǎn)大理想 堅定崇高信念
- 華南理工大學(xué)碩士論文格式模板
- 電子商務(wù)概論目錄
- 裝修返工合同
- 直流濾波電感設(shè)計
- 消力池砼施工工法
- 電力工程安全保證體系及措施
- 國家職業(yè)類別1-6類明細(xì)表
評論
0/150
提交評論