通信網(wǎng)絡(luò)程序的設(shè)計(jì)第6章-TCP-IP網(wǎng)絡(luò)編程課件_第1頁
通信網(wǎng)絡(luò)程序的設(shè)計(jì)第6章-TCP-IP網(wǎng)絡(luò)編程課件_第2頁
通信網(wǎng)絡(luò)程序的設(shè)計(jì)第6章-TCP-IP網(wǎng)絡(luò)編程課件_第3頁
通信網(wǎng)絡(luò)程序的設(shè)計(jì)第6章-TCP-IP網(wǎng)絡(luò)編程課件_第4頁
通信網(wǎng)絡(luò)程序的設(shè)計(jì)第6章-TCP-IP網(wǎng)絡(luò)編程課件_第5頁
已閱讀5頁,還剩182頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、第6章 TCP/IP網(wǎng)絡(luò)編程6.1 TCP/IP協(xié)議概述6.3 TCP編程6.4 UDP編程6.5 組播編程6.6 WinSock I/O模型小結(jié)基于TCP/IP協(xié)議的網(wǎng)絡(luò)程序是當(dāng)前網(wǎng)絡(luò)通信的主要方式,TCP/IP協(xié)議目前也處于鼎盛時(shí)期。隨著TCP/IP由IPv4向IPv6過渡,可以預(yù)見,這種通信協(xié)議還會(huì)使用很長(zhǎng)時(shí)間。因此,基于TCP/IP協(xié)議的編程方法也是本書所介紹的重點(diǎn)內(nèi)容之一。本章首先簡(jiǎn)要地介紹TCP/IP協(xié)議的基本內(nèi)容,然后介紹TCP/IP在Windows操作系統(tǒng)下網(wǎng)絡(luò)編程的重要編程接口WinSock,基于WinSock進(jìn)行TCP/IP傳輸層兩種通信方式(即TCP和UDP)的編程,接著

2、介紹基于WinSock的TCP/IP組播編程。為了使網(wǎng)絡(luò)編程更加具有靈活性,本章介紹了三種I/O控制方法。6.1.1 基本概念TCP/IP(Transmission Control Protocol/Internet Protocol,傳輸控制協(xié)議/網(wǎng)際協(xié)議)是一系列協(xié)議,或者說是一個(gè)協(xié)議族,它定義了數(shù)據(jù)傳輸如何通過因特網(wǎng)進(jìn)行交換。TCP/IP起源于20世紀(jì)60年代末美國(guó)政府資助的一個(gè)分組交換網(wǎng)絡(luò)研究項(xiàng)目,到20世紀(jì)90年代已發(fā)展成為計(jì)算機(jī)之間最常用的組網(wǎng)協(xié)議。6.1 TCP/IP協(xié)議概述TCP/IP允許分布在各地安裝著完全不同系統(tǒng)的計(jì)算機(jī)互相通信,是一個(gè)真正的開放系統(tǒng)。TCP/IP是根據(jù)它最

3、主要的兩個(gè)協(xié)議命名的,已經(jīng)實(shí)際應(yīng)用了許多年,并在世界范圍內(nèi)證明了它的有效性。1協(xié)議棧結(jié)構(gòu)TCP/IP模型進(jìn)一步提煉與合并了OSI模型,它取消了OSI模型中的表示層和會(huì)話層,并合并了數(shù)據(jù)鏈路層和物理層(由于主要與連接有關(guān)并依賴于闡述介質(zhì),因此TCP/IP參考模型實(shí)際上對(duì)物理層并沒有定義),使得邏輯更加簡(jiǎn)潔明晰,在此基礎(chǔ)上逐步實(shí)現(xiàn)了各種子協(xié)議。TCP/IP模型與OSI模型的比較如圖6-1所示。TCP/IP模型每一層所負(fù)責(zé)的功能如下:鏈路層:有時(shí)被稱做數(shù)據(jù)鏈路層或網(wǎng)絡(luò)接口層,通常包括操作系統(tǒng)中的設(shè)備驅(qū)動(dòng)程序和計(jì)算機(jī)中對(duì)應(yīng)的網(wǎng)絡(luò)接口卡,它們一起處理與電纜(或其他任何傳輸媒介)的物理接口細(xì)節(jié)。網(wǎng)絡(luò)層:有

4、時(shí)也被稱為互連網(wǎng)層,負(fù)責(zé)分組在網(wǎng)絡(luò)中的活動(dòng),包括IP(網(wǎng)際協(xié)議)、ICMP(Internet互聯(lián)網(wǎng)控制報(bào)文協(xié)議)以及IGMP(Internet組管理協(xié)議)。這一層TCP/IP有兩個(gè)基本組件:一個(gè)是IP協(xié)議,另一個(gè)是路由協(xié)議。圖6-1 TCP/IP模型與OSI模型的比較傳輸層:該層主要為兩臺(tái)主機(jī)上的應(yīng)用程序提供端到端的數(shù)據(jù)通信,它分為兩個(gè)不同的協(xié)議,即TCP(傳輸控制協(xié)議)和UDP(用戶數(shù)據(jù)報(bào)協(xié)議)。TCP提供端到端的保證質(zhì)量的數(shù)據(jù)傳輸,該層負(fù)責(zé)數(shù)據(jù)的分組、質(zhì)量控制和超時(shí)重發(fā)等,對(duì)于應(yīng)用層來說,就可以忽略這些工作。UDP則只簡(jiǎn)單地把數(shù)據(jù)報(bào)從一端發(fā)送到另一端,至于數(shù)據(jù)是否到達(dá)或按時(shí)到達(dá)、數(shù)據(jù)是否損

5、壞,這都必須由應(yīng)用層來做。這兩種協(xié)議各有用途,前者可用于面向連接的應(yīng)用,而后者則在及時(shí)性服務(wù)中有著重要的用途,如網(wǎng)絡(luò)多媒體通信等。應(yīng)用層:該層負(fù)責(zé)處理實(shí)際的應(yīng)用程序細(xì)節(jié),包括Telnet、HTTP、SMTP、FTP、DNS和SNMP等協(xié)議和應(yīng)用。層與層之間的聯(lián)系與邏輯分離是利用封裝與分用過程分別實(shí)現(xiàn)的。2協(xié)議封裝當(dāng)應(yīng)用程序傳送數(shù)據(jù)時(shí),數(shù)據(jù)按自上而下的方向被送入?yún)f(xié)議棧中,然后逐個(gè)通過每一層直到被當(dāng)做一串比特流送入網(wǎng)絡(luò)。其中,每一層對(duì)收到的上一層數(shù)據(jù)都要增加一些首部信息(有時(shí)還要增加尾部信息),通過層層包裹完成數(shù)據(jù)的封裝過程,使之適合網(wǎng)絡(luò)傳輸,這相當(dāng)于完成了1.1.2節(jié)提及的數(shù)字通信中的信道編碼。

6、以應(yīng)用程序通過TCP協(xié)議傳輸數(shù)據(jù)為例,該過程如圖6-2所示。圖6-2 應(yīng)用程序通過TCP協(xié)議傳輸數(shù)據(jù)封裝過程用戶數(shù)據(jù)首先被添加應(yīng)用首部,傳給TCP層;在TCP層,數(shù)據(jù)被再安裝TCP首部后,傳給IP層(TCP傳給IP的數(shù)據(jù)單元稱作TCP報(bào)文段或簡(jiǎn)稱為TCP段);在IP層,數(shù)據(jù)被再次安裝IP首部后,傳給鏈路層(IP傳給網(wǎng)絡(luò)接口層的數(shù)據(jù)單元稱作IP數(shù)據(jù)報(bào));在鏈路層,數(shù)據(jù)再被安裝以太網(wǎng)首部,并添加以太網(wǎng)尾部,形成適合網(wǎng)絡(luò)(光、電信號(hào))傳輸?shù)臄?shù)據(jù)比特流,該比特流稱做幀(Frame)。讀者可能對(duì)首部和尾部的概念還不太了解。實(shí)際上,首部和尾部是一種協(xié)議指定的數(shù)據(jù)結(jié)構(gòu),按照一定的順序規(guī)則填寫數(shù)據(jù)。關(guān)于各種首

