課件:《網(wǎng)絡(luò)程序設(shè)計(jì)》第02章_第1頁(yè)
課件:《網(wǎng)絡(luò)程序設(shè)計(jì)》第02章_第2頁(yè)
課件:《網(wǎng)絡(luò)程序設(shè)計(jì)》第02章_第3頁(yè)
課件:《網(wǎng)絡(luò)程序設(shè)計(jì)》第02章_第4頁(yè)
課件:《網(wǎng)絡(luò)程序設(shè)計(jì)》第02章_第5頁(yè)
已閱讀5頁(yè),還剩99頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展過(guò)程套接字與UNIX操作系統(tǒng)的關(guān)系套接字編程的基本概念面向連接的套接字編程無(wú)連接的套接字編程原始套接字Linux系統(tǒng)的網(wǎng)絡(luò)編程接口第2章 UNIX中的套接字網(wǎng)絡(luò)編程接口本章提要2.1.1 問(wèn)題的提出 站在應(yīng)用程序?qū)崿F(xiàn)的角度,應(yīng)用程序如何方便地使用協(xié)議棧軟件進(jìn)行通信呢? 如果能在應(yīng)用程序與協(xié)議棧軟件之間提供一個(gè)軟件接口,就可以方便客戶與服務(wù)器軟件的編程。2.1 UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展 套接字應(yīng)用程序編程接口是網(wǎng)絡(luò)應(yīng)用程序通過(guò)網(wǎng)絡(luò)協(xié)議棧進(jìn)行通信時(shí)所使用的接口,即應(yīng)用程序與協(xié)議棧軟件之間的接口,簡(jiǎn)稱(chēng)套接字編程接口(Socket API)。 它定義

2、了應(yīng)用程序與協(xié)議棧軟件進(jìn)行交互時(shí)可以使用的一組操作,決定了應(yīng)用程序使用協(xié)議棧的方式、應(yīng)用程序所能實(shí)現(xiàn)的功能、以及開(kāi)發(fā)具有這些功能的程序的難度。2.1 UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展 加州大學(xué)伯克利(Berkley)分校開(kāi)發(fā)并推廣了一個(gè)包括 TCP/IP 互聯(lián)協(xié)議的 UNIX,稱(chēng)為BSD UNIX(Berkeley Software Distribution UNIX)操作系統(tǒng),套接字編程接口是這個(gè)操作系統(tǒng)的一個(gè)部分。 后來(lái)的許多操作系統(tǒng)并沒(méi)有另外搞一套其它的編程接口,而是選擇了對(duì)于套接字編程接口的支持。 由于這個(gè)套接字規(guī)范最早是由Berkeley大學(xué)開(kāi)發(fā)的,一般將它稱(chēng)為Berkeley

3、 Sockets規(guī)范。2.1.2 套接字編程接口的起源與應(yīng)用 要想實(shí)現(xiàn)套接字編程接口,可以采用兩種實(shí)現(xiàn)方式: 一種是在操作系統(tǒng)的內(nèi)核中增加相應(yīng)的軟件,網(wǎng)絡(luò)程序中用系統(tǒng)調(diào)用的方法來(lái)實(shí)現(xiàn)(Unix/Linux) 一種是通過(guò)開(kāi)發(fā)操作系統(tǒng)之外的函數(shù)庫(kù),網(wǎng)絡(luò)程序中采用調(diào)用庫(kù)函數(shù)的方法來(lái)實(shí)現(xiàn)(Windows) 2.1.3 套接字編程接口的兩種實(shí)現(xiàn)方式 UNIX操作系統(tǒng)對(duì)文件和所有其它的輸入/輸出設(shè)備采用一種統(tǒng)一的的操作模式,就是“打開(kāi)-讀-寫(xiě)-關(guān)閉”(open - read - write - close)的I/O模式。 當(dāng)TCP/IP協(xié)議被集成到UNIX內(nèi)核中的時(shí)候,相當(dāng)于在 UNIX系統(tǒng)中引入了一種新

4、型的I/O 操作,就是應(yīng)用程序通過(guò)網(wǎng)絡(luò)協(xié)議棧來(lái)交換數(shù)據(jù)。 2.1.4 套接字通信與UNIX操作系統(tǒng)的輸入/輸出 在UNIX系統(tǒng)的實(shí)現(xiàn)中,套接字是完全與其他I/O集成在一起的。操作系統(tǒng)和應(yīng)用程序都將套接字編程接口也看作一種輸入/輸出機(jī)制。 但是,用戶進(jìn)程與網(wǎng)絡(luò)協(xié)議的交互作用實(shí)際要比用戶進(jìn)程與傳統(tǒng)的I/O設(shè)備相互作用要復(fù)雜得多。 2.1.4 套接字通信與UNIX操作系統(tǒng)的輸入/輸出 其次,使用套接字的應(yīng)用程序必須說(shuō)明許多細(xì)節(jié)。僅僅提供open、read、write、close四個(gè)過(guò)程遠(yuǎn)遠(yuǎn)不夠。為避免單個(gè)套接字函數(shù)參數(shù)過(guò)多,套接字編程接口的設(shè)計(jì)者定義了多個(gè)函數(shù)。2.1.4 套接字通信與UNIX操作系

5、統(tǒng)的輸入/輸出2.2 套接字編程的基本概念 套接口是對(duì)網(wǎng)絡(luò)中不同主機(jī)上應(yīng)用進(jìn)程之間進(jìn)行雙向通信的端點(diǎn)的抽象,一個(gè)套接口就是網(wǎng)絡(luò)上進(jìn)程通信的一端,提供了應(yīng)用層進(jìn)程利用網(wǎng)絡(luò)協(xié)議棧交換數(shù)據(jù)的機(jī)制。 圖2.1 電插座與電話插座的作用2.2.1 什么是套接字(SOCKET) 2.2.1 什么是套接字(SOCKET)? 我們應(yīng)當(dāng)從多個(gè)層面來(lái)理解套接字這個(gè)概念的內(nèi)涵。 從套接字所處的地位來(lái)講,套接字上聯(lián)應(yīng)用進(jìn)程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過(guò)網(wǎng)絡(luò)協(xié)議棧進(jìn)行通信的接口,是應(yīng)用程序與網(wǎng)絡(luò)協(xié)議棧進(jìn)行交互的接口。 圖2.2 應(yīng)用進(jìn)程、套接口、網(wǎng)絡(luò)協(xié)議棧及操作系統(tǒng)的關(guān)系 進(jìn)程、套接口、協(xié)議棧、操作系統(tǒng)的關(guān)系 從實(shí)現(xiàn)的

