網(wǎng)絡(luò)編程實(shí)用教程_第2章.ppt_第1頁(yè)
網(wǎng)絡(luò)編程實(shí)用教程_第2章.ppt_第2頁(yè)
網(wǎng)絡(luò)編程實(shí)用教程_第2章.ppt_第3頁(yè)
網(wǎng)絡(luò)編程實(shí)用教程_第2章.ppt_第4頁(yè)
網(wǎng)絡(luò)編程實(shí)用教程_第2章.ppt_第5頁(yè)
已閱讀5頁(yè),還剩85頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、第2章 UNIX中的套接字網(wǎng)絡(luò)編程接口,UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展過程 套接字與UNIX操作系統(tǒng)的關(guān)系 套接字編程的基本概念 套接字的特點(diǎn)、應(yīng)用場(chǎng)合、使用的數(shù)據(jù)類型 面向連接的套接字編程 套接字的工作過程、系統(tǒng)調(diào)用、編程實(shí)例 借助實(shí)例分析進(jìn)程的阻塞問題和對(duì)策 無連接的套接字編程 無連接套接字編程的兩種模式(C/S和對(duì)等) 數(shù)據(jù)報(bào)套接字的對(duì)等模式編程實(shí)例,2.1 UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展,2.1.1 問題的提出 應(yīng)用程序與協(xié)議軟件進(jìn)行交互時(shí)須說明許多細(xì)節(jié): 是服務(wù)器還是客戶機(jī),主動(dòng)還是被動(dòng)通信? 發(fā)送方需說明發(fā)送的數(shù)據(jù); 接收方需說明接收的數(shù)據(jù)如何存放。 站在應(yīng)用程序?qū)?/p>

2、現(xiàn)的角度,應(yīng)用程序如何方便地使用協(xié)議棧軟件進(jìn)行通信呢? 如果能在應(yīng)用程序與協(xié)議棧軟件之間提供一個(gè)軟件接口,就可以方便客戶與服務(wù)器軟件的編程。 UNIX最早將TCP/IP協(xié)議簇集成到內(nèi)核中,UNIX的開發(fā)者提出并實(shí)現(xiàn)了套接字應(yīng)用編程接口。,套接字應(yīng)用程序編程接口:是網(wǎng)絡(luò)應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧進(jìn)行通信時(shí)所使用的接口,即應(yīng)用程序與協(xié)議棧軟件之間的接口,簡(jiǎn)稱套接字編程接口(Socket API)。 定義了應(yīng)用程序與協(xié)議棧軟件進(jìn)行交互時(shí)可以使用的一組操作,決定了應(yīng)用程序使用協(xié)議棧的方式、應(yīng)用程序所能實(shí)現(xiàn)的功能、以及開發(fā)具有這些功能的程序的難度。 套接字編程接口給出了應(yīng)用程序能夠調(diào)用的一組過程,以及這些過

3、程所需的參數(shù),每個(gè)獨(dú)立的過程完成一個(gè)與協(xié)議棧軟件交互的基本操作(如:建立連接、接收數(shù)據(jù)、釋放鏈接)。,2.1.2 套接字編程接口的起源與應(yīng)用 加州大學(xué)伯克利分校開發(fā)了一個(gè)包括TCP/IP協(xié)議簇的BSD UNIX,并迅速得到推廣,套接字編程接口是這個(gè)操作系統(tǒng)一部分。 TCP/IP標(biāo)準(zhǔn)并沒有定義應(yīng)用程序用來與該協(xié)議進(jìn)行交互的應(yīng)用程序編程接口,只規(guī)定了應(yīng)該提供的一般操作,并允許各個(gè)操作系統(tǒng)去定義用來實(shí)現(xiàn)這些操作的具體API。 一個(gè)協(xié)議標(biāo)準(zhǔn)可能只是建議某個(gè)操作在應(yīng)用程序發(fā)送數(shù)據(jù)時(shí)是需要的,而由應(yīng)用程序編程接口來定義具體的函數(shù)名和每個(gè)參數(shù)的類型。,盡管協(xié)議標(biāo)準(zhǔn)允許操作系統(tǒng)設(shè)計(jì)者開發(fā)自己的應(yīng)用程序編程接口

4、,但由于BSD UNIX的廣泛使用,后來的許多操作系統(tǒng)及編程語(yǔ)言都選擇了對(duì)套接字編程接口的支持。 由于這個(gè)套接字規(guī)范最早是由Berkeley大學(xué)開發(fā)的,一般將它稱為Berkeley Sockets規(guī)范。 Berkeley Sockets規(guī)范規(guī)定了一系列與套接字使用有關(guān)的庫(kù)函數(shù),為在UNIX操作系統(tǒng)下不同計(jì)算機(jī)中的應(yīng)用程序進(jìn)程之間,使用TCP/IP協(xié)議簇進(jìn)行網(wǎng)絡(luò)通信提供了一套應(yīng)用程序編程接口。,2.1.3 套接字編程接口的兩種實(shí)現(xiàn)方式 采用兩種實(shí)現(xiàn)套接字編程接口的方式: 在操作系統(tǒng)的內(nèi)核中增加相應(yīng)的軟件來實(shí)現(xiàn); 通過開發(fā)操作系統(tǒng)之外的函數(shù)庫(kù)來實(shí)現(xiàn)。 在BSD UNIX及起源于它的操作系統(tǒng)中,套接