7、部中的字段含義、用途將在后面章節(jié)進(jìn)行詳細(xì)介紹。3協(xié)議分用網(wǎng)絡(luò)接口分別發(fā)送和接收IP、ARP和RARP數(shù)據(jù)。IP層接口負(fù)責(zé)發(fā)送ICMP、IGMP、TCP、UDP數(shù)據(jù)包,因此必須在以太網(wǎng)的幀首部、IP特定字段中加入某種形式的標(biāo)識(shí),以指明生成數(shù)據(jù)的網(wǎng)絡(luò)協(xié)議。例如:以太網(wǎng)的幀首部有一個(gè)16bit的幀類型域,當(dāng)目的主機(jī)收到一個(gè)以太網(wǎng)數(shù)據(jù)幀時(shí),數(shù)據(jù)就開始從協(xié)議棧中由底向上升,同時(shí)去掉各層協(xié)議上加的報(bào)文首部。每層協(xié)議都要檢查報(bào)文協(xié)議標(biāo)識(shí),以確定接收數(shù)據(jù)的上層協(xié)議。這個(gè)過程稱做分用(Demultiplexing),它解決了數(shù)據(jù)包接收時(shí)協(xié)議解析的問題,從而保證了各種不同的TCP/IP子協(xié)議能夠被組合成一個(gè)整體(

8、圖6-3顯示了該過程)。圖6-3 TCP/IP協(xié)議分用過程6.1.2 常用協(xié)議如前所述,TCP/IP協(xié)議是一個(gè)協(xié)議族,下面對(duì)常用的協(xié)議分別進(jìn)行介紹。1MAC協(xié)議MAC(Media Access Control,媒體訪問控制)協(xié)議最重要的功能是確定誰占有信道,即信道分配問題,其主要作用是保證信道的公平性和有效的資源共享。MAC的機(jī)制分為兩類,即基于競(jìng)爭(zhēng)的信道協(xié)議和無競(jìng)爭(zhēng)的信道協(xié)議。基于競(jìng)爭(zhēng)的信道協(xié)議是假定網(wǎng)絡(luò)中沒有中心實(shí)體來分配信道資源,每個(gè)節(jié)點(diǎn)必須通過競(jìng)爭(zhēng)媒體資源來進(jìn)行傳送,當(dāng)超過一個(gè)節(jié)點(diǎn)同時(shí)嘗試發(fā)送時(shí),碰撞就會(huì)發(fā)生(見7.1.1節(jié)所介紹的CSMA/CD協(xié)議)。相反,無競(jìng)爭(zhēng)的信道協(xié)議為每個(gè)需要

9、通信的節(jié)點(diǎn)分配專用的信道資源。無競(jìng)爭(zhēng)的信道協(xié)議能夠有效地減少?zèng)_突,其代價(jià)是突發(fā)數(shù)據(jù)業(yè)務(wù)的信道利用率可能會(huì)比較低。不同的傳輸介質(zhì)決定了所使用的MAC標(biāo)準(zhǔn),如:以太網(wǎng)遵循IEEE 802.3標(biāo)準(zhǔn),令牌總線遵循IEEE 802.4標(biāo)準(zhǔn),令牌環(huán)網(wǎng)遵循IEEE 802.5標(biāo)準(zhǔn),等等。本書重點(diǎn)關(guān)心的IEEE 802.3標(biāo)準(zhǔn)定義了一種具有七個(gè)字段的MAC幀,包括:前導(dǎo)符P、幀起始分界符SFD、目的地址DA、源地址SA、表示數(shù)據(jù)字段字節(jié)數(shù)長(zhǎng)度的字段LEN、要發(fā)送的數(shù)據(jù)字段、填充字段PAD和幀校驗(yàn)序列FCS等8個(gè)字段,這8個(gè)字段中除了數(shù)據(jù)字段和填充字段外,其余的長(zhǎng)度都是固定的。圖6-4就是以太網(wǎng)幀的結(jié)構(gòu),其首部

10、由5個(gè)字段組成,包括前導(dǎo)符、起始幀分界符、目標(biāo)地址、源地址、長(zhǎng)度/類型構(gòu)成;尾部由一個(gè)字段構(gòu)成(CRC);上層協(xié)議的首部及數(shù)據(jù)夾在首部與尾部之間的數(shù)據(jù)字段里。圖6-4 以太網(wǎng)幀結(jié)構(gòu)這里使用的地址無論是DA還是SA,都是硬件地址,或稱為MAC地址。MAC地址由網(wǎng)卡的生產(chǎn)廠商唯一設(shè)定給每一塊不同的網(wǎng)卡。一塊網(wǎng)卡依據(jù)數(shù)據(jù)幀的包頭信息中是否寫有它的MAC地址來決定是否接受并上傳該幀。查閱本機(jī)MAC地址的方法很多,如Windows的ipcongfig命令、NetBIOS的Astatus命令等。需要注意的是,IEEE 802.3標(biāo)準(zhǔn)的MAC幀不提供任何對(duì)收到的幀進(jìn)行確認(rèn)的機(jī)制,其通信確認(rèn)在高層完成,這表明

11、它是一種不可靠的介質(zhì)。以太網(wǎng)MAC協(xié)議承載了其他TCP/IP上層子協(xié)議。2IP協(xié)議IP協(xié)議負(fù)責(zé)在TCP/IP主機(jī)之間提供數(shù)據(jù)報(bào)服務(wù),進(jìn)行數(shù)據(jù)封裝,產(chǎn)生協(xié)議頭。由于在以太網(wǎng)中幀的大小受限制,并且不同的幀可能由不同的網(wǎng)絡(luò)路徑傳送,因此IP協(xié)議需要將較大的數(shù)據(jù)報(bào)文分割,并在目的主機(jī)處按正確順序組合。另外,IP協(xié)議不負(fù)責(zé)包的校驗(yàn),它是一種無連接、不可靠的傳輸。如果發(fā)生任何錯(cuò)誤,IP協(xié)議則丟棄該數(shù)據(jù)報(bào),然后發(fā)送ICMP消息報(bào)給信源端。數(shù)據(jù)報(bào)的檢測(cè)校驗(yàn)是由上層協(xié)議如TCP等提供的。無連接數(shù)據(jù)報(bào)并不維護(hù)任何關(guān)于后續(xù)數(shù)據(jù)報(bào)的狀態(tài),每個(gè)數(shù)據(jù)報(bào)的處理是相互獨(dú)立的,即IP數(shù)據(jù)報(bào)可以不按發(fā)送順序接收。IP協(xié)議還需要負(fù)

12、責(zé)尋找路由,因此它需要配一個(gè)確定的IP地址。在IP報(bào)文的包頭中包含了源與目的的IP地址。一般來說,不會(huì)有應(yīng)用程序直接訪問IP協(xié)議。IP數(shù)據(jù)報(bào)是Internet上數(shù)據(jù)通信的基本單元,這些數(shù)據(jù)報(bào)不超過1000字節(jié)長(zhǎng),當(dāng)人們打開Web頁、下載文件或者發(fā)送E-mail時(shí),這些數(shù)據(jù)報(bào)就在世界各地來回傳輸。IP協(xié)議包裹的協(xié)議有:ARP、RAPRP、ICMP、IGMP、路由協(xié)議。網(wǎng)絡(luò)互聯(lián)的目的是提供一個(gè)無縫的通信系統(tǒng),為此,互聯(lián)網(wǎng)協(xié)議必須屏蔽物理網(wǎng)絡(luò)的具體細(xì)節(jié),并提供一個(gè)虛擬網(wǎng)絡(luò)的功能,使設(shè)計(jì)者可以在不考慮物理硬件細(xì)節(jié)的情況下自由地選擇地址。在TCP/IP棧中,編址由IP協(xié)議規(guī)定,IP標(biāo)準(zhǔn)分配給每臺(tái)主機(jī)一個(gè)