6、角度來(lái)講,非常復(fù)雜。套接字是一個(gè)復(fù)雜的軟件機(jī)構(gòu),包含了一定的數(shù)據(jù)結(jié)構(gòu),包含許多選項(xiàng),由操作系統(tǒng)內(nèi)核管理。 從使用的角度來(lái)講,非常簡(jiǎn)單。對(duì)于套接字的操作形成了一種網(wǎng)絡(luò)應(yīng)用程序的編程接口(API)。 本書(shū)把這一套操作套接字的編程接口函數(shù)稱(chēng)作套接字編程接口,套接字是它的操作對(duì)象。 總之,套接字是網(wǎng)絡(luò)通信的基石。 套接字編程接口2.2.2 套接字的特點(diǎn)1通信域 套接字存在于通信域中,通信域是為了處理一般的進(jìn)程通過(guò)套接字通信而引入的一種抽象概念,套接字通常只和同一域中的套接字交換數(shù)據(jù)。 如果數(shù)據(jù)交換要穿越域的邊界,就一定要執(zhí)行某種解釋程序。 本課程中,僅僅針對(duì)Internet域,并且使用Internet

7、協(xié)議族(即TCP/IP協(xié)議族)來(lái)通信。2套接字具有三種類(lèi)型 每一個(gè)正被使用的套接字都有它確定的類(lèi)型,只有相同類(lèi)型的套接字才能相互通信。 (1) 數(shù)據(jù)報(bào)套接字 (Datagram SOCKET) 數(shù)據(jù)報(bào)套接字提供無(wú)連接的、不保證可靠的獨(dú)立的數(shù)據(jù)報(bào)傳輸服務(wù)。在Internet通信域中,數(shù)據(jù)報(bào)套接字使用UDP數(shù)據(jù)報(bào)協(xié)議形成的進(jìn)程間通路,具有UDP協(xié)議為上層所提供的服務(wù)的所有特點(diǎn)。數(shù)據(jù)報(bào)套接字基于UDP協(xié)議 圖2.3 在Internet通信域中,數(shù)據(jù)報(bào)套接字基于UDP協(xié)議 (2)流套接字(Stream SOCKET) 流套接字提供雙向的、有序的、無(wú)重復(fù)的、無(wú)記錄邊界的、可靠的數(shù)據(jù)流傳輸服務(wù)。在Inte

8、rnet通信域中,流套接字使用TCP協(xié)議形成的進(jìn)程間通路,具有TCP協(xié)議為上層所提供的服務(wù)的所有特點(diǎn),在使用流套接字傳輸數(shù)據(jù)之前,必須在數(shù)據(jù)的發(fā)送端和接收端之間先建立連接,如下頁(yè)圖2.4所示。 流式套接字基于TCP協(xié)議圖2.4 在Internet通信域中,流式套接字基于TCP協(xié)議(3)原始套接字 (RAW SOCKET) 原始套接字允許對(duì)較低層次的協(xié)議,如IP、ICMP直接訪問(wèn),或用于檢驗(yàn)新的協(xié)議的實(shí)現(xiàn)。TCPUDP IP / ICMP Ethernet應(yīng) 用 程 序流套接字?jǐn)?shù)據(jù)報(bào)套接字原始套接字原始套接字3套接字由應(yīng)用層通信進(jìn)程創(chuàng)建,并為其服務(wù) 套接字由應(yīng)用層的通信進(jìn)程創(chuàng)建,并為其服務(wù),這就

9、是說(shuō),每一個(gè)套接字都有一個(gè)相關(guān)的應(yīng)用進(jìn)程,操作該套接字的代碼是該進(jìn)程的組成部分。4使用確定的IP地址和傳輸層端口號(hào) 套接字編程時(shí),往往在生成套接字的描述符后,要將套接字與計(jì)算機(jī)上的特定的IP地址和傳輸層端口號(hào)相關(guān)聯(lián),這個(gè)過(guò)程稱(chēng)為綁定。 一個(gè)套接口要使用一個(gè)確定的三元組網(wǎng)絡(luò)地址信息,才能使它在網(wǎng)絡(luò)中唯一地被標(biāo)識(shí)。 (1)不管是采用對(duì)等模式或者客戶機(jī)/服務(wù)器模式,通信雙方的應(yīng)用程序都需要開(kāi)發(fā)。 (2)雙方所交換數(shù)據(jù)的結(jié)構(gòu)和交換數(shù)據(jù)的順序有特定的要求,不符合現(xiàn)在成熟的應(yīng)用層協(xié)議的要求時(shí)。甚至,有時(shí)需要自己去開(kāi)發(fā)應(yīng)用層協(xié)議,自己設(shè)計(jì)最適合的數(shù)據(jù)結(jié)構(gòu)和信息交換規(guī)程。 2.2.3 套接字的應(yīng)用場(chǎng)合2.2.

10、4 套接字使用的數(shù)據(jù)類(lèi)型和相關(guān)的問(wèn)題1三種表示套接字地址的結(jié)構(gòu) 在套接字編程接口中,專(zhuān)門(mén)定義了三種結(jié)構(gòu)型的數(shù)據(jù)類(lèi)型,用來(lái)存儲(chǔ)協(xié)議相關(guān)的網(wǎng)絡(luò)地址,在套接字編程接口的函數(shù)調(diào)用中要用到它們。三種表示套接字地址的結(jié)構(gòu) (1)sockaddr 結(jié)構(gòu),針對(duì)各種通信域的套接字,存儲(chǔ)它們的地址信息: struct sockaddr unsigned short sa_family; / 地址家族 char sa_data14; / 協(xié)議地址 (2) sockaddr_in 結(jié)構(gòu),專(zhuān)門(mén)針對(duì)Internet通信域,存儲(chǔ)套接字相關(guān)的網(wǎng)絡(luò)地址信息,例如IP地址、端口號(hào)等信息。 struct sockaddr_in s