5、字函數(shù)是操作系統(tǒng)本身的功能調(diào)用,是操作系統(tǒng)內(nèi)核的一部分。 其他操作系統(tǒng)供應(yīng)商為了不修改基本操作系統(tǒng),開發(fā)了套接字庫(kù)(Socket Library)來提供套接字編程接口。 套接字庫(kù)中的每個(gè)過程具有與UNIX套接字函數(shù)相同的名字與參數(shù),向沒有本機(jī)套接字的操作系統(tǒng)上的應(yīng)用程序提供套接字編程接口。,套接字庫(kù)與操作系統(tǒng)內(nèi)核中實(shí)現(xiàn)的套接字在語(yǔ)義上是相同的。 應(yīng)用程序調(diào)用套接字過程不必管它是由操作系統(tǒng)內(nèi)核過程提供的,還是由庫(kù)過程提供的。 這種方式提供了程序的可移植性:將程序從一臺(tái)計(jì)算機(jī)移植到另一臺(tái)計(jì)算機(jī)時(shí),程序的源代碼不需改動(dòng),只要用新計(jì)算機(jī)上的套接字庫(kù)重新編譯即可。 套接字庫(kù)與操作系統(tǒng)直接提供的本機(jī)套接字

6、編程接口在實(shí)現(xiàn)上是不同的。 套接字庫(kù)的過程需要鏈接到應(yīng)用程序中; 并駐留于應(yīng)用程序地址空間; 調(diào)用時(shí)控制從應(yīng)用程序轉(zhuǎn)向庫(kù)程序,并進(jìn)一步調(diào)用一個(gè)或多個(gè)底層操作系統(tǒng)的功能調(diào)用。,2.1.4 套接字通信與UNIX操作系統(tǒng)的輸入/輸出 套接字編程接口采用傳統(tǒng)的UNIX輸入/輸出模式。 UNIX操作系統(tǒng)對(duì)文件和所有其它的輸入/輸出設(shè)備采用一種統(tǒng)一的操作模式,就是“打開-讀-寫-關(guān)閉”(open - read - write - close)的I/O模式。 調(diào)用open命令獲得對(duì)指定文件或設(shè)備的使用權(quán),并返回一個(gè)用來標(biāo)識(shí)該文件或設(shè)備的短整型描述符,作為用戶在打開的文件或設(shè)備上進(jìn)行I/O的句柄。 多次調(diào)用r

7、ead或write命令來傳輸數(shù)據(jù),期間用描述符作為命令的參數(shù),指明要操作的對(duì)象。 傳輸完成后調(diào)用close命令,通知操作系統(tǒng)已經(jīng)完成了對(duì)某對(duì)象的調(diào)用,釋放所占用的資源。,當(dāng)TCP/IP協(xié)議被集成到UNIX內(nèi)核中的時(shí)候,相當(dāng)于在UNIX系統(tǒng)中引入了一種新型的I/O操作。 應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧來交換數(shù)據(jù)。 操作系統(tǒng)和應(yīng)用程序都將套接字編程接口也看作一種輸入/輸出機(jī)制。 操作過程類似,創(chuàng)建套接字-使用-刪除; 操作方法類似,申請(qǐng)生成一個(gè)套接字后,系統(tǒng)返回一個(gè)短整型描述符來標(biāo)識(shí)這個(gè)套接字對(duì)象; 使用的過程名可以是相同的,如write過程可以將數(shù)據(jù)發(fā)送給另一個(gè)程序、文件或網(wǎng)絡(luò)中的另一個(gè)進(jìn)程。,UNIX

8、系統(tǒng)對(duì)于各種I/O的集成提供了靈活性。 應(yīng)用程序可以編寫成向任何地方傳輸數(shù)據(jù),取決于描述符對(duì)象代表什么(設(shè)備、文件、套接字)。 系統(tǒng)對(duì)套接字和其它I/O使用相同的描述符空間,使得單個(gè)應(yīng)用程序既可以進(jìn)行網(wǎng)絡(luò)通信,又可以實(shí)現(xiàn)本地?cái)?shù)據(jù)傳輸。,用戶進(jìn)程與網(wǎng)絡(luò)協(xié)議的交互,實(shí)際要比用戶進(jìn)程與傳統(tǒng)I/O設(shè)備的交互復(fù)雜得多。 僅提供open、read、write、close四個(gè)過程遠(yuǎn)不夠. 使用套接字的應(yīng)用程序必須說明許多細(xì)節(jié)。 應(yīng)用程序使用的協(xié)議簇、遠(yuǎn)程計(jì)算機(jī)的地址、該應(yīng)用程序是客戶機(jī)還是服務(wù)器、希望的服務(wù)類型是面向連接的還是無連接的,等等。 為了提供這些細(xì)節(jié),每個(gè)套接字有許多參數(shù)與選項(xiàng),需要應(yīng)用程序提供具