13、32位的二進(jìn)制數(shù)作為該主機(jī)的IP地址。在2019年6月即將正式投入運(yùn)行的IPv6中,IP地址升至128位,這樣IP資源變得更加豐富。IP協(xié)議將每個(gè)IP地址分割成前綴和后綴兩部分。前綴用于確定計(jì)算機(jī)從屬的物理網(wǎng)絡(luò),后綴則用于確定網(wǎng)絡(luò)上一臺(tái)單獨(dú)的計(jì)算機(jī)?;ヂ?lián)網(wǎng)中的每一個(gè)物理網(wǎng)絡(luò)都有一個(gè)唯一的值作為網(wǎng)絡(luò)號(hào)(Network Number)。IP地址的層次性設(shè)計(jì)保證了以下兩個(gè)重要性質(zhì):每臺(tái)計(jì)算機(jī)分配一個(gè)唯一的地址;網(wǎng)絡(luò)號(hào)分配全球統(tǒng)一,但后綴可本地分配,無需全球統(tǒng)一。IP地址共分五類:A類、B類、C類、D類和E類。其中,A類、B類和C類為基本類;D類用于多播傳送;E類屬于保留類,現(xiàn)在不用。這種地址分配方法

14、的優(yōu)點(diǎn)是,通過判斷從左到右第一個(gè)0出現(xiàn)的位置就可以區(qū)分地址類型。它們的格式如表6-1所示(其中,*代表網(wǎng)絡(luò)號(hào)位數(shù),X代表主機(jī)號(hào)位數(shù))。表6-1 IP地址分類IP地址一般采用點(diǎn)分十進(jìn)制的方法表示,例如10000001 00110100 00000110 00000000。此外,需要特別注意以下幾個(gè)特殊的IP地址:(1) 網(wǎng)絡(luò)地址:IP中主機(jī)地址為0,表示網(wǎng)絡(luò)地址,如。(2) 廣播地址:網(wǎng)絡(luò)號(hào)后跟一個(gè)所有位全是1的后綴,即直接廣播地址。(3) 回送地址:用于測(cè)試。(4) 內(nèi)網(wǎng)地址:B類地址中的55、55,C類地址中的55等三個(gè)地址段內(nèi)的IP習(xí)慣上經(jīng)常作為內(nèi)部網(wǎng)絡(luò)地址使用。除了給每個(gè)主機(jī)分配一個(gè)IP

15、地址外,IP協(xié)議也規(guī)定給每個(gè)路由器分配IP地址。事實(shí)上,每個(gè)路由器會(huì)被分配了兩個(gè)或更多個(gè)IP地址。一個(gè)路由器連接到多個(gè)物理網(wǎng)絡(luò),每一個(gè)IP地址包含一個(gè)特定物理網(wǎng)絡(luò)的網(wǎng)絡(luò)號(hào)。這個(gè)IP地址并不標(biāo)識(shí)一臺(tái)特定的計(jì)算機(jī),而是標(biāo)識(shí)一臺(tái)計(jì)算機(jī)和一個(gè)網(wǎng)絡(luò)間的一個(gè)連接?,F(xiàn)在所有的主機(jī)都要求支持子網(wǎng)編址(RFC950,J.Mogul and J.Postel,1985),該功能要求,不僅要把IP地址看成由單純的一個(gè)網(wǎng)絡(luò)號(hào)和一個(gè)主機(jī)號(hào)組成,還要把主機(jī)號(hào)再分成一個(gè)子網(wǎng)號(hào)和主機(jī)號(hào)。這樣做是因?yàn)锳類和B類地址為主機(jī)號(hào)分配了太多空間,但事實(shí)上在一個(gè)網(wǎng)絡(luò)中并不會(huì)有這么多主機(jī),因此在NIC(Network Informatio

16、n Center)獲得某個(gè)IP網(wǎng)絡(luò)號(hào)后,就由系統(tǒng)管理員來決定是否建立子網(wǎng),以及分配多少位給子網(wǎng)號(hào)和主機(jī)號(hào)。例如,這里有一個(gè)B類地址(),在剩下的16位中,8位用于子網(wǎng)號(hào),8位用于主機(jī)號(hào),其格式如圖6-5所示。這樣就允許有254個(gè)子網(wǎng),每個(gè)子網(wǎng)可有254臺(tái)主機(jī)。圖6-5 B類地址的子網(wǎng)編址舉例除了地址類型以外,主機(jī)還需要知道地址中分別有多少位用于子網(wǎng)號(hào)與主機(jī)號(hào)。這是在引導(dǎo)過程中由子網(wǎng)掩碼所確定的。這個(gè)掩碼是一個(gè)32位的值,其中值為1的位留給網(wǎng)絡(luò)號(hào)和子網(wǎng)號(hào),為0的位留給主機(jī)號(hào)。在上面的例子中,子網(wǎng)掩碼就是。通常規(guī)定,具有相同網(wǎng)絡(luò)號(hào)的主機(jī)屬于網(wǎng)內(nèi)關(guān)系,不同網(wǎng)絡(luò)號(hào)的主機(jī)屬于網(wǎng)間關(guān)系。IP協(xié)議包裹或承載

17、了ARP/RARP、ICMP、IGMP、OSPF等TCP/IP子協(xié)議。3ARP/RARP協(xié)議ARP(Address Resolution Protocol,地址解析協(xié)議)和RARP(Reverse Address Resolution Protocol,逆向地址解析協(xié)議)是某些網(wǎng)絡(luò)接口(如以太網(wǎng)和令牌環(huán)網(wǎng))使用的特殊協(xié)議,用來轉(zhuǎn)換IP層和MAC層使用的地址。由于IP地址只對(duì)TCP/IP有效,MAC地址只對(duì)網(wǎng)絡(luò)訪問層有意義,因此分配給主機(jī)使用的IP地址和它固有的MAC地址是互不相干的。在物理網(wǎng)絡(luò)上的數(shù)據(jù)幀交換依賴于MAC地址,而在網(wǎng)絡(luò)層層面的IP地址賦予用戶設(shè)定邏輯地址的權(quán)利,要使二者配合工作必

18、須進(jìn)行正確的轉(zhuǎn)換。ARP實(shí)現(xiàn)了從IP地址到MAC地址的映射,而RARP負(fù)責(zé)根據(jù)NIC硬件地址去查詢對(duì)應(yīng)的IP地址。ARP要求網(wǎng)絡(luò)接口有一個(gè)硬件地址。在硬件上進(jìn)行的數(shù)據(jù)幀交換必須要有正確的接口地址。TCP/IP的地址是32位的IP地址。僅知道主機(jī)的IP地址并不能讓內(nèi)核(如以太網(wǎng)驅(qū)動(dòng)程序)發(fā)送數(shù)據(jù)幀給主機(jī),內(nèi)核必須知道目的端的硬件地址才能發(fā)送數(shù)據(jù)。假設(shè)在一個(gè)以太網(wǎng)中,客戶端要將一個(gè)IP報(bào)文發(fā)送到服務(wù)器端,那么客戶端就必須把32位的IP地址轉(zhuǎn)換成48位的以太網(wǎng)地址。ARP獲取IP的過程可分為以下三個(gè)步驟:(1) ARP以廣播的方式發(fā)送ARP Request數(shù)據(jù)幀給以太網(wǎng)的每個(gè)主機(jī)。ARP請(qǐng)求數(shù)據(jù)幀中