11、hort int sin_family; /地址家族 unsigned short int sin_port; /2字節(jié)端口號(hào) struct in_addr sin_addr; /4字節(jié)IP 地址 unsigned char sin_zero8; /8字節(jié)全0 /最后包含一個(gè)8字節(jié)的全0的域,以使該結(jié)構(gòu)在大小上與sockaddr相同三種表示套接字地址的結(jié)構(gòu) (3)in_addr 結(jié)構(gòu),專(zhuān)門(mén)用來(lái)存儲(chǔ) IP地址: struct in_addr unsigned long s_addr; /4字節(jié)IP 三種表示套接字地址的結(jié)構(gòu) (4)這些數(shù)據(jù)結(jié)構(gòu)組合使用的一般用法: 首先,定義一個(gè)sockaddr_

12、in的結(jié)構(gòu)實(shí)例,并將它清零。 比如: struct sockaddr_in myad; memset(&myad, 0, sizeof(struct sockaddr_in); 一般,三種結(jié)構(gòu)組合起來(lái)使用: 然后,為這個(gè)myad結(jié)構(gòu)賦值,比如: myad.sin_family = AF_INET; myad.sin_port = htons(8080); myad.sin_addr.s_addr = htonl(INADDR_ANY);注1:地址家族有AF_INET、AF_DECnet、等字符常量可 選,在Internet域內(nèi)進(jìn)行通信時(shí),應(yīng)賦值A(chǔ)F_INET。注2:INADDR_ANY字符常量

13、表示該主機(jī)的任何一個(gè)IP地址。一般,三種結(jié)構(gòu)組合起來(lái)使用: 第三步:在函數(shù)調(diào)用中使用時(shí),將這個(gè)結(jié)構(gòu)強(qiáng)制轉(zhuǎn)換為sockaddr類(lèi)型。 如:accept(listenfd, (sockaddr*)(&myad), &addrlen); 一般,三種結(jié)構(gòu)組合起來(lái)使用:2主機(jī)字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序 多字節(jié)數(shù)據(jù)的字節(jié)順序 大端模式 (big endian): 高字節(jié)放到低地址上 小端模式 (little endian): 高字節(jié)放到高地址上 在具體計(jì)算機(jī)中多字節(jié)數(shù)據(jù)的存儲(chǔ)順序稱(chēng)為主機(jī)字節(jié)順序。 不同的機(jī)器內(nèi)存中主機(jī)字節(jié)順序不相同,與CPU設(shè)計(jì)有關(guān): Motorola 68000、PowerPC系列 - 大

14、端模式 (big endian) Intel x86系列 - 小端模式 (little endian) 多字節(jié)數(shù)據(jù)在網(wǎng)絡(luò)協(xié)議報(bào)頭中的 順序,稱(chēng)為 網(wǎng)絡(luò)字節(jié)順序。 網(wǎng)絡(luò)通信時(shí)一律使用統(tǒng)一的 大端模式網(wǎng)絡(luò)字節(jié)順序,避免主 機(jī)間通信時(shí)識(shí)別兼容問(wèn)題。5612347834785612 低址: 高址: 表示 0 x12345678時(shí): Motorola Intel2主機(jī)字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序 網(wǎng)絡(luò)應(yīng)用程序要在不同的計(jì)算機(jī)中運(yùn)行,多字節(jié)數(shù)據(jù)在各機(jī)器內(nèi)存中存放的主機(jī)字節(jié)順序可能不同,可能是大端模式,也可能是小端模式;但是,在網(wǎng)絡(luò)上傳輸時(shí),在信包協(xié)議報(bào)頭字段中的網(wǎng)絡(luò)字節(jié)順序是一定的,都是大端模式。 所以,應(yīng)用程

15、序在編程的時(shí)候,在把主機(jī)內(nèi)存變量中的IP地址和端口號(hào)裝入網(wǎng)絡(luò)通信套接字的時(shí)候,應(yīng)當(dāng)把它們從主機(jī)字節(jié)順序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序;相反,在主機(jī)輸出顯示時(shí),應(yīng)從收到的網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為主機(jī)字節(jié)順序。 在不同機(jī)器上運(yùn)行網(wǎng)絡(luò)程序,解決兼容性問(wèn)題的途徑: 往網(wǎng)絡(luò)上發(fā)送前:將IP地址、端口號(hào)轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序; 從網(wǎng)絡(luò)上接收后:將IP地址、端口號(hào)轉(zhuǎn)換成主機(jī)字節(jié)序。四個(gè)轉(zhuǎn)換函數(shù) 套接字編程接口特為解決這個(gè)問(wèn)題設(shè)置了四個(gè)函數(shù): htons(): 短整數(shù)主機(jī)字節(jié)順序轉(zhuǎn)換為 網(wǎng)絡(luò)字節(jié)順序, 用于端口號(hào)。 htonl(): 長(zhǎng)整數(shù)主機(jī)字節(jié)順序轉(zhuǎn)換為 網(wǎng)絡(luò)字節(jié)順序, 用于IP地址。 說(shuō)明 h 代表host, n 代表 net

16、work;s 代表short,l 代表 long ntohs(): 短整數(shù)網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為 主機(jī)字節(jié)順序,用于端口號(hào)。 ntohl(): 長(zhǎng)整數(shù)網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為 主機(jī)字節(jié)順序,用于IP地址。 這四個(gè)函數(shù)將被轉(zhuǎn)換的數(shù)值作為函數(shù)的入口參數(shù),函數(shù)返回值是轉(zhuǎn)換后的結(jié)果。四個(gè)轉(zhuǎn)換函數(shù) 說(shuō)明 h 代表host, n 代表 network;s 代表short,l 代表 long 3兩個(gè)IP地址轉(zhuǎn)換函數(shù) 在因特網(wǎng)中,IP地址常常用點(diǎn)分十進(jìn)制的表示方法,但在套接字中,IP地址是無(wú)符號(hào)長(zhǎng)整型數(shù),套接字編程接口設(shè)置了兩個(gè)函數(shù),專(zhuān)門(mén)用于兩種形式的IP地址的轉(zhuǎn)換。(1)inet-addr 函數(shù)unsigned lo

17、ng inet_addr(const char* cp) 入口參數(shù)cp:點(diǎn)分十進(jìn)制形式IP地址字符串; 返回值: 無(wú)符號(hào)長(zhǎng)整型的網(wǎng)絡(luò)字節(jié)順序 的IP地址。例:0 x80 00 00 01u_long“128.0.0.1”char *(2)inet_ntoa函數(shù)char* inet_ntoa(struct in_addr in) 入口參數(shù)in:包含無(wú)符號(hào)長(zhǎng)整型IP地址的 in_addr結(jié)構(gòu)變量; 返回值: 指向點(diǎn)分十進(jìn)制IP地址字符串 的指針。 例:0 x80 00 00 01u_longstruct in_addr“128.0.0.1”char * 通常,我們使用域名來(lái)標(biāo)識(shí)站點(diǎn),可以將文字型的

18、主機(jī)域名直接轉(zhuǎn)換成IP地址:struct hostent* gethostbyname( const char* name); 入口參數(shù)name :是站點(diǎn)的主機(jī)域名字符串 返回值: 是指向hostent 結(jié)構(gòu)的指針 hostent結(jié)構(gòu)包含主機(jī)名,主機(jī)別名數(shù)組,返回地址的類(lèi)型(一般是AF_INET),地址長(zhǎng)度字節(jié)數(shù),已符合網(wǎng)絡(luò)字節(jié)順序的IP地址等。 4域名解析函數(shù)上述gethostbyname()域名解析函數(shù)的返回結(jié)構(gòu)hostent為 struct hostent char* h_name; /主機(jī)名 char* h_aliases; /主機(jī)別名列表 short h_addrtype; /返回地

19、址的類(lèi)型 short h_length; /地址的長(zhǎng)度 char* h_addr_list; /主機(jī)IP地址列表(主機(jī)可能多個(gè)IP) #define h_addr h_addr_list0; /主機(jī)IP地址列表中的第一個(gè)地址 ;比如,可以用下面的程序,將主機(jī)域名解析出IP地址: h = gethostbyname(某域名); printf(“host name: %s”, hh_name); printf(“IP address is: %s”, inet_ntoa(*(struct in_addr *)hh_addr);4域名解析函數(shù)2.3 面向連接的套接字編程2.3.1 套接字的工作過(guò)程2

20、.3.2 UNIX套接字編程接口的系統(tǒng)調(diào)用1創(chuàng)建套接字SOCKET() SOCKET過(guò)程創(chuàng)建一個(gè)套接字并返回一個(gè)整型描述符: int socket(int proto_family, int type, int protocol);2 BIND()綁定套接字到指定的地址int bind(int sockfd, struct sockaddr* my_addr, int addrlen);3Listen()啟動(dòng)監(jiān)聽(tīng)int listen( int sockfd, int queue_size); 舉例:listen(sockfd, 10); 圖2.6 監(jiān)聽(tīng)套接字使用緩沖區(qū)接納多個(gè)客戶端的連接請(qǐng)求

21、4ACCEPT() 接受連接請(qǐng)求int accept(int sockfd, struct sockaddr* addr, int* addrlen);舉例:int clientfd; / 定義響應(yīng)套接字描述符變量int addrlen = sizeof(sockaddr); / 獲得套接字地址結(jié)構(gòu)長(zhǎng)度struct sockaddr_in cltsockaddr; / 定義用于返回客戶端地址的結(jié)構(gòu)clientfd = accept(listenfd, (sockaddr*)(&cltsockaddr), &addrlen); / 接受客戶連接請(qǐng)求 5CONNECT()請(qǐng)求建立連接int con

22、nect(int sockfd, struct sockaddr* service_addr, int addrlen);舉例: if (connect(sockfd, (struct sockaddr*)(&serv_addr), sizeof(struct sockaddr)0) 連接服務(wù)器有錯(cuò)時(shí)的報(bào)錯(cuò)處理,并退出 6 READ()和WRITE()讀/寫(xiě)套接字 int read(int sockfd, void* buffer, int len ); int write(int sockfd, void* buffer, int len )7 SEND()和RECV()向套接字發(fā)送/接收i

23、nt send(int sockfd, char* buf, int len, int flags );int recv(int sockfd, char* buf, int len, int flags );8CLOSE()關(guān)閉套接字int close(int sockfd); 2.3.3 面向連接的套接字編程實(shí)例1實(shí)例的功能 服務(wù)器對(duì)來(lái)訪的客戶計(jì)數(shù),并向客戶報(bào)告這個(gè)計(jì)數(shù)值。 客戶建立與服務(wù)器的一個(gè)連接并等待它的輸出。 每當(dāng)連接請(qǐng)求到達(dá)時(shí),服務(wù)器生成一個(gè)可打印的ASCII串信息,將它在連接上發(fā)回,然后關(guān)閉連接。 客戶顯示收到的信息,然后退出。1實(shí)例的功能 例如,對(duì)于服務(wù)器接收的第10次客戶連

24、接請(qǐng)求,該客戶將收到并打印如下信息: This server has been contacted 10 times. 2實(shí)例程序的命令行參數(shù) 實(shí)例是UNIX環(huán)境下的C程序,客戶和服務(wù)器程序在編譯后,均以命令行方式執(zhí)行。 服務(wù)器程序執(zhí)行時(shí)可以帶一個(gè)命令行參數(shù),是用來(lái)表示接受客戶端請(qǐng)求時(shí)的服務(wù)器監(jiān)聽(tīng)套接字的協(xié)議端口號(hào)。 這個(gè)參數(shù)是可選的。如果不指定端口號(hào),代碼將使用程序內(nèi)定的缺省端口號(hào)5188。 2實(shí)例程序的命令行參數(shù) 客戶程序執(zhí)行時(shí)可以帶兩個(gè)命令行參數(shù):一個(gè)是服務(wù)器所在計(jì)算機(jī)的主機(jī)名,另一個(gè)是服務(wù)器監(jiān)聽(tīng)的協(xié)議端口號(hào)。這兩個(gè)參數(shù)都是可選的。 如果沒(méi)有指定協(xié)議端口號(hào),客戶使用程序內(nèi)定的缺省端口51

25、88。 如果一個(gè)參數(shù)也沒(méi)有,客戶使用缺省端口5188和缺省主機(jī)名localhost,localhost是映射到客戶所在計(jì)算機(jī)的一個(gè)別名。 允許客戶與本地機(jī)上的服務(wù)器通信,對(duì)調(diào)試是很有用的。3客戶程序代碼/*-* 程序: client.c* 目的: 創(chuàng)建一個(gè)套接字,通過(guò)網(wǎng)絡(luò)連接一個(gè)服務(wù)器,并打印來(lái)自服務(wù)器的信息* 語(yǔ)法: client host port * host - 運(yùn)行服務(wù)器的計(jì)算機(jī)的名字* port - 服務(wù)器監(jiān)聽(tīng)套接字所用協(xié)議端口號(hào)* 注意:兩個(gè)參數(shù)都是可選的。如果未指定主機(jī)名,客戶* 使用缺省主機(jī)名localhost;如果未指定端口號(hào),客戶* 將使用PROTOPORT中給定的缺省協(xié)

26、議端口號(hào)。*-*/ 3客戶程序代碼#include #include /* UNIX下,套接字的相關(guān)包含文件。*/#include #include #include #include #include #define PROTOPORT 5188 /*缺省協(xié)議端口號(hào)*/extern int errno;char localhost = “l(fā)ocalhost”; /*缺省主機(jī)名*/ 3客戶程序代碼int main(int argc, char *argv) struct hostent *ptrh; /* 指向主機(jī)列表中一個(gè)條目的指針 */ struct sockaddr_in servadd

27、r; /* 存放服務(wù)器端網(wǎng)絡(luò)地址的結(jié)構(gòu) */ int sockfd; /* 客戶端的套接字描述符 */ int port; /* 服務(wù)器端套接字協(xié)議端口號(hào)*/ char* host; /* 服務(wù)器主機(jī)名指針 */ int n; /* 讀取的字符數(shù) */ char buf1000 ; /* 緩沖區(qū),接收服務(wù)器發(fā)來(lái)的數(shù)據(jù) */ 關(guān)于argc、argv的說(shuō)明:例:命令行若鍵入 # client hp1 8080,則參數(shù)個(gè)數(shù) argc=3,參數(shù)字符串?dāng)?shù)組元素 argv0=“client”, argv1=“hp1”, argv2=“8080”,在程序中可引用。memset(char*)&servaddr

28、, 0, sizeof(servaddr); servaddr.sin_family = AF_INET; /*因特網(wǎng)協(xié)議族*/ /*檢查命令行參數(shù),若有則取端口號(hào),否則使用內(nèi)定缺省值*/if (argc2) port = atoi(argv2) /*若指定協(xié)議端口則轉(zhuǎn)換成整數(shù)*/ else port = PROTOPORT; /*否則,使用缺省端口號(hào)*/if (port0) /*若端口號(hào)合法值則將它裝入網(wǎng)絡(luò)地址結(jié)構(gòu)*/ servaddr.sin_port = htons(u_short)port)else /* 否則,打印錯(cuò)誤信息并退出*/ fprintf(stderr,”bad port

29、number %sn”,argv2); exit(1);3客戶程序代碼/* 檢查主機(jī)參數(shù)并指定主機(jī)名 */if(argc1) host = argv1; /* 如果指定了主機(jī)名參數(shù),就使用它 */else host = localhost; /* 否則,使用缺省值 */ 3客戶程序代碼/* 將主機(jī)名轉(zhuǎn)換成相應(yīng)的IP地址并復(fù)制到servaddr 結(jié)構(gòu)中 */ptrh = gethostbyname(host); /*從服務(wù)器主機(jī)名得到相應(yīng)IP地址*/If (char *)ptrh = null) /*檢查主機(jī)名的有效性,無(wú)效則退出*/ fprintf( stderr, ”invalid host

30、: %sn”, host ); exit(1);memcpy(&servaddr.sin_addr, ptrh-h_addr, ptrh-h_length); 3客戶程序代碼/* 創(chuàng)建一個(gè)套接字*/sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0) fprintf(stderr, ”socket creation failedn” ); exit(1);/* 請(qǐng)求連接到服務(wù)器 */if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr) 0) write(1,b

31、uf, n); /*1stdout設(shè)備(即顯示器), 0stdin設(shè)備 n = recv(sockfd, buf, sizeof( buf ), 0 ); /* 關(guān)閉套接字*/ closesocket(sockfd); /* 終止客戶程序*/ exit(0); 3客戶程序代碼4服務(wù)器實(shí)例代碼/*-* 程序:server.c* 目的: 分配一個(gè)套接字,然后反復(fù)執(zhí)行如下幾步:* (1) 等待客戶的下一個(gè)連接* (2) 發(fā)送一個(gè)短消息給客戶* (3) 關(guān)閉與客戶的連接* (4) 轉(zhuǎn)向(1)步* 命令行語(yǔ)法: server port * port 服務(wù)器端監(jiān)聽(tīng)套接字使用的協(xié)議端口號(hào)* 注意: 端口號(hào)可

32、選。如果未指定端口號(hào),服務(wù)器使用PROTOPORT中* 指定的缺省端口號(hào)*-*/ 4服務(wù)器實(shí)例代碼#include #include #include #include #include #include #define PROTOPORT 5188 /*監(jiān)聽(tīng)套接字的缺省協(xié)議端口號(hào)*/#define QLEN 6 /*監(jiān)聽(tīng)套接字的請(qǐng)求隊(duì)列大小*/int visits = 0; /* 對(duì)于客戶連接的計(jì)數(shù)*/ int main(argc, argv)int argc;char* argv;struct hostent *ptrh; /*指向主機(jī)列表中一個(gè)條目的指針*/struct sockaddr