9、體值。 為避免單個(gè)套接字函數(shù)參數(shù)過多,套接字編程接口的設(shè)計(jì)者定義了多個(gè)函數(shù)。 例如,創(chuàng)建套接字時(shí),先調(diào)用一個(gè)函數(shù)創(chuàng)建套接字,再調(diào)用其它函數(shù)說明使用套接字的細(xì)節(jié)。,2.2 套接字編程的基本概念,圖2.1 電插座與電話插座的作用,2.2.1 什么是套接字(SOCKET),套接字是對(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.2 應(yīng)用進(jìn)程、套接口、網(wǎng)絡(luò)協(xié)議棧及操作系統(tǒng)的關(guān)系,兩個(gè)應(yīng)用進(jìn)程只要分別連接到自己的套接字,就可以通過網(wǎng)絡(luò)痛惜,不用去管復(fù)雜的網(wǎng)絡(luò)結(jié)構(gòu)及數(shù)據(jù)傳輸過程。,從多個(gè)層面來理解套接字這個(gè)

10、概念的內(nèi)涵 從所處的地位來講,套接字上聯(lián)應(yīng)用進(jìn)程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧進(jìn)行通信的接口,是應(yīng)用程序與網(wǎng)絡(luò)協(xié)議棧交互的接口. 從實(shí)現(xiàn)的角度來講,非常復(fù)雜。套接字是一個(gè)復(fù)雜的軟件機(jī)構(gòu),包含了一定的數(shù)據(jù)結(jié)構(gòu),包含許多選項(xiàng),由操作系統(tǒng)內(nèi)核管理。 從使用的角度來講,非常簡(jiǎn)單。對(duì)套接字的操作形成了一種網(wǎng)絡(luò)應(yīng)用程序的編程接口(API),提供了一組系統(tǒng)調(diào)用或庫(kù)函數(shù),可以用于構(gòu)造套接字、安裝綁定套接字、連接套接字、通過套接字交換數(shù)據(jù)、關(guān)閉套接字,實(shí)現(xiàn)各種分布式應(yīng)用。 套接字編程接口是一套操作套接字的編程接口函數(shù),套接字是它的操作對(duì)象。,2.2.2 套接字的特點(diǎn) 1通信域 通信域:是一個(gè)計(jì)算機(jī)網(wǎng)

11、絡(luò)的范圍,在這個(gè)范圍中,所有的計(jì)算機(jī)使用同一種網(wǎng)絡(luò)體系結(jié)構(gòu)及協(xié)議棧。 套接字存在于通信域中。 套接字通常只和同一域中的套接字交換數(shù)據(jù)。 如果數(shù)據(jù)交換要穿越域的邊界,就一定要執(zhí)行某種解釋程序。 這里,僅僅針對(duì)Internet域,并且使用Internet協(xié)議族(即TCP/IP協(xié)議族)來通信。,2套接字具有三種類型 每一個(gè)正被使用的套接字都有它確定的類型。 只有相同類型的套接字才能相互通信。 (1) 數(shù)據(jù)報(bào)套接字(Datagram SOCKET) 數(shù)據(jù)報(bào)套接字提供無連接的、不保證可靠的、獨(dú)立的數(shù)據(jù)報(bào)傳輸服務(wù)。 在Internet通信域中,數(shù)據(jù)報(bào)套接字使用UDP數(shù)據(jù)報(bào)協(xié)議形成的進(jìn)程間通路,具有UDP協(xié)

12、議為上層所提供的服務(wù)的所有特點(diǎn)。 一般用于輕載通信,并具有多播通信的能力。,圖2.3 在Internet通信域中,數(shù)據(jù)報(bào)套接字基于UDP協(xié)議,(2) 流式套接字(Stream SOCKET) 流式套接字提供雙向的、有序的、無重復(fù)的、無記錄邊界的可靠的數(shù)據(jù)流傳輸服務(wù)。 在Internet通信域中,流式套接字使用TCP協(xié)議形成的進(jìn)程間通路,具有TCP協(xié)議為上層所提供的服務(wù)的所有特點(diǎn)。 在使用流式套接字傳輸數(shù)據(jù)之前,必須在數(shù)據(jù)的發(fā)送端和接收端之間建立連接。 一般用于交換大批量的數(shù)據(jù)時(shí),或者要求數(shù)據(jù)按照發(fā)送的順序無重復(fù)的到達(dá)目的地的時(shí)候。,圖2.4 在Internet通信域中,流式套接字基于TCP協(xié)議

13、,(3) 原始式套接字(RAW SOCKET) 原始式套接字允許對(duì)較低層次的協(xié)議(如IP、ICMP)直接訪問,用于檢驗(yàn)新協(xié)議的實(shí)現(xiàn)。 原始套接字保存了數(shù)據(jù)包中的完整IP頭; 前面兩種套接字只能收到用戶數(shù)據(jù); 因此可以通過原始套接字對(duì)數(shù)據(jù)進(jìn)行分析。,3套接字的創(chuàng)建 套接字由應(yīng)用層的通信進(jìn)程創(chuàng)建,并為其服務(wù)。 即,每一個(gè)套接字都有一個(gè)相關(guān)的應(yīng)用進(jìn)程,操作該套接字的代碼是該進(jìn)程的組成部分。 4使用確定的IP地址和傳輸層端口號(hào) 在生成套接字的描述符后,要將套接字與計(jì)算機(jī)上的特定的IP地址和傳輸層端口號(hào)相關(guān)聯(lián),這個(gè)過程稱為綁定。 一個(gè)套接口要使用一個(gè)確定的三元組網(wǎng)絡(luò)地址信息,才能使它在網(wǎng)絡(luò)中唯一地被標(biāo)識(shí)

14、。,2.2.3 套接字的應(yīng)用場(chǎng)合 并非所有的網(wǎng)絡(luò)應(yīng)用編程都要使用套接字。 套接字適合開發(fā)具有如下特點(diǎn)的新網(wǎng)絡(luò)應(yīng)用。 不管是采用對(duì)等模式或者客戶機(jī)/服務(wù)器模式,通信雙方的應(yīng)用程序都需要開發(fā)。 雙方所交換數(shù)據(jù)的結(jié)構(gòu)和交換數(shù)據(jù)的順序有特定的要求,不符合現(xiàn)在成熟的應(yīng)用層協(xié)議,甚至需要自己去開發(fā)應(yīng)用層協(xié)議,自己設(shè)計(jì)最適合的數(shù)據(jù)結(jié)構(gòu)和信息交換規(guī)程。 套接字編程層次較低,自由度較大。,2.2.4 套接字使用的數(shù)據(jù)類型和相關(guān)的問題 1三種表示套接字地址的結(jié)構(gòu) 在套接字編程接口中,專門定義了三種結(jié)構(gòu)型的數(shù)據(jù)類型,用來存儲(chǔ)協(xié)議相關(guān)的網(wǎng)絡(luò)地址,在套接字編程接口的函數(shù)調(diào)用中要用到它們。 (1) sockaddr結(jié)構(gòu):

15、針對(duì)各種通信域的套接字,存儲(chǔ)它們的地址信息。 struct sockaddr unsigned shortsa_family; / 地址家族 charsa_data14; / 協(xié)議地址 ,(2) sockaddr_in結(jié)構(gòu):專門針對(duì)Internet通信域,存儲(chǔ)套接字相關(guān)的網(wǎng)絡(luò)地址信息,例如IP地址,傳輸層端口號(hào)等信息。 struct sockaddr_in short intsin_family;/ 地址家族,必須設(shè)定為 unsigned shortint sin_port;/ 端口號(hào) struct in_addrsin_addr;/ IP 地址 unsigned charsin_zero8;

16、/ 全為0 (3) in_addr結(jié)構(gòu):專門用來存儲(chǔ) IP地址。 Struct in_addr Unsigned longs_addrl; ,AF_INET,(4) 這些數(shù)據(jù)結(jié)構(gòu)的一般用法 首先,定義一個(gè)sockaddr_in的結(jié)構(gòu)實(shí)例,并將它清零。 struct sockaddr_in myad; memset(,2本機(jī)字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序 本機(jī)字節(jié)順序:在具體計(jì)算機(jī)中的多字節(jié)數(shù)據(jù)的存儲(chǔ)順序。 網(wǎng)絡(luò)字節(jié)順序:多字節(jié)數(shù)據(jù)在網(wǎng)絡(luò)協(xié)議報(bào)頭中的存儲(chǔ)順序。 網(wǎng)絡(luò)應(yīng)用程序要在不同的計(jì)算機(jī)中運(yùn)行,本機(jī)字節(jié)順序是不同的,但網(wǎng)絡(luò)字節(jié)順序是一定的。 所以,在應(yīng)用程序編程的時(shí)候,在把IP地址和端口號(hào)裝入套接字時(shí)

17、,應(yīng)當(dāng)把它們從本機(jī)字節(jié)順序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序;相反,在本機(jī)輸出時(shí),應(yīng)將它們從網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為本機(jī)字節(jié)順序。,套接字編程接口為解決這個(gè)問題設(shè)置了四個(gè)函數(shù): htons() 短整數(shù)本機(jī)順序轉(zhuǎn)換為網(wǎng)絡(luò)順序,用于端口號(hào)。 htonl() 長(zhǎng)整數(shù)本機(jī)順序轉(zhuǎn)換為網(wǎng)絡(luò)順序,用于IP地址。 ntohs() 短整數(shù)網(wǎng)絡(luò)順序轉(zhuǎn)換為本機(jī)順序,用于端口號(hào)。 ntohl() 長(zhǎng)整數(shù)網(wǎng)絡(luò)順序轉(zhuǎn)化為本機(jī)順序,用于IP地址。 這四個(gè)函數(shù)將被轉(zhuǎn)換的數(shù)值作為函數(shù)的參數(shù),函數(shù)返回值是轉(zhuǎn)換后的結(jié)果。,3點(diǎn)分十進(jìn)制的IP地址的轉(zhuǎn)換 在因特網(wǎng)中,IP地址常用點(diǎn)分十進(jìn)制的表示方法,在套接字中,IP地址是無符號(hào)的長(zhǎng)整型數(shù),套接字接口設(shè)置了

18、兩個(gè)函數(shù)用于兩種形式IP地址的轉(zhuǎn)換。 (1) inet-addr函數(shù) unsigned long inet-addr( const char* cp) 入口參數(shù)cp:點(diǎn)分十進(jìn)制形式的IP地址。 返回值: 網(wǎng)絡(luò)字節(jié)順序的IP地址,是無符號(hào)的長(zhǎng)整數(shù)。,(2) inet_ntoa函數(shù) char* inet_ntoa(struct in_addr in) 入口參數(shù)in:包含長(zhǎng)整型IP地址的 in_addr 結(jié)構(gòu)變量; 返回值: 指向點(diǎn)分十進(jìn)制IP地址的字符串的指針.,4域名服務(wù) 通常,我們使用域名來標(biāo)識(shí)站點(diǎn),可以將文字型的主機(jī)域名直接轉(zhuǎn)換成IP地址。 struct hostent* gethostby

19、name( const char* name); 入口參數(shù):是站點(diǎn)的主機(jī)域名字符串; 返回值:是指向hostent 結(jié)構(gòu)的指針。 hostent結(jié)構(gòu)包含主機(jī)名、主機(jī)別名數(shù)組、返回地址的類型(一般是AF-INET)、地址長(zhǎng)度的字節(jié)數(shù)、已符合網(wǎng)絡(luò)字節(jié)順序的主機(jī)網(wǎng)絡(luò)地址等。,2.3 面向連接的套接字編程,2.3.1 套接字的工作過程 面向連接的通信方式基于TCP,必須借助流式套接字來編程,應(yīng)用服務(wù)器分為服務(wù)器端和客戶端,雙方是不對(duì)稱的,需要分別編程。 雙方首先要?jiǎng)?chuàng)建并安裝套接字,做好準(zhǔn)備; 建立連接,采用三次握手的方式; 數(shù)據(jù)交換,稱為客戶機(jī)與服務(wù)器的會(huì)話期,會(huì)話的內(nèi)容必須遵守一定的格式和順序; 釋