19、包含目的主機(jī)的IP地址,意思是“如果你是這個(gè)IP地址的擁有者,請(qǐng)回答你的硬件地址”。(2) 目的主機(jī)的ARP層收到這份廣播報(bào)文后,識(shí)別出這是發(fā)送端在詢問它的IP地址,于是發(fā)送一個(gè)ARP應(yīng)答。這個(gè)ARP應(yīng)答包含IP地址及對(duì)應(yīng)的硬件地址。(3) 發(fā)送端收到ARP應(yīng)答后,主機(jī)間通過使用ARP協(xié)議獲得的硬件地址進(jìn)行通信。ARP中規(guī)定了兩種信息的基本類型:請(qǐng)求(Request)和應(yīng)答(Response)。在以太網(wǎng)上解析IP地址時(shí),ARP請(qǐng)求和應(yīng)答分組的格式如附錄4中的附表4-6所示(ARP亦可用于解析其他類型網(wǎng)絡(luò)的IP地址以外的地址,緊跟著幀類型字段的前四個(gè)字段決定了最后四個(gè)字段的類型和長(zhǎng)度)。4ICM

20、P協(xié)議ICMP(Internet Control Message Protocol)是Internet控制報(bào)文協(xié)議。它是TCP/IP協(xié)議族的一個(gè)子協(xié)議,用于在IP主機(jī)、路由器之間傳遞控制消息??刂葡⑹侵妇W(wǎng)絡(luò)通不通、主機(jī)是否可達(dá)、路由是否可用等網(wǎng)絡(luò)本身的消息。這些控制消息雖然并不傳輸用戶數(shù)據(jù),但是對(duì)于用戶數(shù)據(jù)的傳遞起著至關(guān)重要的作用。ICMP協(xié)議是一種面向非連接的協(xié)議,用于傳輸出錯(cuò)報(bào)告控制信息。它是一個(gè)非常重要的協(xié)議,對(duì)網(wǎng)絡(luò)安全具有極其重要的意義。它是TCP/IP協(xié)議族的一個(gè)子協(xié)議,屬于網(wǎng)絡(luò)層協(xié)議,主要用于在主機(jī)與路由器之間傳遞控制信息,包括報(bào)告錯(cuò)誤、交換受限控制和狀態(tài)信息等。當(dāng)遇到IP數(shù)據(jù)無

21、法訪問目標(biāo)、IP路由器無法按當(dāng)前的傳輸速度轉(zhuǎn)發(fā)數(shù)據(jù)包等情況時(shí),IP路由器會(huì)自動(dòng)發(fā)送ICMP消息。ICMP提供一致易懂的出錯(cuò)報(bào)告信息。發(fā)送的出錯(cuò)報(bào)文返回到發(fā)送原數(shù)據(jù)的設(shè)備,因?yàn)橹挥邪l(fā)送設(shè)備才是出錯(cuò)報(bào)文的邏輯接受者。發(fā)送設(shè)備隨后可根據(jù)ICMP報(bào)文確定發(fā)生錯(cuò)誤的類型,并確定如何才能更好地重發(fā)失敗的數(shù)據(jù)報(bào)。但是ICMP唯一的功能是報(bào)告問題而不是糾正錯(cuò)誤,糾正錯(cuò)誤的任務(wù)由發(fā)送方完成。5IGMP協(xié)議Internet 組管理協(xié)議(IGMP)是因特網(wǎng)協(xié)議家族中的一個(gè)組播協(xié)議,用于 IP 主機(jī)向任一個(gè)直接相鄰的路由器報(bào)告它們的組成員情況。IGMP信息封裝在IP報(bào)文中,其IP的協(xié)議號(hào)為2,用來在IP主機(jī)和與其直接

22、相鄰的組播路由器之間建立、維護(hù)組播組成員關(guān)系。IGMP不包括組播路由器之間的組成員關(guān)系信息的傳播與維護(hù),這部分工作由各組播路由協(xié)議完成。所有參與組播的主機(jī)必須實(shí)現(xiàn)IGMP。參與IP組播的主機(jī)可以在任意位置、任意時(shí)間、成員總數(shù)不受限制地加入或退出組播組。組播路由器不需要也不可能保存所有主機(jī)的成員關(guān)系,它只是通過IGMP協(xié)議了解每個(gè)接口連接的網(wǎng)段上是否存在某個(gè)組播組的接收者,即組成員。而主機(jī)方只需要保存自己加入了哪些組播組。IGMP在主機(jī)與路由器之間是不對(duì)稱的:主機(jī)需要響應(yīng)組播路由器的IGMP查詢報(bào)文,即以IGMP membership report報(bào)文響應(yīng);路由器周期性發(fā)送成員資格查詢報(bào)文,然后

23、根據(jù)收到的響應(yīng)報(bào)文確定某個(gè)特定組在自己所在子網(wǎng)上是否有主機(jī)加入,并且當(dāng)收到主機(jī)的退出組的報(bào)告時(shí),發(fā)出特定組的查詢報(bào)文(IGMP版本2),以確定某個(gè)特定組是否已無成員存在。6路由協(xié)議當(dāng)數(shù)據(jù)跨網(wǎng)傳輸時(shí)需要進(jìn)行路由,通常路由包括兩個(gè)基本的動(dòng)作:確定最佳路徑和讓信息群(或稱為分組)通過網(wǎng)絡(luò)傳輸。通過網(wǎng)絡(luò)傳輸分組相對(duì)較簡(jiǎn)單,而路徑的確定卻相對(duì)復(fù)雜,一般采用的方法就是查詢路由表。路由表保存了通過路由器可能到達(dá)的目標(biāo)網(wǎng)絡(luò)以及如何到達(dá)該目標(biāo)網(wǎng)絡(luò)的信息,基本項(xiàng)包括目標(biāo)網(wǎng)絡(luò)地址、子網(wǎng)掩碼以及到達(dá)目標(biāo)網(wǎng)絡(luò)的下一站路由器的地址,簡(jiǎn)介記錄了網(wǎng)絡(luò)間的位置關(guān)系。路由表由路由協(xié)議維護(hù)和更新,此外,路由協(xié)議還完成發(fā)送路由更新信

24、息且基于路由算法決定路由的功能,常見的路由協(xié)議有RIP、OSPF、BGP等。RIP協(xié)議使用V-D算法在局域網(wǎng)上實(shí)現(xiàn),它將參加者分為主動(dòng)機(jī)和被動(dòng)機(jī)兩種。主動(dòng)機(jī)主動(dòng)地向外廣播路徑刷新報(bào)文,被動(dòng)機(jī)被動(dòng)地接受路徑刷新報(bào)文。一般情況下,網(wǎng)關(guān)作主動(dòng)機(jī),主機(jī)作被動(dòng)機(jī)。RIP規(guī)定一條路徑的距離為該路徑(從信源機(jī)到信宿機(jī))上的網(wǎng)關(guān)數(shù)。為防止尋徑回路的長(zhǎng)期存在,RIP規(guī)定,長(zhǎng)度為16的路徑為無限長(zhǎng)路徑,即不存在路徑。所以一條有限的路徑長(zhǎng)度不得超過15。正是這一規(guī)定限制了RIP的使用范圍,使RIP局限于小型的局域網(wǎng)中。OSPF(Open Shortest Path First)是一個(gè)內(nèi)部網(wǎng)關(guān)協(xié)議(Interior

25、Gateway Protocol,IGP),用于在單一自治系統(tǒng)(Autonomous System,AS)內(nèi)決策路由,一個(gè)自治系統(tǒng)的經(jīng)典定義是在一個(gè)管理機(jī)構(gòu)控制之下的一組路由器。與RIP相對(duì),OSPF是鏈路狀態(tài)路由協(xié)議,而RIP是距離向量路由協(xié)議。鏈路是路由器接口的另一種說法,因此OSPF也稱為接口狀態(tài)路由協(xié)議。OSPF通過路由器之間通告網(wǎng)絡(luò)接口的狀態(tài)來建立鏈路狀態(tài)數(shù)據(jù)庫,生成最短路徑樹,每個(gè)OSPF路由器使用這些最短路徑構(gòu)造路由表。BGP(Border Gateway Protocol)是一種在自治系統(tǒng)之間動(dòng)態(tài)交換路由信息的路由協(xié)議,它使用IGP(內(nèi)部網(wǎng)關(guān)協(xié)議)和普通度量值向其他自治系統(tǒng)轉(zhuǎn)發(fā)