33、_in servaddr; /*存放服務(wù)器網(wǎng)絡(luò)地址的結(jié)構(gòu)*/struct sockaddr_in clientaddr; /*存放客戶網(wǎng)絡(luò)地址的結(jié)構(gòu)*/int listenfd; /*監(jiān)聽(tīng)套接字描述符*/int clientfd; /*響應(yīng)套接字描述符*/int port; /*協(xié)議端口號(hào)*/int alen; /*地址長(zhǎng)度*/char buf1000; /*供服務(wù)器發(fā)送字符串所用的緩沖區(qū)*/ 4服務(wù)器實(shí)例代碼memset(char*)&servaddr, 0, sizeof(servaddr); /*清空sockaddr結(jié)構(gòu)*/servaddr.sin_family = AF_INET; /

34、*設(shè)置為因特網(wǎng)協(xié)議族*/servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /*設(shè)置本地IP地址*/*檢查命令行參數(shù),若指定了,就用該端口號(hào),否則使用缺省端口號(hào)*/if (argc 1) port = atoi(argv1); /*如果指定了端口號(hào),就將它轉(zhuǎn)換成整數(shù)*/else port = PROTOPORT; /*否則,使用缺省端口號(hào)*/ 4服務(wù)器實(shí)例代碼if (port 0) /* 測(cè)試端口號(hào)是否合法 */ servaddr.sin_port = htons(u_short)port);else /* 打印錯(cuò)誤信息并退出 */ fprintf( s

35、tderr, ”bad portnumber %sn”, argv1 ); exit(1);/* 創(chuàng)建一個(gè)用于監(jiān)聽(tīng)的流式套接字 */listenfd = SOCKET(AF_INET, SOCK_STREAM, 0);if (listenfd 0) fprintf( stderr, “socket creation failedn” ); exit(1); 4服務(wù)器實(shí)例代碼/* 將本地地址綁定到監(jiān)聽(tīng)套接字*/if ( bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr) ) 0 ) fprintf(stderr, ”bind

36、 failedn” ); exit(1);/* 開(kāi)始監(jiān)聽(tīng),并指定監(jiān)聽(tīng)套接字請(qǐng)求隊(duì)列的長(zhǎng)度 */if (listen(listenfd, QLEN) 0) fprintf(stderr, ”listen filedn” ); exit(1); 4服務(wù)器實(shí)例代碼 while(1) /*服務(wù)器主循環(huán)-接受和處理來(lái)自客戶端的連接請(qǐng)求*/ alen = sizeof(clientaddr); /*接受客戶端連接請(qǐng)求,并生成響應(yīng)套接字*/ if(clientfd=accept(listenfd,(struct sockaddr *)&clientaddr, &alen) 0 ) fprintf( stde

37、rr, “accept failedn”); exit(1); visits+; /*累加訪問(wèn)的客戶數(shù)*/ sprintf(buf, “This server has been contacted %d time.n”, visits ); send(clientfd, buf, strlen(buf), 0 ); /*向客戶端發(fā)送信息*/ closesocket(clientfd); /*關(guān)閉響應(yīng)套接字*/ closesocket(listenfd); /*關(guān)閉監(jiān)聽(tīng)套接字*/ 4服務(wù)器實(shí)例代碼關(guān)于阻塞的問(wèn)題 圖2.7 服務(wù)器進(jìn)程因調(diào)用ACCEPT()而被阻塞 2.3.4 進(jìn)程的阻塞問(wèn)題和對(duì)策