20、放連接。 下面介紹面向連接的服務(wù)器和客戶端的編程步驟.,2.3.2 UNIX套接字編程接口的系統(tǒng)調(diào)用 1創(chuàng)建套接字SOCKET() 創(chuàng)建一個(gè)套接字,并返回一個(gè)整型描述符: int SOCKET( int Protofamily, int Type, int Protocol); 入口參數(shù): Protofamily:套接字使用的協(xié)議簇,一般為PF_INET,表示TCP/IP協(xié)議簇,PF_DECnet表示DEC協(xié)議。 type:套接字類型,SOCK_STREMA表示創(chuàng)建面向連接的流傳輸?shù)牧魇教捉幼?;SOCK_DGRAMA表示創(chuàng)建無連接的面向消息的數(shù)據(jù)報(bào)套接字。 protocol:套接字使用的傳輸層

21、網(wǎng)絡(luò)協(xié)議,一般為IPPROTO_IP,internet通信域中一般取值為0。,返回值: 套接字創(chuàng)建成功,返回一個(gè)int型的整數(shù),即所創(chuàng)建套接字的描述符,指向被維護(hù)在操作系統(tǒng)內(nèi)核里的socket數(shù)據(jù)結(jié)構(gòu)。 套接字創(chuàng)建出錯(cuò),返回1,表示出錯(cuò)類型的代碼保存在全局變量Errno中。 舉例: int sockfd=SOCKET(PF_INTE,SOCK_STREAM,0) 創(chuàng)建套接字時(shí),為其分配了內(nèi)存,并建立了相應(yīng)的數(shù)據(jù)結(jié)構(gòu),用于指定連接的種類和使用的協(xié)議,同時(shí)還有關(guān)于連接隊(duì)列操作的選項(xiàng)結(jié)構(gòu)字段,創(chuàng)建時(shí)設(shè)置為默認(rèn)值。,2綁定套接字到指定的地址 BIND() int BIND( int Sockfd, s

22、truct sockaddr* My_addr, int Addrlen); 入口參數(shù): Sockfd:是由SOCKET()系統(tǒng)調(diào)用創(chuàng)建的套接字描述符,要將其綁定到指定的網(wǎng)絡(luò)地址上; My_addr:指向sockaddr結(jié)構(gòu)變量的指針,所指結(jié)構(gòu)中保存著特定的網(wǎng)絡(luò)地址,要將套接字綁定到這個(gè)網(wǎng)絡(luò)地址上; Addlen:是sockaddr結(jié)構(gòu)的長(zhǎng)度。,返回值: 如果返回0,表示已經(jīng)綁定成功。 如果返回1,表示有錯(cuò),出錯(cuò)碼在Errno中。 舉例: Struct sockaddr_in my_addr; if( BIND(sockfd, (sockaddr*) 入口參數(shù): Sockfd:套接字描述符,通

23、過它來監(jiān)聽來自客戶機(jī)端的連接請(qǐng)求。 Queuesize:等待連接隊(duì)列的最大長(zhǎng)度,最大可設(shè)為20,一般設(shè)為510。 返回值: 函數(shù)正確執(zhí)行則返回0,出錯(cuò)則返回-1。 舉例:LISTEN(Sockfe,10);,舉例:LISTEN(Sockfe, 10);,圖2.6 監(jiān)聽套接字使用緩沖區(qū)接納多個(gè)客戶端的連接請(qǐng)求,4接收連接請(qǐng)求ACCEPT() int ACCEPT(int Sockfd, struct sockaddr* Addr, int* addrlen); 入口參數(shù): Sockfd:監(jiān)聽客戶端連接請(qǐng)求的套接字描述符。 Addr:sockaddr結(jié)構(gòu)變量的指針,是一個(gè)出口參數(shù),當(dāng)調(diào)用執(zhí)行完畢時(shí)

24、,變量中放置的是所接收客戶機(jī)端的網(wǎng)絡(luò)地址。 Addrlen:整型變量指針,也是一個(gè)出口參數(shù),調(diào)用時(shí)初始設(shè)置為Addr結(jié)構(gòu)的長(zhǎng)度,不能為0或null,調(diào)用執(zhí)行完畢時(shí),返回所接收的客戶機(jī)端網(wǎng)絡(luò)地址長(zhǎng)度。,返回值: 如果執(zhí)行正確,返回一個(gè)新的套接字描述符,這個(gè)套接字已經(jīng)與客戶機(jī)端建立了連接,并專用于此后與客戶機(jī)端交換數(shù)據(jù)。 如果出錯(cuò),返回1。 說明: 調(diào)用從監(jiān)聽套接字的等待隊(duì)列中,取出第一個(gè)連接請(qǐng)求,創(chuàng)建一個(gè)新的套接字,并通過這個(gè)新套接字向客戶機(jī)端發(fā)送連接應(yīng)答,從而與客戶機(jī)端建立連接,系統(tǒng)為這個(gè)新的套接字分配一個(gè)服務(wù)器端的自由端口號(hào),這個(gè)套接字用于后續(xù)與客戶機(jī)端交換數(shù)據(jù),稱為響應(yīng)套接字。,舉例: i

25、nt clientfd; / 定義響應(yīng)套接字描述符變量 int addrler=sizeof(sockaddr); / 獲得套接字地址結(jié)構(gòu)長(zhǎng)度。 struct sockaddr_in cltsockaddr; / 定義用于返回客戶端地址的結(jié)構(gòu)。 clientfd=ACCEPT(listenfd, (sockaddr* )( / 接收客戶連接請(qǐng)求,5請(qǐng)求建立連接CONNECT() int CONNECT( int Sockfd, struct sockaddr* Service_addr, int Addrlen); 入口參數(shù): Sockfd:客戶機(jī)端的請(qǐng)求套接字; Service_addr:存

26、放服務(wù)器端的網(wǎng)絡(luò)地址; Addrlen:sockaddr結(jié)構(gòu)的長(zhǎng)度。 返回值: 連接成功,返回0; 連接未成功,返回-1。,說明: 用于客戶端請(qǐng)求連接到服務(wù)器; 對(duì)于流式套接字,使用TCP協(xié)議,服務(wù)器若接受連接請(qǐng)求,即把它放入監(jiān)聽套接字的緩沖區(qū)隊(duì)列,并調(diào)用ACCEPT()來接收處理; 對(duì)于數(shù)據(jù)報(bào)套接字,使用UDP協(xié)議,客戶機(jī)向同一服務(wù)器傳送多條信息時(shí),允許客戶機(jī)使用CONNECT只指明服務(wù)器地址一次,而不必在每條信息中都指明目的地址。 舉例:if ( CONNECT(sockfd, (struct sockaddr*)( int RECV( int sockfd, char* buf, int

27、 len, int flags ); 入口參數(shù): sockfd:用來發(fā)送/接收數(shù)據(jù)的套接字描述符,可以是由SOCKET()創(chuàng)建的,也可以是ACCEPT()返回的; buf:用于發(fā)送/接收數(shù)據(jù)的緩沖區(qū)指針; len:發(fā)送或接收的字符數(shù); flags:執(zhí)行本調(diào)用的方式,一般置為0.,返回值: 處理錯(cuò)誤,返回-1; 如果正確,對(duì)于發(fā)送返回實(shí)際發(fā)送出去的字節(jié)數(shù);對(duì)于接收返回實(shí)際讀入緩沖區(qū)的字節(jié)數(shù)。 說明: 和read、write一樣,必須用于已連接的套接字,無需調(diào)用者指明目的地參數(shù)。,8關(guān)閉套接字CLOSE() int CLOSE( int sockfd ); 入口參數(shù): sockfd:要關(guān)閉的套接字

28、描述符。 說明: 如果是面向連接的,CLOSE在關(guān)閉套接字前先終止連接; 關(guān)閉一個(gè)套接字意味著立即終止對(duì)它的使用,描述符被釋放,以防止應(yīng)用程序發(fā)送或接收更多的數(shù)據(jù)。,2.3.3 面向連接的套接字編程實(shí)例 1實(shí)例的功能 服務(wù)器對(duì)來訪的客戶計(jì)數(shù),并向客戶報(bào)告這個(gè)計(jì)數(shù)值; 客戶建立與服務(wù)器的一個(gè)連接并等待它的輸出; 每當(dāng)連接請(qǐng)求到達(dá)時(shí),服務(wù)器生成一個(gè)可打印的ASCII串信息,將它在連接上發(fā)回,然后關(guān)閉連接; 客戶顯示收到的信息,然后退出。 例如,對(duì)于服務(wù)器接收的第10次客戶連接請(qǐng)求,該客戶將收到并打印如下信息: This server has been contacted 10 times.,2實(shí)例

29、程序的命令行參數(shù) 實(shí)例是UNIX環(huán)境下的C程序,客戶和服務(wù)器程序在編譯后,均以命令行的方式執(zhí)行。 服務(wù)器程序執(zhí)行時(shí)可以帶一個(gè)命令行參數(shù),用來接收請(qǐng)求的監(jiān)聽套接字的協(xié)議端口號(hào)。 這個(gè)參數(shù)是可選的,如果不指定端口號(hào),代碼將使用程序內(nèi)定的缺省端口號(hào)5188。 客戶程序執(zhí)行時(shí)可以帶兩個(gè)命令行參數(shù): 一個(gè)是服務(wù)器所在計(jì)算機(jī)的主機(jī)名; 另一個(gè)是服務(wù)器監(jiān)聽的協(xié)議端口號(hào)。,這兩個(gè)參數(shù)都是可選的。 如果沒有指定協(xié)議端口號(hào),客戶使用程序內(nèi)定的缺省值5188。 如果一個(gè)參數(shù)也沒有,客戶使用缺省端口和主機(jī)名localhost,localhost是映射到客戶所運(yùn)行的計(jì)算機(jī)的一個(gè)別名。 允許客戶與本地機(jī)上的服務(wù)器通信,對(duì)

30、調(diào)試是很有用的。,3客戶程序代碼 /*- * 程序: client.c * 目的: 創(chuàng)建一個(gè)套接字,通過網(wǎng)絡(luò)連接一個(gè)服務(wù)器,并打印來自服務(wù)器的信息 * 語(yǔ)法: client host port * host - 運(yùn)行服務(wù)器的計(jì)算機(jī)的名字 * port - 服務(wù)器監(jiān)聽套接字所用協(xié)議端口號(hào) * 注意:兩個(gè)參數(shù)都是可選的。如果未指定主機(jī)名,客戶使用localhost;如果未指定端口號(hào), * 客戶將使用PROTOPORT中給定的缺省協(xié)議端口號(hào) *-*/,#include /* 基本系統(tǒng)數(shù)據(jù)類型*/ #include /* UNIX下,套接字接口包含文件*/ #include /* Internet地址

31、簇*/ #include /* Internet定義*/ #include /* 網(wǎng)絡(luò)數(shù)據(jù)庫(kù)操作*/ #include /* 標(biāo)準(zhǔn)輸入輸出*/ #include /* 字符串處理*/ #define PROTOPORT 5188 /*缺省協(xié)議端口號(hào)*/ extern int errno; char localhost = “l(fā)ocalhost”; /*缺省主機(jī)名*/,main(argc,argv) int argc; char *argv; struct hostent *ptrh; /* 指向主機(jī)列表中一個(gè)條目的指針 */ struct sockaddr_in servaddr; /* 存放

32、服務(wù)器端網(wǎng)絡(luò)地址的結(jié)構(gòu) */ intsockfd; /* 客戶端的套接字描述符 */ intport; /* 服務(wù)器端套接字協(xié)議端口號(hào)*/ char* host; /* 服務(wù)器主機(jī)名指針 */ int n; /* 讀取的字符數(shù) */ char buf1000 ; /* 緩沖區(qū),接收服務(wù)器發(fā)來的數(shù)據(jù) */,memset(char*) /* 否則,使用缺省端口號(hào) */ if (port0) /* 如果端口號(hào)是合法的數(shù)值,就將它裝入網(wǎng)絡(luò)地址結(jié)構(gòu) */,servaddr.sin_port = htons(u_short)port); else /* 否則,打印錯(cuò)誤信息并退出*/ fprintf(std

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

34、r, ”invalid host: %sn”, host ); exit(1); memcpy(,Struct hostent char *h_name; char *h_aliases; int h_addrtype; int h_length; char *h_addr_list; ;,/* 創(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( soc

35、kfd, (struct sockaddr *) ,/* 從套接字反復(fù)讀數(shù)據(jù),并輸出到用戶屏幕上 */ n = recv(sockfd , buf, sizeof( buf ), 0 ); while ( n 0) write(1,buf, n); n = recv( sockfd , buf, sizeof( buf ), 0 ); /* 關(guān)閉套接字*/ closesocket( sockfd ); /* 終止客戶程序*/ exit(0); ,4服務(wù)器實(shí)例代碼 /*- * 程序:server.c * 目的: 分配一個(gè)套接字,然后反復(fù)執(zhí)行如下幾步: * (1) 等待客戶的下一個(gè)連接 * (2)

36、 發(fā)送一個(gè)短消息給客戶 * (3) 關(guān)閉與客戶的連接 * (4) 轉(zhuǎn)向(1)步 * 命令行語(yǔ)法: server port * port 服務(wù)器端監(jiān)聽套接字使用的協(xié)議端口號(hào) * 注意: 端口號(hào)可選。如果未指定端口號(hào),服務(wù)器使用PROTOPORT中指定的缺省* 端口號(hào) *-*/,#include #include #include #include #include #include #define PROTOPORT 5188 /* 監(jiān)聽套接字的缺省協(xié)議端口號(hào) */ #define QLEN 6 /* 監(jiān)聽套接字的請(qǐng)求隊(duì)列大小 */ int visits = 0; /* 對(duì)于客戶連接的計(jì)數(shù)*/,

37、main(argc,argc) int argc; char* argv; struct hostent *ptrh; /* 指向主機(jī)列表中一個(gè)條目的指針 */ struct sockaddr_in servaddr; /* 存放服務(wù)器網(wǎng)絡(luò)地址的結(jié)構(gòu) */ struct sockaddr_in clientaddr; /* 存放客戶網(wǎng)絡(luò)地址的結(jié)構(gòu) */ int listenfd; /* 監(jiān)聽套接字描述符 */ int clientfd; /* 響應(yīng)套接字描述符 */ int port; /* 協(xié)議端口號(hào) */ int alen; /* 地址長(zhǎng)度 */ char buf1000; /* 供服務(wù)器

38、發(fā)送字符串所用的緩沖區(qū) */,/* 清空sockaddr結(jié)構(gòu) */ memset( (char*) /* 否則,使用缺省端口號(hào) */ ,if (port 0) /* 測(cè)試端口號(hào)是否合法 */ servaddr.sin_port=htons( (u_short)port ); else /* 打印錯(cuò)誤信息并退出 */ fprintf( stderr, ”bad port number %sn”, argv1 ); exit(1); /* 創(chuàng)建一個(gè)用于監(jiān)聽的流式套接字 */ listenfd = SOCKET(AF_INET,SOCK_STREAM,0); if (listenfd 0) fpri

39、ntf( stderr, “socket creation failedn” ); exit(1); ,/* 將本地地址綁定到監(jiān)聽套接字*/ if ( bind( listenfd, (struct sockaddr *) ,/* 服務(wù)器主循環(huán)接受和處理來自客戶端的連接請(qǐng)求 */ while(1) alen = sizeof(clientaddr); /* 接受客戶端連接請(qǐng)求,并生成響應(yīng)套接字 */ if(clientfd = accept( listenfd, (struct sockaddr *) /* 關(guān)閉響應(yīng)套接字 */ ,關(guān)于阻塞的問題,圖2.7 服務(wù)器進(jìn)程因調(diào)用ACCEPT()而被

40、阻塞,2.3.4 進(jìn)程的阻塞問題和對(duì)策 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)稱為阻塞。,圖2.8 RECV()函數(shù)的兩種執(zhí)行方式,2能引起阻塞的套接字調(diào)用 在Berkeley套接字網(wǎng)絡(luò)編程接口的模型中,套接字的默認(rèn)行為是阻塞的,具體地說,在一定情況下,有多個(gè)操作套接字的系統(tǒng)調(diào)用會(huì)引起進(jìn)程阻塞。 (1)ACCEPT() (2)READ()、RECV()和READFORM() (3)WRITE()、SEND()和SENDTO() (4)CONNECT() (5)S

41、ELECT() (6)CLOSESOCKET(),圖2.9 采用阻塞工作模式的服務(wù)器不能很好地為多個(gè)客戶服務(wù),3阻塞工作模式帶來的問題 采用阻塞工作模式的單進(jìn)程服務(wù)器,不能很好地同時(shí)為多個(gè)客戶服務(wù)的。圖2.9是一個(gè)例子。,4一種解決方案 利用UNIX操作系統(tǒng)的FORK()系統(tǒng)調(diào)用,編制多進(jìn)程并發(fā)執(zhí)行的服務(wù)器程序,可以創(chuàng)建子進(jìn)程。 對(duì)每一個(gè)客戶端,用一個(gè)專門的進(jìn)程為它服務(wù),通過進(jìn)程的并發(fā)執(zhí)行,來對(duì)實(shí)現(xiàn)多個(gè)客戶的并發(fā)服務(wù). 基本的編程框架是:,父進(jìn)程代碼 If (pid = FORK() = 0) . 子進(jìn)程代碼 . else if (pid0) 報(bào)錯(cuò)信息 父進(jìn)程代碼,舉例: #include #

42、include #include #include void main(int argc, char* argv) int listenfd,clientfd,pid; struct sockaddr_in ssockaddr, csockaddr; char buffer1024; int addrlen,n;,/* 創(chuàng)建監(jiān)聽套接字 */ listenfd = socket(AF_INET,SOCK_STREAM,0); if (listenfd 0) fprintf(stderr, socket error!n); exit(1); ,/* 為監(jiān)聽套接字綁定網(wǎng)絡(luò)地址 */ memset(

43、,/* 啟動(dòng)套接字的監(jiān)聽 */ listen(listenfd,5); addrlen = sizeof(sockaddr); /* 服務(wù)器進(jìn)入循環(huán),接受并處理來自不同客戶端的連接請(qǐng)求 */ while (1) clientfd = accept(listenfd,(sockaddr*)( /* accept調(diào)用返回時(shí),表明有客戶端請(qǐng)求連接,創(chuàng)建子進(jìn)程處理連接*/ If (pid = FORK() = 0) ,/* 顯示客戶端的網(wǎng)絡(luò)地址 */ printf(Client Addr: %s%dn,inet_ntoa(csockaddr.sin_addr), ntohs(csockaddr.sin

44、_port); /* 讀取客戶端發(fā)送來的數(shù)據(jù),在將它們返回到客戶端 */ while (n = read(clientfd,buffer,1024) 0) buffern = 0; printf(Client Send: %s,buffer); write( clientfd, buffer, n); if (n 0) fprintf( stderr, read error!n); exit(3); ,/* 通信完畢,關(guān)閉與這個(gè)客戶連接的套接字 */ printf(clent %s closed!n, inet_ntoa(csockaddr.sin_addr); close(clientfd); exit(1); else if (pid 0) printf(fork failed!n); close(clientfd); close(listenfd); /* 關(guān)閉監(jiān)聽套接字 */ ,2.4 無連接的套接字編程,2.4.1 無連接的套接字編程的兩種模式 使用數(shù)據(jù)報(bào)套接字開發(fā)網(wǎng)絡(luò)應(yīng)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 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)論