26、報(bào)文。BGP中使用自治系統(tǒng)這個(gè)術(shù)語是為了強(qiáng)調(diào)這樣一個(gè)事實(shí):一個(gè)自治系統(tǒng)的管理對(duì)于其他自治系統(tǒng)而言是提供一個(gè)統(tǒng)一的內(nèi)部選路計(jì)劃,它為那些通過它可以到達(dá)的網(wǎng)絡(luò)提供了一個(gè)一致的描述。三種協(xié)議分別采用不同的下層協(xié)議承載自己,即RIP使用UDP、OSPF使用IP、BGP使用TCP。7TCP協(xié)議TCP(Transmission Control Protocol,傳輸控制協(xié)議)使用IP作為網(wǎng)絡(luò)層協(xié)議。在網(wǎng)絡(luò)通信傳輸機(jī)制中,它屬于面向連接、可靠傳輸?shù)念愋?。面向連接的傳輸意味著在進(jìn)行通信以前,需要在兩個(gè)系統(tǒng)之間建立邏輯連接,在每個(gè)數(shù)據(jù)傳輸?shù)倪^程中都需要進(jìn)行應(yīng)答以保證數(shù)據(jù)包的完整。這種方法需要的網(wǎng)絡(luò)開銷較大,可是

27、數(shù)據(jù)傳輸?shù)目煽啃钥梢员WC。雖然TCP使用不可靠的IP服務(wù),但它卻提供了一種可靠的傳輸層服務(wù)。TCP承載的高級(jí)應(yīng)用與路由協(xié)議有HTTP、FTP、SMTP、BGP等。8UDP協(xié)議UDP(User Datagram Protocol,用戶數(shù)據(jù)報(bào)協(xié)議)屬于面向無連接、不可靠傳輸?shù)念愋?。該協(xié)議只負(fù)責(zé)接收和傳送由上層協(xié)議傳遞的消息,它本身不做任何檢測(cè)、修改與應(yīng)答,上層協(xié)議需要自己處理這些事務(wù)。UDP的報(bào)頭格式較簡(jiǎn)單,主要是地址信息、包的長(zhǎng)度和校驗(yàn)信息。與此對(duì)應(yīng),TCP包的頭信息有十多個(gè)域。因此UDP的網(wǎng)絡(luò)開銷一般要小于TCP。由于UDP在傳送數(shù)據(jù)過程中沒有建立連接,亦不進(jìn)行檢查,因此在良好的網(wǎng)絡(luò)環(huán)境中,其

28、工作效率較TCP要高。由于UDP的這種特點(diǎn),因此亦是進(jìn)行網(wǎng)絡(luò)廣播的首選協(xié)議。UDP承載的高級(jí)應(yīng)用與路由協(xié)議有DNS、SNMP及RIP等。9應(yīng)用協(xié)議應(yīng)用協(xié)議是平時(shí)使用最廣泛的協(xié)議,這層的每個(gè)協(xié)議都由兩部分組成:客戶程序和服務(wù)程序。程序通過服務(wù)器與客戶機(jī)的交互來工作,如SNMP、FTP、SMTP、POP3等。應(yīng)用協(xié)議被下層協(xié)議所承載,提供更加具體的應(yīng)用服務(wù),詳見第12章。更多關(guān)于TCP/IP協(xié)議的介紹請(qǐng)參考相關(guān)書籍。6.1.3 TCP/IP地址函數(shù)TCP/IP協(xié)議下的WinSock函數(shù)與5.2.3節(jié)介紹的函數(shù)基本一致(實(shí)現(xiàn)產(chǎn)生的區(qū)別見8.1節(jié)),特殊之處在于其地址編碼。TCP/IP協(xié)議的地址編碼遵

29、循IP協(xié)議(參見6.1.2節(jié)),采用結(jié)構(gòu)sockaddr_in實(shí)現(xiàn)。同時(shí),為了解決不同情況下的地址格式轉(zhuǎn)換與查詢問題,還分別提供了一組地址轉(zhuǎn)換函數(shù)和地址信息查詢函數(shù),下面分別進(jìn)行介紹。1地址結(jié)構(gòu)TCP/IP協(xié)議采用一種不同于IPX/SPX和NetBIOS的邏輯地址編碼方法,使用IP地址結(jié)構(gòu)體sockaddr。TCP/IP協(xié)議WinSock的bind、connect、recvfrom、sendto等都用這個(gè)地址結(jié)構(gòu)來指明地址信息,該結(jié)構(gòu)的定義如下:struct sockaddr unsigned short sa_family; /地址協(xié)議族char sa_data14; /地址數(shù)據(jù)字符數(shù)組然而

30、,一般在編程中,并不直接使用sockaddr結(jié)構(gòu),而是使用其等價(jià)結(jié)構(gòu)sockaddr_in,定義如下:struct sockaddr_inshort sin_family;/地址協(xié)議族unsigned short sin_port;/IP端口struct in_addr sin_addr;/IP地址結(jié)構(gòu)char sin_zero8 ;/填充,使總長(zhǎng)度與sockaddr一致其中,in_addr結(jié)構(gòu)體存放的IP地址可以用標(biāo)準(zhǔn)點(diǎn)分式字符串、無符號(hào)短整型、無符號(hào)長(zhǎng)整型等三種不同的方式描述。該結(jié)構(gòu)是一個(gè)聯(lián)合體(union),定義如下:struct in_addr union struct unsigne

31、d char s_b1, s_b2,s_b3, s_b4;/標(biāo)準(zhǔn)點(diǎn)分式字符串 S_un_b; struct unsigned short s_w1, s_w2;/兩個(gè)無符號(hào)短整型 S_un_w; unsigned long S_addr;/一個(gè)無符號(hào)長(zhǎng)整型 S_un;2地址轉(zhuǎn)換在TCP/IP地址的使用中,不僅由于具有不同的字節(jié)順序(網(wǎng)絡(luò)字節(jié)順序和主機(jī)字節(jié)順序)需要轉(zhuǎn)換,再加上地址本身的三種數(shù)據(jù)類型有時(shí)需要進(jìn)行適當(dāng)?shù)霓D(zhuǎn)換,因此WinSock提供了以下一組轉(zhuǎn)換函數(shù)。(1) ntohl()函數(shù):將一個(gè)u_long類型數(shù)(32位無符號(hào)整數(shù))從TCP/IP網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換成主機(jī)字節(jié)順序,原型如下:u_l