38、1什么是阻塞 阻塞是指一個(gè)進(jìn)程執(zhí)行了一個(gè)函數(shù)或者系統(tǒng)調(diào)用,該函數(shù)由于某種原因不能立即完成,因而不能返回調(diào)用它的進(jìn)程,導(dǎo)致進(jìn)程受控于這個(gè)函數(shù)而處于等待的狀態(tài),進(jìn)程的這種狀態(tài)稱(chēng)為阻塞。 2.3.4 進(jìn)程的阻塞問(wèn)題和對(duì)策圖2.8 RECV()函數(shù)的兩種執(zhí)行方式 注: recv()函數(shù)究竟按阻塞方式還是非阻塞方式執(zhí)行,取決于程序開(kāi)始時(shí)的設(shè)置,默認(rèn)方式下,recv()函數(shù)按阻塞方式執(zhí)行。 2能引起阻塞的套接字調(diào)用 在Berkeley套接字網(wǎng)絡(luò)編程接口的模型中,套接字的默認(rèn)行為是阻塞的,具體地說(shuō),在一定情況下,有以下操作套接字的系統(tǒng)調(diào)用會(huì)引起進(jìn)程阻塞: (1)accept() (2)read()、recv

39、() 和 readfrom() (3)write()、send() 和 sendto() (4)connect() (5)select() (6)closesocket() 3阻塞工作模式帶來(lái)的問(wèn)題圖2.9 采用阻塞工作模式的服務(wù)器不能很好地為多個(gè)客戶服務(wù) 采用阻塞工作模式的單進(jìn)程服務(wù)器是不能很好地同時(shí)為多個(gè)客戶服務(wù)的。下圖是一個(gè)例子。 4一種解決方案 利用 UNIX/Linux 操作系統(tǒng)的 fork() 系統(tǒng)調(diào)用,編制多進(jìn)程并發(fā)執(zhí)行的服務(wù)器程序,可以用創(chuàng)建子進(jìn)程的辦法實(shí)現(xiàn)。主進(jìn)程對(duì)于每一個(gè)連上來(lái)上的客戶端,專(zhuān)門(mén)創(chuàng)建一個(gè)子進(jìn)程為它服務(wù),這樣,通過(guò)主進(jìn)程和各個(gè)子進(jìn)程的并發(fā)執(zhí)行,來(lái)實(shí)現(xiàn)服務(wù)器端對(duì)多