32、ong WSAAPI ntohl(u_long netlong);/netlong是TCP/IP網(wǎng)絡(luò)字節(jié)順序表示的32位/無符號(hào)整數(shù)(2) ntohs()函數(shù):將一個(gè)u_short類型數(shù)(16位無符號(hào)整數(shù))從TCP/IP網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換成主機(jī)字節(jié)順序,原型如下:u_short WSAAPI ntohs(u_short netshort);/netshort是TCP/IP網(wǎng)絡(luò)字節(jié)順序表示的16位/無符號(hào)整數(shù)(3) htonl()函數(shù):將一個(gè)u_long類型數(shù)(32位無符號(hào)整數(shù))從主機(jī)字節(jié)順序轉(zhuǎn)換成TCP/IP網(wǎng)絡(luò)字節(jié)順序,原型如下:u_long WSAAPI htonl(u_long hostl

33、ong); /hostlong是指主機(jī)字節(jié)順序表示的32位無符號(hào)整數(shù)(4) htons()函數(shù):將一個(gè)u_short類型數(shù)(16位無符號(hào)整數(shù))從主機(jī)字節(jié)順序轉(zhuǎn)換成TCP/IP網(wǎng)絡(luò)字節(jié)順序,原型如下:u_short WSAAPI htons(u_short hostshort);/hostshort是按主機(jī)字節(jié)順序表示的16位無符號(hào)整數(shù)上述函數(shù)很容易記憶,h代表主機(jī)字節(jié)順序,n代表網(wǎng)絡(luò)字節(jié)順序,s代表無符號(hào)短整型,l代表無符號(hào)長(zhǎng)整型,to代表轉(zhuǎn)換目標(biāo)。另外,還有兩個(gè)重要的函數(shù),即inet_addr()和inet_ntoa(),用于IP地址點(diǎn)分表示法的轉(zhuǎn)換。(1) inet_addr()函數(shù)將一個(gè)

34、用點(diǎn)分表示法表示的地址的字符串地址轉(zhuǎn)換成網(wǎng)際地址in_addr形式,所有網(wǎng)際地址都以網(wǎng)絡(luò)字節(jié)順序(字節(jié)順序從左到右)返回,原型如下:unsigned long WSAAPI inet_addr(const char FAR * cp);/cp是含有用點(diǎn)分表示法表示的/地址字符串(2) inet_ntoa()函數(shù)將一個(gè)網(wǎng)際地址轉(zhuǎn)換成點(diǎn)分十進(jìn)制表示法表示的字符串。它接收由參數(shù)in指定的網(wǎng)際地址結(jié)構(gòu),返回以點(diǎn)分表示法表示的地址的ASCII字符串,原型如下:char FAR * WSAAPI inet_ntoa(struct in_addr in);/in表示主機(jī)網(wǎng)際地址結(jié)構(gòu)3地址查詢TCP/IP還提

35、供地址查詢函數(shù),可以在編程過程中根據(jù)需要獲取主機(jī)信息。主機(jī)信息被放入一個(gè)hostent的結(jié)構(gòu)體里。函數(shù)如下:struct hostent char FAR * h_name; /PC的官方名 char FAR * FAR * h_aliases; /PC的別名 short h_addrtype; /地址類型 short h_length; /地址長(zhǎng)度 char FAR * FAR * h_addr_list;/主機(jī)地址列表可以依據(jù)主機(jī)的地址得到該主機(jī)信息,函數(shù)如下:struct HOSTENT FAR * gethostbyaddr ( const char FAR * addr, /主機(jī)地址

36、 int len,/地址長(zhǎng)度 int type);/地址類型可以依據(jù)主機(jī)名得到該主機(jī)信息,函數(shù)如下:struct hostent FAR * gethostbyname (const char FAR * name);/指向主機(jī)名的指針 可以依據(jù)主機(jī)名得到擴(kuò)展gethostbyname,函數(shù)如下:HANDLE WSAAsyncGetHostByName (HWND hWnd,/接收異步請(qǐng)求的窗口句柄unsigned int wMsg, /接收該異步請(qǐng)求的消息const char FAR * name, /指向主機(jī)名的指針char FAR * buf, /接收信息的緩沖區(qū)指針int buflen

37、 );/緩沖區(qū)長(zhǎng)度獲得本地主機(jī)名的函數(shù)如下:int gethostname ( char FAR * name, /接收主機(jī)名的緩存區(qū)int namelen);/緩沖區(qū)長(zhǎng)度上述部分函數(shù)需要PSDK(參見2.8.2節(jié))的支持。TCP/IP協(xié)議中的面向連接服務(wù)是TCP協(xié)議提供的,本節(jié)對(duì)TCP編程進(jìn)行介紹。在WinSock編程中,TCP協(xié)議編程是用流套接字實(shí)現(xiàn)的。流套接字的服務(wù)進(jìn)程和客戶進(jìn)程在通信前必須創(chuàng)建各自的套接字并建立連接,然后才能對(duì)相應(yīng)的套接字進(jìn)行讀/寫操作,實(shí)現(xiàn)數(shù)據(jù)的傳輸。6.3 TCP編程6.3.1 TCP程序結(jié)構(gòu)在TCP通信中主要有連接的建立、數(shù)據(jù)的傳輸、連接的關(guān)閉等三個(gè)主要過程(如圖

38、6-6所示)。每個(gè)過程完成不同的工作,而且TCP包的序列號(hào)和確認(rèn)號(hào)在每個(gè)過程中的變化都是不同的。TCP建立連接也就是我們常說的三次握手,它需要三步完成。在 TCP 建立連接后,就可以開始傳輸數(shù)據(jù)了。TCP工作在全雙工模式,它可以同時(shí)進(jìn)行雙向數(shù)據(jù)傳輸。以服務(wù)器向客戶端發(fā)送數(shù)據(jù)為例,服務(wù)器向客戶端發(fā)送一個(gè)數(shù)據(jù)包,客戶端收到這個(gè)數(shù)據(jù)包后,會(huì)向服務(wù)器發(fā)送一個(gè)確認(rèn)數(shù)據(jù)包。TCP連接的關(guān)閉經(jīng)歷四次揮手的過程。圖6-6 流套接字程序時(shí)序圖下面是從套接字編程角度進(jìn)行的服務(wù)端與客戶端的函數(shù)過程,TCP通信的三個(gè)過程蘊(yùn)含于其中。 建立套接字。用socket()函數(shù)完成。 將指定協(xié)議的套接字綁定到它已知的名字上,這

39、個(gè)名字就是本地的IP地址端口號(hào)。這個(gè)過程通過bind()函數(shù)完成。 服務(wù)進(jìn)程要處于監(jiān)聽狀態(tài),等待任意數(shù)量的客戶端連接,以便為它們的請(qǐng)求提供服務(wù)。此服務(wù)進(jìn)程必須在所綁定的名字上進(jìn)行監(jiān)聽,所以要把套接字置為監(jiān)聽模式。通過listen()函數(shù)來實(shí)現(xiàn)。 服務(wù)進(jìn)程調(diào)用函數(shù)accept()或WSAAccept()準(zhǔn)備接收來自客戶端的連接,如果一個(gè)客戶端用connect()函數(shù)試圖建立連接,服務(wù)進(jìn)程就可以接受連接。 建立連接后,服務(wù)器和客戶端之間就可以使用send()和recv()函數(shù)進(jìn)行通信。注意,默認(rèn)情況recv()函數(shù)處于阻塞模式,在接收到數(shù)據(jù)前,程序不向下執(zhí)行。 通信結(jié)束后,調(diào)用closescoke

40、t()函數(shù)關(guān)閉套接字。注意:在此編程過程中,服務(wù)器必須首先啟動(dòng),直到執(zhí)行完accept()調(diào)用,進(jìn)入等待狀態(tài)后,方能接收客戶請(qǐng)求。如客戶在此之前啟動(dòng),則connect()將返回出錯(cuò)代碼,表示連接不成功。6.3.2 TCP服務(wù)器端下列程序是一個(gè)面向連接的服務(wù)器端程序,能夠偵聽客戶端的連接請(qǐng)求。當(dāng)使客戶端發(fā)送字符串“l(fā)ist0”到“l(fā)ist5”,服務(wù)器端每接收到一個(gè)字符串就回應(yīng)一個(gè)echo信號(hào),例如:接收到“l(fā)ist4”,回應(yīng)“echo list4”。#include stdafx.h#include winsock.h#include windows.h#include stdio.h#prag

41、ma comment(lib,wsock32.lib)#define RECV_PORT 3000SOCKET sock,sock1;sockaddr_in ServerAddr;sockaddr_in ClientAddr;int Addrlen;DWORD StartSock()WSADATA WSAData; if (WSAStartup(MAKEWORD(2,2),&WSAData)!=0) /初始化套接字printf(sock init fail !n);return(-1); return(1);DWORD CreateSocket()sock=socket(AF_INET,SOC

42、K_STREAM,0); /創(chuàng)建套接字if (sock=SOCKET_ERROR)printf(sock create fail !n);WSACleanup();return(-1);ServerAddr.sin_family=AF_INET; /填充服務(wù)器地址ServerAddr.sin_addr.s_addr=htonl(INADDR_ANY);ServerAddr.sin_port=htons(RECV_PORT);if (bind(sock,(struct sockaddr FAR*)&ServerAddr,sizeof(ServerAddr)=SOCKET_ERROR) /綁定套接

43、字為創(chuàng)建的sock指定通信對(duì)象 printf(bind is the error); return(-1); return (1);DWORD ConnectProcess() char buff80;char buffecho80=echo ;int i,length;Addrlen=sizeof(sockaddr_in);if (listen( sock, 5 ) 0) printf(Listen error); return(-1); else printf(Listening.n);sock1 = accept( sock,(struct sockaddr FAR *) &Client

44、Addr,&Addrlen);printf(connect ok n);printf(wait for receive.n); for (i=0;i6;i+) memset(buff,0,80); if (recv(sock1,buff,80,0)=0) return -1; else printf(recive %sn,buff); strncpy(buffecho+5,buff,5);/依次生成ehco list0、ehco list1、ehco list2、ehco list3、/ ehco list4、ehco list5字符串并發(fā)送 length=send(sock1,buffech

45、o,strlen(buffecho),0); if (length=0) printf(send data error !n); closesocket(sock); WSACleanup(); return(-1); return(1);int main(int argc, char* argv)if (StartSock()=-1)return(-1);if (CreateSocket()=-1)return(-1);if (ConnectProcess()=-1)return(-1);closesocket(sock);WSACleanup();return 0;6.3.3 TCP客戶端

46、下面程序是6.3.2節(jié)程序?qū)?yīng)的客戶端程序,首先向服務(wù)端發(fā)出連接請(qǐng)求。連接建立后向服務(wù)端發(fā)送字符串“l(fā)ist0”到“l(fā)ist5”,之后接收來自服務(wù)端的響應(yīng)。#include stdafx.h#include winsock.h#include windows.h#include stdio.h#include #pragma comment(lib,wsock32.lib)#define SEND_PORT 3000SOCKET sock;sockaddr_in ServerAddr;DWORD CreateSocket() sock=socket(AF_INET,SOCK_STREAM,0)