40、個(gè)客戶的并發(fā)服務(wù)。Unix / Linux 系統(tǒng)調(diào)用 fork() 的特點(diǎn)進(jìn)程在調(diào)用fork()時(shí),會(huì)將自己拷貝一份,一份為父進(jìn)程,另一份為子進(jìn)程。CPU會(huì)分別調(diào)度執(zhí)行。在各進(jìn)程中調(diào)用fork()后的返回值: 父進(jìn)程:fork() 返回值為正(為新建的子進(jìn)程的進(jìn)程號(hào)) 子進(jìn)程:fork() 返回值為 0, 出錯(cuò)時(shí):fork() 返回值為負(fù)。因此,根據(jù)fork()返回值就可分清當(dāng)前進(jìn)程是父進(jìn)程還是子進(jìn)程。另外,調(diào)用fork()前的父進(jìn)程中每個(gè)打開(kāi)的套接字描述符,在fork()返回后會(huì)被父進(jìn)程和子進(jìn)程共享。此時(shí)因?yàn)橛懈?、?個(gè)進(jìn)程共享,故每個(gè)套接字描述符引用計(jì)數(shù) reference count=2

41、,以后,該共享的套接字描述符在各進(jìn)程中用close()每關(guān)閉1次,引用計(jì)數(shù)值count就會(huì)減1,當(dāng)套接字描述符的引用計(jì)數(shù)值count被減為0時(shí),此套接字才真正被close,所占用資源才被釋放。這時(shí)服務(wù)端結(jié)點(diǎn)會(huì)發(fā)送出首部FIN標(biāo)志為1的TCP段,進(jìn)入釋放TCP連接的過(guò)程。父進(jìn)程主代碼 .If (pid = fork() = 0) . 子進(jìn)程代碼 exit(0); else if (pid 0) 報(bào)錯(cuò)信息 .父進(jìn)程主代碼 .使用 fork() 時(shí)基本的編程框架是:若fork()返回值pid=0,該部分代碼為子進(jìn)程若fork()返回值pid=負(fù),則進(jìn)行出錯(cuò)處理若fork()返回值pid=正,該部分代