47、; /創(chuàng)建套接字if (sock=SOCKET_ERROR)printf(sock create fail !n);WSACleanup();return(-1);return (1);DWORD CallServer() CreateSocket();if(connect(sock,(struct sockaddr*) &ServerAddr,sizeof( ServerAddr)=SOCKET_ERROR) printf(Connect fail n); closesocket( sock ); return(-1); return(1);DWORD TCPSend(char data)i

48、nt length;length=send(sock,data,strlen(data),0); if (length=0)printf(send data error !n);closesocket(sock);WSACleanup();return(-1);return(1);DWORD TCPRecv(char data)int length;length=recv(sock,data,80,0); if (length=0)printf(send data error !n);closesocket(sock);WSACleanup();return(-1);return(1);DWO

49、RD StartSock()WSADATA WSAData; if (WSAStartup(MAKEWORD(2,2),&WSAData)!=0)/初始化套接字printf(sock init fail !n);return(-1); ServerAddr.sin_family=AF_INET; /填充服務(wù)器地址ServerAddr.sin_addr.s_addr=inet_addr();ServerAddr.sin_port=htons(SEND_PORT);return(1);int main( )char buff80=list;char buffrecv80=;char num; in

50、t i;StartSock();while (CallServer()=-1);printf(connect ok!n); for (i=0;i6;i+) _itoa(i,&num,10); strncpy(buff+4,&num,1); printf(press any key to send %s!,buff); getchar(); TCPSend(buff);/發(fā)送list并接收echo ZeroMemory(buffrecv,80); TCPRecv(buffrecv); printf(%sn,buffrecv); closesocket(sock);WSACleanup(); re

51、turn(0);6.3.4 TCP連接與斷開TCP連接與斷開是其通信的關(guān)鍵,TCP采用三次握手與四次揮手的方式來實(shí)現(xiàn)。1三次握手TCP提供的一個(gè)可靠連接的方式是通過三次握手(Three-way Handshake)來完成的。三次握手是指通信雙方彼此交換三次信息。三次握手是指在存在包丟失、重復(fù)和延遲的情況下,確保通信雙方信息交換確定性的充分必要條件。三次握手的操作過程如圖6-7(a)所示。(1) 請(qǐng)求端(通常稱為客戶)發(fā)送一個(gè)TCP報(bào)文,并設(shè)置了SYN標(biāo)志,指明客戶打算連接的服務(wù)器的端口,以及初始序號(hào)(ISN)。這個(gè)TCP報(bào)文為報(bào)文段1。(2) 服務(wù)器發(fā)回一個(gè)設(shè)置了SYN標(biāo)志和ACK標(biāo)志的TCP

52、報(bào)文(報(bào)文段2)作為應(yīng)答,并將該報(bào)文中確認(rèn)序號(hào)設(shè)置為客戶的ISN加1,并將ISN設(shè)置為服務(wù)器端初始序號(hào),用以對(duì)客戶的SYN報(bào)文段進(jìn)行確認(rèn),一個(gè)SYN占用一個(gè)序號(hào)。(3) 客戶開始向服務(wù)器發(fā)送數(shù)據(jù),并設(shè)置ACK標(biāo)志,將確認(rèn)序號(hào)設(shè)置為服務(wù)器的ISN加1,用以對(duì)服務(wù)器的SYN報(bào)文段進(jìn)行確認(rèn)(報(bào)文段3)。圖6-7 三次握手與四次揮手的過程在程序設(shè)計(jì)中,WinSock的listen、connect、accept配合完成該過程,三次握手在WinSock函數(shù)TCP編程中所處的位置如圖6-8所示。上述三個(gè)過程的依次完成表明建立了TCP連接。圖6-8 三次握手在Winsock函數(shù)TCP編程中所處的位置2四次揮手

53、建立一個(gè)TCP連接需要三次握手,而正常終止一個(gè)連接則要經(jīng)過四次揮手,這是由TCP的半關(guān)閉(half-close)特性所造成的。由于TCP是全雙工連接,每個(gè)方向的連接必須單獨(dú)關(guān)閉,因此當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后必須發(fā)送一個(gè)FIN標(biāo)志來終止這個(gè)方向的連接。當(dāng)一端收到一個(gè)FIN后,必須通知應(yīng)用層另一端已經(jīng)終止了該方向的數(shù)據(jù)傳送。發(fā)送FIN通常是應(yīng)用層關(guān)閉連接的結(jié)果。TCP連接收到一個(gè)FIN標(biāo)志只意味著對(duì)方已不再發(fā)送數(shù)據(jù),但己方仍能發(fā)送數(shù)據(jù),這是半關(guān)閉型應(yīng)用。正常關(guān)閉過程如圖6-7(b)所示。(1) 通常情況下,一方完成主動(dòng)關(guān)閉而另一方完成被動(dòng)關(guān)閉(但也存在雙方都執(zhí)行主動(dòng)關(guān)閉的特例)。首先進(jìn)行關(guān)閉的一方

54、(即發(fā)送第一個(gè)FIN)執(zhí)行主動(dòng)關(guān)閉,而另一方(收到這個(gè)FIN)執(zhí)行被動(dòng)關(guān)閉。圖6-8中的報(bào)文段1發(fā)起終止連接,TCP客戶端發(fā)送一個(gè)FIN,用來關(guān)閉從客戶到服務(wù)器的數(shù)據(jù)傳送。(2) 當(dāng)服務(wù)器收到這個(gè)FIN,它發(fā)回一個(gè)ACK,確認(rèn)序號(hào)為收到的ISN加1(報(bào)文段2)。(3) 接著,這個(gè)服務(wù)器程序就關(guān)閉它的連接,TCP端發(fā)送一個(gè)FIN(報(bào)文段3),客戶必須發(fā)回一個(gè)確認(rèn),并將確認(rèn)序號(hào)設(shè)置為收到的ISN加1(報(bào)文段4)。四次揮手的WinSock函數(shù)在TCP編程中所處的位置如圖6-9所示。圖6-9 四次揮手的WinSock函數(shù)在TCP編程中所處的位置3優(yōu)雅地關(guān)閉連接TCP連接的關(guān)閉處于通信程序的末端,一般容

55、易被程序設(shè)計(jì)者所忽視,認(rèn)為直接調(diào)用shutdown()或closesocket()函數(shù)即可,這種做法通常過于武斷和直接,會(huì)導(dǎo)致四次揮手沒有全部完成,從而造成傳輸數(shù)據(jù)丟失、關(guān)閉不完善等問題。在這種關(guān)閉過程中,一方開始關(guān)閉通信會(huì)話,但另一方仍然可以讀取線上或網(wǎng)絡(luò)堆棧上已掛起的數(shù)據(jù)。因此必須提倡優(yōu)雅地關(guān)閉TCP連接,這也是MSDN專門強(qiáng)調(diào)的問題。建議按照如下的方法關(guān)閉TCP連接(C代表客戶,S代表服務(wù)器)優(yōu)雅地關(guān)閉TCP連接:C:注冊(cè)(用WSAAsyncSelect)FD_CLOSE事件(套接字起初創(chuàng)建之后就應(yīng)當(dāng)注冊(cè)),調(diào)用shutdown,how=SD_SEND(實(shí)際上發(fā)了一個(gè)FIN包);S:注冊(cè)

56、FD_CLOSE事件(套接字起初創(chuàng)建之后就應(yīng)當(dāng)注冊(cè)),當(dāng)發(fā)現(xiàn)此事件發(fā)生后(C的shutdown和全部數(shù)據(jù)都處理這兩個(gè)條件均滿足才會(huì)引起的,參見MSDN中FD_CLOSE的解釋),為了使FD_CLOSE可以順利發(fā)生,則要調(diào)用recv直到返回值是0或SOCKET_ERROR,調(diào)用shutdown,how=SD_SEND(實(shí)際上發(fā)了一個(gè)FIN包),等上一會(huì),調(diào)用closesocket;C:當(dāng)發(fā)現(xiàn)FD_CLOSE事件發(fā)生后(S的shutdown和全部數(shù)據(jù)都處理這兩個(gè)條件均滿足才會(huì)引起的,參見MSDN中看FD_CLOSE的解釋),為了使FD_CLOSE可以順利發(fā)生,則要調(diào)用recv直到返回值是0或SOC

57、KET_ERROR,等上一會(huì)再調(diào)用closesocket。圖6-10是利用網(wǎng)絡(luò)嗅探器軟件Wireshark抓到的TCP服務(wù)器(IP:00)與客戶端(IP:5)之間的三次握手(包13)和四次揮手(包13)過程中的數(shù)據(jù)包。從圖中包列表面板(packet list)的info字段可以清楚地看到SYN、ACK、FIN等標(biāo)識(shí),以及報(bào)文長(zhǎng)度等信息,如果想得到一個(gè)數(shù)據(jù)包更加詳細(xì)的信息,可以在包列表窗口選中該包,在包細(xì)節(jié)面板(packet details)里看到該數(shù)據(jù)包的各字段數(shù)據(jù),或者在包字節(jié)面板(packet byte)里查看該數(shù)據(jù)包的十六進(jìn)制數(shù)據(jù)。圖6-10 三次握手與四次揮手過程數(shù)據(jù)報(bào)套接字是無連接的

58、,其編程過程與流套接字編程類似,但是要比流套接字簡(jiǎn)單。6.4.1 UDP程序結(jié)構(gòu)數(shù)據(jù)報(bào)套接字是無連接的,所使用的基本W(wǎng)inSock函數(shù)與流套接字相同,而數(shù)據(jù)傳輸函數(shù)則使用的是sendto()函數(shù)和recvfrom()函數(shù)。6.4 UDP編程圖6-11 UDP通信時(shí)序圖具體步驟如下(如圖6-11所示): 服務(wù)器和客戶端都要建立一個(gè)數(shù)據(jù)報(bào)套接字。 服務(wù)器調(diào)用bind()函數(shù)給套接字分配一個(gè)公認(rèn)的端口,在開發(fā)應(yīng)用程序時(shí),這個(gè)公認(rèn)端口通常是指定的??蛻舳送瑯有枰獙?duì)套接字進(jìn)行綁定(如果在套接字建立之后直接調(diào)用sendto()函數(shù),該步驟可以省略)。 客戶端和服務(wù)器都可以使用sendto()函數(shù)發(fā)送數(shù)據(jù),

59、使用recvfrom()函數(shù)接收數(shù)據(jù),從而完成數(shù)據(jù)報(bào)傳遞。默認(rèn)情況recvfrom()函數(shù)處于阻塞模式,在接收到數(shù)據(jù)前,程序不向下執(zhí)行。 通信結(jié)束后,調(diào)用closescoket()關(guān)閉套接字。注意:無連接服務(wù)器也必須先啟動(dòng),否則客戶請(qǐng)求傳不到服務(wù)進(jìn)程。無連接客戶不調(diào)用connect(),因此在數(shù)據(jù)發(fā)送之前,客戶與服務(wù)器之間尚未建立完全相關(guān),但各自通過socket()和bind()建立了半相關(guān)。發(fā)送數(shù)據(jù)時(shí),發(fā)送方除指定本地套接字號(hào)外,還需指定接收方套接字號(hào),從而在數(shù)據(jù)收發(fā)過程中動(dòng)態(tài)地建立了全相關(guān)。6.4.2 UDP服務(wù)器端本節(jié)展示的是用UDP實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)會(huì)話的一個(gè)實(shí)例程序。以下程序?qū)崿F(xiàn)的是一個(gè)計(jì)算

60、機(jī)對(duì)計(jì)算機(jī)的點(diǎn)對(duì)點(diǎn)會(huì)話。程序循環(huán)接收另外一臺(tái)發(fā)送的消息(也可以增加發(fā)送功能)。實(shí)現(xiàn)原理是程序首先建立一個(gè)socket(),然后同一個(gè)本地地址與端口100綁定在一起。這樣,如果對(duì)方計(jì)算機(jī)向這個(gè)地址上的這個(gè)端口發(fā)送數(shù)據(jù),此計(jì)算機(jī)就可以循環(huán)接收數(shù)據(jù)了。#include #include #pragma comment(lib, wsock32.lib)DWORD StartSock() /略,同6.3.2節(jié)int main()printf(初始化.n);StartSock();SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /創(chuàng)建套接字if(

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論