42、碼為父進(jìn)程 父進(jìn)程 父進(jìn)程 子進(jìn)程 典型的并發(fā)服務(wù)器編程框架listenfd = socket(); /監(jiān)聽(tīng)套接字bind(listenfd, ); /綁定監(jiān)聽(tīng)套接字listen(listenfd, LISTENQ); /啟動(dòng)監(jiān)聽(tīng)for( ; ; ) connfd = accept(listenfd, ); /接受客戶連接,生成連接套接字 if (pid = fork() = 0) close(listenfd); /子進(jìn)程關(guān)閉監(jiān)聽(tīng)套接字 do_it(connfd); /在連接套接字上處理該客戶請(qǐng)求 close(connfd); /結(jié)束該客戶處理, 關(guān)閉連接套接字 exit(0); /子進(jìn)程終

43、止 close(connfd); /父進(jìn)程關(guān)閉連接套接字 注:詳情可參見(jiàn)Unix網(wǎng)絡(luò)編程第2版 第1卷4.7 - 4.8舉例:#include #include #include #include int main(int argc, char* argv) int listenfd, clientfd, pid; struct sockaddr_in ssockaddr, csockaddr; char buffer1024; int addrlen, n; Unix / Linux 多進(jìn)程并發(fā)服務(wù)器例Unix / Linux 多進(jìn)程并發(fā)服務(wù)器例/* 創(chuàng)建監(jiān)聽(tīng)套接字 */listenfd =

44、 socket(AF_INET, SOCK_STREAM, 0);if (listenfd 0) fprintf(stderr, socket error!n); exit(1); /* 為監(jiān)聽(tīng)套接字綁定網(wǎng)絡(luò)地址 */memset(&ssockaddr, 0, sizeof(struct sockaddr_in);ssockaddr.sin_family = AF_INET;ssockaddr.sin_addr.s_addr = htonl(INADDR_ANY);ssockaddr.sin_port = htons(8080);If (bind(listenfd, &ssockaddr, s

45、izeof(struct sockaddr_in) 0) buffern = 0; /串尾標(biāo)記0 printf(Client Send: %s, buffer); write(clientfd, buffer, n); /同樣數(shù)據(jù)回送給客戶端if (n 0) fprintf( stderr, read error!n); exit(3); Unix / Linux 多進(jìn)程并發(fā)服務(wù)器例 /* 通信完畢,子進(jìn)程將關(guān)閉與這個(gè)客戶連接的套接字,此時(shí) n=0 */ printf(client %s closed!n, inet_ntoa(csockaddr.sin_addr); close(client

46、fd); /* 子進(jìn)程關(guān)閉客戶連接套接字 */ exit(0); /* 子進(jìn)程終止 */ else if (pid 0) printf(“fork failed!n”); /pid0時(shí),為出錯(cuò)處理 close(clientfd); /* 主進(jìn)程,只關(guān)心監(jiān)聽(tīng)套接字,不關(guān)心每個(gè)客戶的 連接套接字,所以關(guān)閉這個(gè)客戶連接套接字 */ /* end of while(1),結(jié)束服務(wù)器處理各個(gè)客戶端的連接請(qǐng)求 */ close(listenfd); /* 主進(jìn)程關(guān)閉監(jiān)聽(tīng)套接字 */ exit(0); /* 主進(jìn)程終止 */ Unix / Linux 多進(jìn)程并發(fā)服務(wù)器例2.4 無(wú)連接的套接字編程2.4.1

47、無(wú)連接的套接字編程的兩種模式 使用數(shù)據(jù)報(bào)套接字開(kāi)發(fā)網(wǎng)絡(luò)應(yīng)用程序,既可以采用客戶/服務(wù)器模式,也可以采用對(duì)等模式。圖2.10 對(duì)等模式的數(shù)據(jù)報(bào)套接字的編程模型 1對(duì)等模式 2客戶/服務(wù)器模式 圖2.11 C/S模式的數(shù)據(jù)報(bào)套接字的編程模型(可多個(gè)客戶端) 2.4.2 兩個(gè)數(shù)據(jù)報(bào)專(zhuān)用的系統(tǒng)調(diào)用1發(fā)送數(shù)據(jù)報(bào) SENDTO() int sendto(int sockfd, const void* msg, /*發(fā)送緩沖區(qū)*/ int len, unsigned int flags, /*一般置為0*/ struct sockaddr* to, /*接收方套接字地址*/ int tolen); 2接收數(shù)

48、據(jù)報(bào) RECVFROM() int recvfrom(int sockfd, void* buf, /*接收緩沖區(qū)*/ int len, unsigned int flags, /*一般置為0*/ struct sockaddr* from, /*發(fā)送方套接字地址*/ int* fromlen) 2.4.3 數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例聊天程序命令行: #chat 目的IP 目的端口 源IP 源端口#include #include #include #include #include #include /* 聲明一個(gè)定時(shí)器超時(shí)的中斷處理例程 */void int_proc(int sign

49、o) /* signo為Unix系統(tǒng)的信號(hào)值 */數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例int main(int argc, char* argv) struct sockaddr_in daddr, saddr, cmpaddr; int sockfd; int timer = 3; char buffer1024; int addrlen, n; /* 判斷用戶輸入的命令行是否正確,如果有錯(cuò),提示用法 */ if (argc != 5) printf(用法:%s 目的IP 目的端口 源IP 源端口n, argv0); exit(1); /* 設(shè)定中斷處理函數(shù),并設(shè)置時(shí)間限制 */ signal(S

50、IGALRM, int_proc); /*若定時(shí)器超時(shí),則執(zhí)行例程int_proc()*/ alarm(timer); /* 設(shè)定一個(gè)3秒的報(bào)警時(shí)鐘 */ /* 建立數(shù)據(jù)報(bào)套接字 */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd 0) fprintf( stderr, socket error!n); exit(1); 數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例/* 為結(jié)構(gòu)變量daddr的各個(gè)字段賦值 */addrlen = sizeof(struct sockaddr_in);memset(&daddr, 0, addrlen);daddr.s

51、in_family = AF_INET;daddr.sin_port = htons(atoi(argv2);if (inet_pton(AF_INET, argv1, &daddr.sin_addr ) = 0) fprintf(stderr, “Invaild dest IP!n”); /*stderr為系統(tǒng)標(biāo)準(zhǔn)報(bào)錯(cuò)設(shè)備*/ exit(1);數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例 int inet_pton(int af, const char *src, void *dst),這個(gè)函數(shù)將點(diǎn)分十進(jìn)制IP地址字符串轉(zhuǎn)換到長(zhǎng)整型的網(wǎng)絡(luò)地址,第一個(gè)參數(shù)af是地址族,第二個(gè)參數(shù)*src是點(diǎn)分十進(jìn)制IP來(lái)源

52、地址,第三個(gè)參數(shù)* dst是接受轉(zhuǎn)換后的長(zhǎng)整型數(shù)據(jù)。/* 為結(jié)構(gòu)變量saddr的各個(gè)字段賦值 */addrlen = sizeof(struct sockaddr_in);memset(&saddr, 0, addrlen);saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv4);if (inet_pton(AF_INET, argv3, &saddr.sin_addr ) = 0) fprintf(stderr, Invaild source IP!n); exit(0); 數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例/* 綁定地址 */

53、if (bind(sockfd, &saddr, addrlen) 0 ) fprintf( stderr, bind local address error!n); exit(1);/* 從標(biāo)準(zhǔn)輸入即鍵盤(pán)獲得字符串放入緩沖后,發(fā)送給目標(biāo)地址 */if (fgets(buffer,1024,stdin) = NULL ) exit(0);if (sendto(sockfd,buffer,strlen(buffer),0,&daddr,addrlen)0) fprintf( stderr, sendto error!n); exit(2); 數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例while (1) /*

54、 接收信息并顯示 */ n = recvfrom(sockfd,buffer,1024,0,&cmpaddr,&daddrlen); if (n 0) /*根據(jù)errno數(shù)值是否常量EWOULDBLOCK,區(qū)別超時(shí)錯(cuò)和一般性錯(cuò)*/ if ( errno = EWOULDBLOCK) fprintf(stderr, recvfrom timeout error!n); else fprintf(stderr, recvfrom error!n); exit(3); 數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例 else /* 比較數(shù)據(jù)報(bào)來(lái)源地址cmpaddr與命令行參數(shù)中想要與之聊天的目標(biāo)地址daddr是否一

55、致: */ if (memcmp(cmpaddr, daddr, addrlen) continue; /* 若兩個(gè)地址不同,則memcmp()返回非0,不是要聊天的那臺(tái) 機(jī)器發(fā)來(lái)的數(shù)據(jù)報(bào),因此結(jié)束此循環(huán) */ buffern = 0; /* 兩個(gè)地址相同,是要聊天的那臺(tái)機(jī)器發(fā)來(lái)的數(shù) 據(jù)報(bào),因此準(zhǔn)備送顯示,先將數(shù)據(jù)最后結(jié)束處添0 */ printf( “Received: %s”, buffer); /* 然后送顯示 */ 數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例 /* 從標(biāo)準(zhǔn)輸入即鍵盤(pán)獲得字符串,準(zhǔn)備對(duì)對(duì)方發(fā)來(lái)數(shù)據(jù)進(jìn)行響應(yīng) */ if (fgets(buffer,1024,stdin) = NULL

56、) exit(0); /* 發(fā)送給目標(biāo)地址 */ if (sendto(sockfd,buffer,strlen(buffer),0,&daddr,addrlen)0) fprintf(stderr, sendto error!n); exit(3); /* 關(guān)閉套接字 */ close(sockfd);數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例2.5 原始套接字 (Raw Socket) 利用原始套接字 ,可以訪問(wèn)基層的網(wǎng)絡(luò)協(xié)議,如IP(網(wǎng)際協(xié)議)、ICMP(Internet控制消息協(xié)議)、IGMP(Internet組管理協(xié)議)等。很多網(wǎng)絡(luò)實(shí)用工具,如traceroute、ping、網(wǎng)絡(luò)嗅探器(snif

57、fer)程序等,就是利用原始套接字實(shí)現(xiàn)的。 Raw socket的作用主要在三個(gè)方面:1. 通過(guò)raw socket接收發(fā)向本機(jī)的 ICMP/IGMP信包、數(shù)據(jù)鏈 路層幀, 或者用來(lái)發(fā)送ICMP/IGMP信包、數(shù)據(jù)鏈路層幀;2. 接收、發(fā)送本機(jī)TCP/IP棧不能識(shí)別處理的IP信包(如開(kāi)發(fā)本 機(jī)內(nèi)核中還沒(méi)有實(shí)現(xiàn)的基于IP的OSPF協(xié)議或自定義協(xié)議);3. 用來(lái)發(fā)送一些自己規(guī)定源地址等特殊作用的IP包(如以偽造 自己源IP地址、源端口寫(xiě)IP頭、TCP頭等等的hacker行為)2.5.1 原始套接字的創(chuàng)建 格式一 (Unix/Linux): int sockRaw=socket(AF_INET, SOCK_RAW, protocol);格式二 (Windows):SOCKET sockRaw=WSASocket(AF_INET, SOCK_RAW, protocol, NULL, 0, 0); 參數(shù) protocol 的取值 要想收到什么樣的數(shù)據(jù)包,就應(yīng)在參數(shù) protocol 里指定相應(yīng)的協(xié)議類(lèi)型,取符號(hào)常量值如下: IPPROTO_ICMP 1/* ICMP協(xié)議 */ IPPROTO_IGMP2 /*

溫馨提示

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