《網(wǎng)絡(luò)程序設(shè)計》第2章_第1頁
《網(wǎng)絡(luò)程序設(shè)計》第2章_第2頁
《網(wǎng)絡(luò)程序設(shè)計》第2章_第3頁
《網(wǎng)絡(luò)程序設(shè)計》第2章_第4頁
《網(wǎng)絡(luò)程序設(shè)計》第2章_第5頁
已閱讀5頁,還剩100頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、n UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展過程套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展過程n 套接字與套接字與UNIX操作系統(tǒng)的關(guān)系操作系統(tǒng)的關(guān)系n 套接字編程的基本概念套接字編程的基本概念n 面向連接的套接字編程面向連接的套接字編程n 無連接的套接字編程無連接的套接字編程n 原始套接字原始套接字n Linux系統(tǒng)的網(wǎng)絡(luò)編程接口系統(tǒng)的網(wǎng)絡(luò)編程接口本章提要本章提要第2章 UNIX中的套接字網(wǎng)絡(luò)編程接口2.1.1 問題的提出問題的提出 站在應(yīng)用程序?qū)崿F(xiàn)的角度,應(yīng)用程序如站在應(yīng)用程序?qū)崿F(xiàn)的角度,應(yīng)用程序如何方便地使用協(xié)議棧軟件進行通信呢?何方便地使用協(xié)議棧軟件進行通信呢? 如果能在應(yīng)用程序與協(xié)議棧軟件之間提如

2、果能在應(yīng)用程序與協(xié)議棧軟件之間提供一個軟件接口,就可以方便客戶與服務(wù)器供一個軟件接口,就可以方便客戶與服務(wù)器軟件的編程。軟件的編程。2.1 UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展 套接字應(yīng)用程序編程接口是網(wǎng)絡(luò)應(yīng)用程序套接字應(yīng)用程序編程接口是網(wǎng)絡(luò)應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧進行通信時所使用的接口,即通過網(wǎng)絡(luò)協(xié)議棧進行通信時所使用的接口,即應(yīng)用程序與協(xié)議棧軟件之間的接口,簡稱應(yīng)用程序與協(xié)議棧軟件之間的接口,簡稱套接套接字編程接口字編程接口(Socket API)。 它定義了應(yīng)用程序與協(xié)議棧軟件進行交互它定義了應(yīng)用程序與協(xié)議棧軟件進行交互時可以使用的一組操作,決定了應(yīng)用程序使用時可以使用的一組操作,決定了

3、應(yīng)用程序使用協(xié)議棧的方式、應(yīng)用程序所能實現(xiàn)的功能、以協(xié)議棧的方式、應(yīng)用程序所能實現(xiàn)的功能、以及開發(fā)具有這些功能的程序的難度。及開發(fā)具有這些功能的程序的難度。2.1 UNIX套接字網(wǎng)絡(luò)編程接口的產(chǎn)生與發(fā)展 加州大學(xué)伯克利加州大學(xué)伯克利(Berkley)分校開發(fā)并推廣了一分校開發(fā)并推廣了一個個包括包括 TCP/IP 互聯(lián)協(xié)議的互聯(lián)協(xié)議的 UNIX,稱為稱為BSD UNIX(Berkeley Software Distribution UNIX)操作系統(tǒng),操作系統(tǒng),套接字編程接口套接字編程接口是是這個操作系統(tǒng)這個操作系統(tǒng)的的一個部分一個部分。 后來的許多操作系統(tǒng)并沒有另外搞一套其它的編后來的許多操作

4、系統(tǒng)并沒有另外搞一套其它的編程接口,而是選擇了對于套接字編程接口的支持。程接口,而是選擇了對于套接字編程接口的支持。 由于這個套接字規(guī)范最早是由由于這個套接字規(guī)范最早是由Berkeley大學(xué)開大學(xué)開發(fā)的,一般將它稱為發(fā)的,一般將它稱為Berkeley Sockets規(guī)范。規(guī)范。2.1.2 套接字編程接口的起源與應(yīng)用套接字編程接口的起源與應(yīng)用 要想實現(xiàn)套接字編程接口,可以采用兩要想實現(xiàn)套接字編程接口,可以采用兩種實現(xiàn)方式種實現(xiàn)方式: 一種是在操作系統(tǒng)的內(nèi)核中增加相應(yīng)的一種是在操作系統(tǒng)的內(nèi)核中增加相應(yīng)的軟件,網(wǎng)絡(luò)程序中用軟件,網(wǎng)絡(luò)程序中用系統(tǒng)調(diào)用系統(tǒng)調(diào)用的方法來實現(xiàn)的方法來實現(xiàn)(Unix/Linu

5、x) 一種是通過開發(fā)操作系統(tǒng)之外的函數(shù)庫,一種是通過開發(fā)操作系統(tǒng)之外的函數(shù)庫,網(wǎng)絡(luò)程序中采用網(wǎng)絡(luò)程序中采用調(diào)用庫函數(shù)調(diào)用庫函數(shù)的方法來實現(xiàn)的方法來實現(xiàn)(Windows) 2.1.3 套接字編程接口的兩種實現(xiàn)方式套接字編程接口的兩種實現(xiàn)方式 UNIX操作系統(tǒng)對文件和所有其它操作系統(tǒng)對文件和所有其它的輸入的輸入/輸出設(shè)備輸出設(shè)備采用一種采用一種統(tǒng)一的的操作模式統(tǒng)一的的操作模式,就是,就是“打開打開- -讀讀- -寫寫- -關(guān)閉關(guān)閉”(open - read - write - close)的)的I/O模式。模式。 當當TCP/IP協(xié)議被集成到協(xié)議被集成到UNIX內(nèi)核中的時內(nèi)核中的時候,相當于在候,

6、相當于在 UNIX系統(tǒng)中引入了一種新型的系統(tǒng)中引入了一種新型的I/O 操作,就是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧來交操作,就是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧來交換數(shù)據(jù)。換數(shù)據(jù)。 2.1.4 套接字通信與套接字通信與UNIX操作系統(tǒng)的輸入操作系統(tǒng)的輸入/輸出輸出 在在UNIX系統(tǒng)的實現(xiàn)中,套接字是完全系統(tǒng)的實現(xiàn)中,套接字是完全與其他與其他I/O集成在一起的。操作系統(tǒng)和應(yīng)用集成在一起的。操作系統(tǒng)和應(yīng)用程序都將程序都將套接字編程接口套接字編程接口也也看作看作一種輸入一種輸入/ /輸輸出機制出機制。 但是,用戶進程與網(wǎng)絡(luò)協(xié)議的但是,用戶進程與網(wǎng)絡(luò)協(xié)議的交互作用交互作用實際要比用戶進程與傳統(tǒng)的實際要比用戶進程與傳統(tǒng)的I/

7、O設(shè)備相互作設(shè)備相互作用要用要復(fù)雜得多復(fù)雜得多。 2.1.4 套接字通信與套接字通信與UNIX操作系統(tǒng)的輸入操作系統(tǒng)的輸入/輸出輸出 其次,使用套接字的應(yīng)用程序其次,使用套接字的應(yīng)用程序必須說明必須說明許多細節(jié)許多細節(jié)。僅僅提供。僅僅提供open、read、write、close四個過程四個過程遠遠不夠遠遠不夠。為避免單個套接。為避免單個套接字函數(shù)參數(shù)過多,套接字編程接口的設(shè)計字函數(shù)參數(shù)過多,套接字編程接口的設(shè)計者者定義了多個函數(shù)。定義了多個函數(shù)。2.1.4 套接字通信與套接字通信與UNIX操作系統(tǒng)的輸入操作系統(tǒng)的輸入/輸出輸出2.2 套接字編程的基本概念套接字編程的基本概念 套接口套接口是對

8、網(wǎng)絡(luò)中不同主機上應(yīng)用進程之間進行雙向通信是對網(wǎng)絡(luò)中不同主機上應(yīng)用進程之間進行雙向通信的的端點的抽象端點的抽象,一個套接口就是網(wǎng)絡(luò)上進程通信的一端,提供,一個套接口就是網(wǎng)絡(luò)上進程通信的一端,提供了應(yīng)用層進程利用網(wǎng)絡(luò)協(xié)議棧交換數(shù)據(jù)的機制了應(yīng)用層進程利用網(wǎng)絡(luò)協(xié)議棧交換數(shù)據(jù)的機制。 圖圖2.1 電插座與電話插座的作用電插座與電話插座的作用2.2.1 什么是套接字(什么是套接字(SOCKET) 2.2.1 什么是套接字什么是套接字(SOCKET)? 我們應(yīng)當從多個層面來理解套接字這個概我們應(yīng)當從多個層面來理解套接字這個概念的內(nèi)涵。念的內(nèi)涵。 從套接字所處的地位來講,套接字上聯(lián)應(yīng)從套接字所處的地位來講,套

9、接字上聯(lián)應(yīng)用進程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過網(wǎng)用進程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧進行絡(luò)協(xié)議棧進行通信的接口通信的接口,是應(yīng)用程序與網(wǎng)絡(luò),是應(yīng)用程序與網(wǎng)絡(luò)協(xié)議棧進行協(xié)議棧進行交互的接口交互的接口。 圖圖2.2 應(yīng)用進程、套接口、網(wǎng)絡(luò)協(xié)議棧及操作系統(tǒng)的關(guān)系應(yīng)用進程、套接口、網(wǎng)絡(luò)協(xié)議棧及操作系統(tǒng)的關(guān)系 進程、套接口、協(xié)議棧、操作系統(tǒng)的關(guān)系 從實現(xiàn)的角度來講從實現(xiàn)的角度來講,非常復(fù)雜非常復(fù)雜。套接字是一個。套接字是一個復(fù)雜的軟件機構(gòu),包含了一定的數(shù)據(jù)結(jié)構(gòu),包含許復(fù)雜的軟件機構(gòu),包含了一定的數(shù)據(jù)結(jié)構(gòu),包含許多選項,由操作系統(tǒng)內(nèi)核管理。多選項,由操作系統(tǒng)內(nèi)核管理。 從使用的角度來講從使用

10、的角度來講,非常簡單非常簡單。對于套接字的。對于套接字的操作形成了一種網(wǎng)絡(luò)應(yīng)用程序的編程接口(操作形成了一種網(wǎng)絡(luò)應(yīng)用程序的編程接口(API)。)。 本書把這一套本書把這一套操作套接字的操作套接字的編程接口函數(shù)編程接口函數(shù)稱作稱作套接字編程接口套接字編程接口,套接字是它的操作對象。,套接字是它的操作對象。 總之,套接字是網(wǎng)絡(luò)通信的基石??傊捉幼质蔷W(wǎng)絡(luò)通信的基石。 套接字編程接口套接字編程接口2.2.2 套接字的特點套接字的特點1 1通信域通信域 套接字存在于通信域中,通信域是為了處理套接字存在于通信域中,通信域是為了處理一一般的進程般的進程通過套接字通信而引入的一種抽象概念,通過套接字通信而

11、引入的一種抽象概念,套接字套接字通常通常只和只和同一域同一域中的中的套接字套接字交換數(shù)據(jù)交換數(shù)據(jù)。 如果如果數(shù)據(jù)交換要數(shù)據(jù)交換要穿越穿越域域的的邊界邊界,就一定要執(zhí)行,就一定要執(zhí)行某種某種解釋解釋程序。程序。 本課程中,僅僅針對本課程中,僅僅針對Internet域域,并且使用,并且使用Internet協(xié)議族協(xié)議族(即即TCP/IP協(xié)議族協(xié)議族)來通信。來通信。2套接字具有三種類型套接字具有三種類型 每一個正被使用的套接字都有它確定的每一個正被使用的套接字都有它確定的類型類型,只有只有相同類型相同類型的套接字的套接字才能相互通信才能相互通信。 (1) 數(shù)據(jù)報套接字數(shù)據(jù)報套接字 (Datagram

12、 SOCKET) 數(shù)據(jù)報套接字提供數(shù)據(jù)報套接字提供無連接的、不保證可靠的無連接的、不保證可靠的獨立的數(shù)據(jù)報傳輸服務(wù)獨立的數(shù)據(jù)報傳輸服務(wù)。在。在Internet通信域中,通信域中,數(shù)據(jù)報套接字使用數(shù)據(jù)報套接字使用UDP數(shù)據(jù)報協(xié)議形成的進程間數(shù)據(jù)報協(xié)議形成的進程間通路,具有通路,具有UDP協(xié)議為上層所提供的服務(wù)的所有協(xié)議為上層所提供的服務(wù)的所有特點。特點。數(shù)據(jù)報套接字基于數(shù)據(jù)報套接字基于UDP協(xié)議協(xié)議 圖圖2.3 在在Internet通信域中,數(shù)據(jù)報套接字基于通信域中,數(shù)據(jù)報套接字基于UDP協(xié)議協(xié)議 (2)流套接字流套接字(Stream SOCKET) 流套接字流套接字提供提供雙向的、有序的、無重

13、復(fù)的、無記雙向的、有序的、無重復(fù)的、無記錄邊界的、可靠的數(shù)據(jù)流傳輸服務(wù)錄邊界的、可靠的數(shù)據(jù)流傳輸服務(wù)。在。在Internet通通信域中,流套接字使用信域中,流套接字使用TCP協(xié)議形成的進程間通路,協(xié)議形成的進程間通路,具有具有TCP協(xié)議為上層所提供的服務(wù)的所有特點,在協(xié)議為上層所提供的服務(wù)的所有特點,在使用流套接字使用流套接字傳輸數(shù)據(jù)之前傳輸數(shù)據(jù)之前,必須必須在數(shù)據(jù)的發(fā)送端和在數(shù)據(jù)的發(fā)送端和接收端之間接收端之間先建立連接先建立連接,如下頁圖,如下頁圖2.4所示。所示。 流式套接字基于流式套接字基于TCP協(xié)議協(xié)議圖圖2.4 在在Internet通信域中,流式套接字基于通信域中,流式套接字基于TC

14、P協(xié)議協(xié)議(3)原始套接字)原始套接字 (RAW SOCKET) 原始套接字原始套接字允許對較低層次的協(xié)議,如允許對較低層次的協(xié)議,如IP、ICMP直接訪問,或用于檢驗新的協(xié)議的實現(xiàn)。直接訪問,或用于檢驗新的協(xié)議的實現(xiàn)。TCPUDP IP / ICMP Ethernet應(yīng) 用 程 序流套接字數(shù)據(jù)報套接字原始套接字原始套接字3 3套接字由應(yīng)用層通信進程創(chuàng)建,并為其服務(wù)套接字由應(yīng)用層通信進程創(chuàng)建,并為其服務(wù) 套接字由應(yīng)用層的通信進程創(chuàng)建,并套接字由應(yīng)用層的通信進程創(chuàng)建,并為其服務(wù),這為其服務(wù),這就是說,就是說,每一個套接字每一個套接字都有都有一個相關(guān)的應(yīng)用進程一個相關(guān)的應(yīng)用進程,操作該套接字的代,

15、操作該套接字的代碼是該進程的組成部分。碼是該進程的組成部分。4 4使用確定的使用確定的IPIP地址和傳輸層端口號地址和傳輸層端口號 套接字編程時,往往在生成套接字的描述套接字編程時,往往在生成套接字的描述符后,要將符后,要將套接字套接字與與計算機上的特定的計算機上的特定的IP地址地址和傳輸層和傳輸層端口號端口號相關(guān)聯(lián)相關(guān)聯(lián),這個過程稱為,這個過程稱為綁定綁定。 一個套接口要使用一個確定的一個套接口要使用一個確定的三元組三元組網(wǎng)絡(luò)網(wǎng)絡(luò)地址信息,才能使它在網(wǎng)絡(luò)中地址信息,才能使它在網(wǎng)絡(luò)中唯一唯一地被地被標識標識。 (1)不管是采用對等模式或者客戶機)不管是采用對等模式或者客戶機/服服務(wù)器模式,務(wù)器

16、模式,通信雙方通信雙方的的應(yīng)用程序應(yīng)用程序都都需要開發(fā)需要開發(fā)。 (2)雙方所交換)雙方所交換數(shù)據(jù)數(shù)據(jù)的的結(jié)構(gòu)結(jié)構(gòu)和交換數(shù)據(jù)的和交換數(shù)據(jù)的順序順序有有特定的要求特定的要求,不符合現(xiàn)在成熟的應(yīng)用層,不符合現(xiàn)在成熟的應(yīng)用層協(xié)議的要求時。甚至,有時需要自己去開發(fā)應(yīng)協(xié)議的要求時。甚至,有時需要自己去開發(fā)應(yīng)用層協(xié)議,自己設(shè)計最適合的數(shù)據(jù)結(jié)構(gòu)和信息用層協(xié)議,自己設(shè)計最適合的數(shù)據(jù)結(jié)構(gòu)和信息交換規(guī)程。交換規(guī)程。 2.2.3 套接字的應(yīng)用場合套接字的應(yīng)用場合2.2.4 套接字使用的數(shù)據(jù)類型和相關(guān)的問套接字使用的數(shù)據(jù)類型和相關(guān)的問題題1三種三種表示表示套接字地址套接字地址的的結(jié)構(gòu)結(jié)構(gòu) 在套接字編程接口中,專門定義

17、了在套接字編程接口中,專門定義了三三種種結(jié)構(gòu)型的數(shù)據(jù)類型結(jié)構(gòu)型的數(shù)據(jù)類型,用來存儲協(xié)議相關(guān),用來存儲協(xié)議相關(guān)的的網(wǎng)絡(luò)地址網(wǎng)絡(luò)地址,在套接字編程接口的函數(shù)調(diào),在套接字編程接口的函數(shù)調(diào)用中要用到它們。用中要用到它們。三種表示套接字地址的結(jié)構(gòu)三種表示套接字地址的結(jié)構(gòu) (1)sockaddr 結(jié)構(gòu)結(jié)構(gòu),針對,針對各種各種通信域通信域的的套接字,存儲它們的地址信息:套接字,存儲它們的地址信息: struct sockaddr unsigned short sa_family; / 地址家族地址家族 char sa_data14; / 協(xié)議地址協(xié)議地址 (2) sockaddr_in 結(jié)構(gòu)結(jié)構(gòu),專門針對專

18、門針對Internet通通信域信域,存儲套接字相關(guān)的網(wǎng)絡(luò)地址信息,例如,存儲套接字相關(guān)的網(wǎng)絡(luò)地址信息,例如IP地址地址、端口號端口號等信息。等信息。 struct sockaddr_in short int sin_family; /地址家族地址家族 unsigned short int sin_port; /2字節(jié)字節(jié)端口號端口號 struct in_addr sin_addr; /4字節(jié)字節(jié)IP 地址地址 unsigned char sin_zero8; /8字節(jié)全字節(jié)全0 /最后包含一個最后包含一個8字節(jié)的全字節(jié)的全0的域,以使該結(jié)構(gòu)在大小上與的域,以使該結(jié)構(gòu)在大小上與sockaddr相

19、同相同三種表示套接字地址的結(jié)構(gòu)三種表示套接字地址的結(jié)構(gòu) (3)in_addr 結(jié)構(gòu)結(jié)構(gòu),專門專門用來存儲用來存儲 IP地址地址: struct in_addr unsigned long s_addr; /4字節(jié)字節(jié)IP 三種表示套接字地址的結(jié)構(gòu)三種表示套接字地址的結(jié)構(gòu) (4)這些數(shù)據(jù)結(jié)構(gòu)組合使用的一般用法:)這些數(shù)據(jù)結(jié)構(gòu)組合使用的一般用法: 首先,首先,定義定義一個一個sockaddr_in的的結(jié)構(gòu)實例結(jié)構(gòu)實例,并將它并將它清零清零。 比如:比如: struct sockaddr_in myad; memset(&myad, 0, sizeof(struct sockaddr_in)

20、; 一般,三種結(jié)構(gòu)組合起來使用:一般,三種結(jié)構(gòu)組合起來使用: 然后,為這個然后,為這個myad結(jié)構(gòu)結(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)進行通信時,應(yīng)賦值域內(nèi)進行通信時,應(yīng)賦值A(chǔ)F_INET。注注2:INADDR_ANY字符常量表示該主機的任何一個字符常量表示該主機的任何一個IP地址。地址

21、。一般,三種結(jié)構(gòu)組合起來使用:一般,三種結(jié)構(gòu)組合起來使用: 第三步:在函數(shù)調(diào)用中使用時,將這個第三步:在函數(shù)調(diào)用中使用時,將這個結(jié)構(gòu)結(jié)構(gòu)強制轉(zhuǎn)換為強制轉(zhuǎn)換為sockaddr類型類型。 如:如:accept(listenfd, (sockaddr*)(&myad), &addrlen); 一般,三種結(jié)構(gòu)組合起來使用:一般,三種結(jié)構(gòu)組合起來使用:2 2主機字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序主機字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序 多字節(jié)數(shù)據(jù)的多字節(jié)數(shù)據(jù)的字節(jié)順序字節(jié)順序 大端模式大端模式 (big endian): 高字節(jié)放到低地址上高字節(jié)放到低地址上 小端模式小端模式 (little endian): 高

22、字節(jié)放到高地址上高字節(jié)放到高地址上 在在具體計算機中具體計算機中多字節(jié)數(shù)據(jù)的多字節(jié)數(shù)據(jù)的存儲順序存儲順序稱為稱為主機字節(jié)順序主機字節(jié)順序。 不同的機器內(nèi)存中主機字節(jié)順序不相同,與不同的機器內(nèi)存中主機字節(jié)順序不相同,與CPU設(shè)計有關(guān):設(shè)計有關(guān): Motorola 68000、PowerPC系列系列 - 大端模式大端模式 (big endian) Intel x86系列系列 - 小端模式小端模式 (little endian) 多字節(jié)數(shù)據(jù)在多字節(jié)數(shù)據(jù)在網(wǎng)絡(luò)協(xié)議報頭中網(wǎng)絡(luò)協(xié)議報頭中的的 順序順序,稱為,稱為 網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序。 網(wǎng)絡(luò)通信時網(wǎng)絡(luò)通信時一律一律使用統(tǒng)一的使用統(tǒng)一的 大端模式大端模

23、式網(wǎng)絡(luò)字節(jié)順序,避免主網(wǎng)絡(luò)字節(jié)順序,避免主 機間通信時識別兼容問題。機間通信時識別兼容問題。5612347834785612 低址低址: 高址高址: 表示表示 0 x12345678時時: Motorola Intel2 2主機字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序主機字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序 網(wǎng)絡(luò)應(yīng)用程序要在網(wǎng)絡(luò)應(yīng)用程序要在不同的不同的計算機中計算機中運行,運行,多字節(jié)數(shù)據(jù)多字節(jié)數(shù)據(jù)在在各機器內(nèi)存中存放的各機器內(nèi)存中存放的主機字節(jié)順序主機字節(jié)順序可能可能不同不同,可能是大端模式,可能是大端模式,也可能是小端模式;但是,在網(wǎng)絡(luò)上傳輸時,在信包協(xié)議報頭也可能是小端模式;但是,在網(wǎng)絡(luò)上傳輸時,在信包協(xié)議報頭字段中的

24、字段中的網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序是是一定一定的的,都是都是大端模式大端模式。 所以,應(yīng)用程序在編程的時候,在把主機內(nèi)存變量中的所以,應(yīng)用程序在編程的時候,在把主機內(nèi)存變量中的IPIP地地址址和和端口號端口號裝入裝入網(wǎng)絡(luò)通信套接字網(wǎng)絡(luò)通信套接字的時候,應(yīng)當把它們從的時候,應(yīng)當把它們從主機字主機字節(jié)順序節(jié)順序轉(zhuǎn)換為轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序;相反,在;相反,在主機輸出顯示主機輸出顯示時,應(yīng)從時,應(yīng)從收到的收到的網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為轉(zhuǎn)換為主機字節(jié)順序主機字節(jié)順序。n 在不同機器上運行網(wǎng)絡(luò)程序,解決兼容性問題的途徑:在不同機器上運行網(wǎng)絡(luò)程序,解決兼容性問題的途徑: 往網(wǎng)絡(luò)上往網(wǎng)絡(luò)上發(fā)送前

25、發(fā)送前:將:將IPIP地址、端口號地址、端口號轉(zhuǎn)換成轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序網(wǎng)絡(luò)字節(jié)序; 從網(wǎng)絡(luò)上從網(wǎng)絡(luò)上接收后接收后:將:將IPIP地址、端口號地址、端口號轉(zhuǎn)換成轉(zhuǎn)換成主機字節(jié)序主機字節(jié)序。四個轉(zhuǎn)換函數(shù)四個轉(zhuǎn)換函數(shù) 套接字編程接口特為解決這個問題設(shè)置套接字編程接口特為解決這個問題設(shè)置了四個函數(shù):了四個函數(shù): htons(): (): 短整數(shù)短整數(shù)主機字節(jié)順序主機字節(jié)順序轉(zhuǎn)換為轉(zhuǎn)換為 網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序, 用于端口號。用于端口號。 htonl():(): 長整數(shù)長整數(shù)主機字節(jié)順序主機字節(jié)順序轉(zhuǎn)換為轉(zhuǎn)換為 網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序, 用于用于IP地址。地址。n 說明說明 h 代表代表host, n

26、 代表代表 network;s 代表代表short,l 代表代表 long ntohs() (): : 短整數(shù)短整數(shù)網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為轉(zhuǎn)換為 主機字節(jié)順序主機字節(jié)順序,用于端口號。,用于端口號。 ntohl() (): : 長整數(shù)長整數(shù)網(wǎng)絡(luò)字節(jié)順序網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為轉(zhuǎn)換為 主機字節(jié)順序主機字節(jié)順序,用于,用于IP地址。地址。 這四個函數(shù)將被轉(zhuǎn)換的數(shù)值作為函數(shù)的這四個函數(shù)將被轉(zhuǎn)換的數(shù)值作為函數(shù)的入口參數(shù),函數(shù)返回值是轉(zhuǎn)換后的結(jié)果。入口參數(shù),函數(shù)返回值是轉(zhuǎn)換后的結(jié)果。四個轉(zhuǎn)換函數(shù)四個轉(zhuǎn)換函數(shù)n 說明說明 h 代表代表host, n 代表代表 network;s 代表代表short,l

27、代表代表 long 3兩個兩個IP地址轉(zhuǎn)換地址轉(zhuǎn)換函數(shù)函數(shù) 在因特網(wǎng)中,在因特網(wǎng)中,IP地址常常用地址常常用點分十進點分十進制制的表示方法,但在套接字中,的表示方法,但在套接字中,IP地址是地址是無符號長整型數(shù)無符號長整型數(shù),套接字編程接口設(shè)置了,套接字編程接口設(shè)置了兩個函數(shù),專門用于兩種形式的兩個函數(shù),專門用于兩種形式的IP地址的地址的轉(zhuǎn)換。轉(zhuǎn)換。(1)inet-addr 函數(shù)函數(shù)unsigned long inet_addr(const char* cp) 入口參數(shù)入口參數(shù)cp:點分十進制形式點分十進制形式IP地址字符串;地址字符串; 返回值返回值: 無符號長整型的網(wǎng)絡(luò)字節(jié)順序無符號長整型

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

29、可以將文字型的主機域名直接轉(zhuǎn)換成型的主機域名直接轉(zhuǎn)換成IP地址:地址:struct hostent* gethostbyname( const char* name); 入口參數(shù)入口參數(shù)name :是站點的主機域名字符串是站點的主機域名字符串 返回值:返回值: 是指向是指向hostent 結(jié)構(gòu)的指針結(jié)構(gòu)的指針 hostent結(jié)構(gòu)包含主機名,主機別名數(shù)組,返結(jié)構(gòu)包含主機名,主機別名數(shù)組,返回地址的類型(一般是回地址的類型(一般是AF_INET),地址長度字),地址長度字節(jié)數(shù),已符合網(wǎng)絡(luò)字節(jié)順序的節(jié)數(shù),已符合網(wǎng)絡(luò)字節(jié)順序的IP地址等。地址等。 4 4域名解析函數(shù)域名解析函數(shù)上述上述gethostb

30、yname()域名解析函數(shù)的返回結(jié)構(gòu)域名解析函數(shù)的返回結(jié)構(gòu)hostent為為 struct hostent char* h_name; /主機名主機名 char* h_aliases; /主機別名列表主機別名列表 short h_addrtype; /返回地址的類型返回地址的類型 short h_length; /地址的長度地址的長度 char* h_addr_list; /主機主機IP地址列表地址列表(主機可能多個主機可能多個IP) #define h_addr h_addr_list0; /主機主機IP地址列表中的第一個地址地址列表中的第一個地址 ;比如,可以用下面的程序,將主機域名解析出

31、比如,可以用下面的程序,將主機域名解析出IP地址:地址: h = gethostbyname(某域名某域名); printf(“host name: %s”, hh_name); printf(“IP address is: %s”, inet_ntoa(*(struct in_addr *)hh_addr);4 4域名解析函數(shù)域名解析函數(shù)2.3 面向連接的套接字編程面向連接的套接字編程2.3.1 套接字的工作過程套接字的工作過程2.3.2 UNIX套接字編程接口的系統(tǒng)調(diào)用套接字編程接口的系統(tǒng)調(diào)用1創(chuàng)建套接字創(chuàng)建套接字SOCKET() SOCKET過程創(chuàng)建一個套接字并返回一個整型過程創(chuàng)建一個套

32、接字并返回一個整型描述符:描述符: int socket(int proto_family, int type, int protocol); 2 BIND()綁定套接字到指定的地址綁定套接字到指定的地址int bind(int sockfd, struct sockaddr* my_addr, int addrlen); 3Listen()啟動監(jiān)聽啟動監(jiān)聽int listen( int sockfd, int queue_size); 舉例:舉例:listen(sockfd, 10); 圖圖2.6 監(jiān)聽套接字使用緩沖區(qū)接納多個客戶端的連接請求監(jiān)聽套接字使用緩沖區(qū)接納多個客戶端的連接請求 4A

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

34、), &addrlen); / 接受客戶連接請求接受客戶連接請求 5CONNECT()請求建立連接請求建立連接int connect(int sockfd, struct sockaddr* service_addr, int addrlen);舉例:舉例: if (connect(sockfd, (struct sockaddr*)(&serv_addr), sizeof(struct sockaddr)0) 連接服務(wù)器有錯時的報錯處理,并退出連接服務(wù)器有錯時的報錯處理,并退出 6 READ()和和WRITE()讀讀/寫套接字寫套接字 int read(int sockfd,

35、 void* buffer, int len ); int write(int sockfd, void* buffer, int len ) 7 SEND()和和RECV()向套接字發(fā)送向套接字發(fā)送/ /接收接收int send(int sockfd, char* buf, int len, int flags );int recv(int sockfd, char* buf, int len, int flags ); 8CLOSE()關(guān)閉套接字關(guān)閉套接字int close(int sockfd); 2.3.3 面向連接的套接字編程實例面向連接的套接字編程實例1 1實例的功能實例的功能 服

36、務(wù)器對來訪的客戶計數(shù),并向客戶報告這個計服務(wù)器對來訪的客戶計數(shù),并向客戶報告這個計數(shù)值。數(shù)值。 客戶建立與服務(wù)器的一個連接并等待它的輸出。客戶建立與服務(wù)器的一個連接并等待它的輸出。 每當連接請求到達時,服務(wù)器生成一個可打印的每當連接請求到達時,服務(wù)器生成一個可打印的ASCII串信息,將它在連接上發(fā)回,然后關(guān)閉連接。串信息,將它在連接上發(fā)回,然后關(guān)閉連接。 客戶顯示收到的信息,然后退出??蛻麸@示收到的信息,然后退出。1 1實例的功能實例的功能 例如,對于服務(wù)器接收的第例如,對于服務(wù)器接收的第10次客戶次客戶連接請求,該客戶將收到并打印如下信息:連接請求,該客戶將收到并打印如下信息: This s

37、erver has been contacted 10 times. 2 2實例程序的命令行參數(shù)實例程序的命令行參數(shù) 實例是實例是UNIX環(huán)境下的環(huán)境下的C程序,客戶和服務(wù)程序,客戶和服務(wù)器程序在編譯后,均以器程序在編譯后,均以命令行方式命令行方式執(zhí)行。執(zhí)行。 服務(wù)器程序服務(wù)器程序執(zhí)行時可以帶執(zhí)行時可以帶一個命令行參數(shù)一個命令行參數(shù),是用來表示接受客戶端請求時的是用來表示接受客戶端請求時的服務(wù)器監(jiān)聽套服務(wù)器監(jiān)聽套接字接字的協(xié)議的協(xié)議端口號端口號。 這個參數(shù)是可選的。如果不指定端口號,這個參數(shù)是可選的。如果不指定端口號,代碼將使用程序內(nèi)定的代碼將使用程序內(nèi)定的缺省缺省端口號端口號5188。 2

38、2實例程序的命令行參數(shù)實例程序的命令行參數(shù) 客戶程序客戶程序執(zhí)行時可以帶執(zhí)行時可以帶兩個命令行參數(shù)兩個命令行參數(shù):一個是:一個是服務(wù)器服務(wù)器所在計算機的所在計算機的主機名主機名,另一個是,另一個是服務(wù)器監(jiān)聽的服務(wù)器監(jiān)聽的協(xié)議端口號協(xié)議端口號。這兩個參數(shù)都是可選的。這兩個參數(shù)都是可選的。 如果沒有指定協(xié)議端口號,客戶使用程序內(nèi)定的如果沒有指定協(xié)議端口號,客戶使用程序內(nèi)定的缺省端口缺省端口5188。 如果一個參數(shù)也沒有,客戶使用如果一個參數(shù)也沒有,客戶使用缺省端口缺省端口5188和和缺省主機名缺省主機名localhost,localhost是映射到客戶所在計是映射到客戶所在計算機的一個別名。算機的

39、一個別名。 允許客戶與本地機上的服務(wù)器通信,允許客戶與本地機上的服務(wù)器通信,對調(diào)試對調(diào)試是是很很有用有用的。的。 3 3客戶程序代碼客戶程序代碼/*-* 程序程序: client.c* 目的目的: 創(chuàng)建一個套接字,通過網(wǎng)絡(luò)連接一個服務(wù)器,并創(chuàng)建一個套接字,通過網(wǎng)絡(luò)連接一個服務(wù)器,并打印來自服務(wù)器的信息打印來自服務(wù)器的信息* 語法語法: client host port * host - 運行服務(wù)器的計算機的名字運行服務(wù)器的計算機的名字* port - 服務(wù)器監(jiān)聽套接字所用協(xié)議端口號服務(wù)器監(jiān)聽套接字所用協(xié)議端口號* 注意:兩個參數(shù)都是可選的。如果未指定主機名,客戶注意:兩個參數(shù)都是可選的。如果未

40、指定主機名,客戶* 使用缺省主機名使用缺省主機名localhost;如果未指定端口號,客戶;如果未指定端口號,客戶* 將使用將使用PROTOPORT中給定的缺省協(xié)議端口號。中給定的缺省協(xié)議端口號。*-*/ 3 3客戶程序代碼客戶程序代碼#include #include /* UNIX下,套接字的相關(guān)包含文件。*/#include #include #include #include #include #define PROTOPORT 5188 /*缺省協(xié)議端口號*/extern int errno;char localhost = “l(fā)ocalhost”; /*缺省主機名*/ 3 3客戶程

41、序代碼客戶程序代碼main(int argc, char *argv) struct hostent *ptrh; /* 指向主機列表中一個條目的指針 */ struct sockaddr_in servaddr; /* 存放服務(wù)器端網(wǎng)絡(luò)地址的結(jié)構(gòu) */ int sockfd; /* 客戶端的套接字描述符 */ int port; /* 服務(wù)器端套接字協(xié)議端口號*/ char* host; /* 服務(wù)器主機名指針 */ int n; /* 讀取的字符數(shù) */ char buf1000 ; /* 緩沖區(qū),接收服務(wù)器發(fā)來的數(shù)據(jù) */ memset(char*)&servaddr, 0, s

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

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

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

45、izeof(servaddr) 0) write(1,buf, n); /*1stdout設(shè)備設(shè)備(即顯示器即顯示器), 0stdin設(shè)備 n = recv(sockfd, buf, sizeof( buf ), 0 ); /* 關(guān)閉套接字*/ closesocket(sockfd); /* 終止客戶程序*/ exit(0); 3 3客戶程序代碼客戶程序代碼4 4服務(wù)器實例代碼服務(wù)器實例代碼/*-* 程序程序:server.c* 目的目的: 分配一個套接字,然后反復(fù)執(zhí)行如下幾步:* (1) 等待客戶的下一個連接* (2) 發(fā)送一個短消息給客戶* (3) 關(guān)閉與客戶的連接* (4) 轉(zhuǎn)向(1)步

46、* 命令行語法命令行語法: server port * port 服務(wù)器端監(jiān)聽套接字使用的協(xié)議端口號* 注意注意: 端口號可選。如果未指定端口號,服務(wù)器使用PROTOPORT中* 指定的缺省端口號*-*/ 4 4服務(wù)器實例代碼服務(wù)器實例代碼#include #include #include #include #include #include #define PROTOPORT 5188 /*監(jiān)聽套接字的缺省協(xié)議端口號*/#define QLEN 6 /*監(jiān)聽套接字的請求隊列大小*/int visits = 0; /* 對于客戶連接的計數(shù)*/ main(argc, argv)int argc

47、;char* argv;struct hostent *ptrh; /*指向主機列表中一個條目的指針*/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é)議端口號*/int alen; /*地址長度*/char buf1000; /*供服務(wù)器發(fā)送字符串所用的緩沖區(qū)*/ 4 4服務(wù)器實例代碼服務(wù)器實例代碼memset(char*)&

48、;servaddr, 0, sizeof(servaddr); /*清空sockaddr結(jié)構(gòu)*/servaddr.sin_family = AF_INET; /*設(shè)置為因特網(wǎng)協(xié)議族*/servaddr.sin_addr.s_addr =INADDR_ANY; /*設(shè)置本地IP地址*/ /*檢查命令行參數(shù),若指定了,就用該端口號,否則使用缺省端口號*/if (argc 1) port = atoi(argv1); /*如果指定了端口號,就將它轉(zhuǎn)換成整數(shù)*/else port = PROTOPORT; /*否則,使用缺省端口號*/ 4 4服務(wù)器實例代碼服務(wù)器實例代碼if (port 0) /* 測

49、試端口號是否合法 */ servaddr.sin_port = htons(u_short)port);else /* 打印錯誤信息并退出 */ fprintf( stderr, ”bad portnumber %sn”, argv1 ); exit(1); /* 創(chuàng)建一個用于監(jiān)聽的流式套接字用于監(jiān)聽的流式套接字 */listenfd = SOCKET(AF_INET, SOCK_STREAM, 0);if (listenfd 0) fprintf( stderr, “socket creation failedn” ); exit(1); 4 4服務(wù)器實例代碼服務(wù)器實例代碼/* 將本地地址綁

50、定到監(jiān)聽套接字監(jiān)聽套接字*/if ( bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr) ) 0) fprintf(stderr, ”bind failedn” ); exit(1); /* 開始監(jiān)聽,并指定監(jiān)聽套接字監(jiān)聽套接字請求隊列的長度 */if (listen(listenfd, QLEN) 0) fprintf(stderr, ”listen filedn” ); exit(1); 4 4服務(wù)器實例代碼服務(wù)器實例代碼 while(1) /*服務(wù)器主循環(huán)-接受和處理來自客戶端的連接請求*/ alen = s

51、izeof(clientaddr); /*接受客戶端連接請求,并生成響應(yīng)套接字響應(yīng)套接字*/ if(clientfd=accept(listenfd,(struct sockaddr *)&clientaddr, &alen) 0 ) fprintf( stderr, “accept failedn”); exit(1); visits+; /*累加訪問的客戶數(shù)*/ sprintf(buf, “This server has been contacted %d time.n”, visits ); send(clientfd, buf, strlen(buf), 0 ); /*

52、向客戶端發(fā)送信息*/ closesocket(clientfd); /*關(guān)閉響應(yīng)套接字響應(yīng)套接字*/ closesocket(listenfd); /*關(guān)閉監(jiān)聽套接字監(jiān)聽套接字*/ 4 4服務(wù)器實例代碼服務(wù)器實例代碼關(guān)于阻塞的問題關(guān)于阻塞的問題 圖圖2.7 服務(wù)器進程因調(diào)用服務(wù)器進程因調(diào)用ACCEPT()而被阻塞而被阻塞 2.3.4 進程的阻塞問題和對策進程的阻塞問題和對策1 1什么是阻塞什么是阻塞 阻塞阻塞是指一個進程執(zhí)行了一個函數(shù)或是指一個進程執(zhí)行了一個函數(shù)或者系統(tǒng)調(diào)用,該函數(shù)由于某種原因者系統(tǒng)調(diào)用,該函數(shù)由于某種原因不能立不能立即完成即完成,因而,因而不能返回調(diào)用它的進程不能返回調(diào)用它的

53、進程,導(dǎo),導(dǎo)致致進程進程受控于這個函數(shù)而受控于這個函數(shù)而處于處于等待等待的狀態(tài)的狀態(tài),進程的這種狀態(tài)稱為阻塞。進程的這種狀態(tài)稱為阻塞。 2.3.4 進程的阻塞問題和對策進程的阻塞問題和對策圖圖2.8 RECV()函數(shù)的兩種執(zhí)行方式函數(shù)的兩種執(zhí)行方式 2 2能引起阻塞的套接字調(diào)用能引起阻塞的套接字調(diào)用 在在Berkeley套接字網(wǎng)絡(luò)編程接口的模型中,套接字網(wǎng)絡(luò)編程接口的模型中,套接套接字的字的默認行為默認行為是是阻塞阻塞的的,具體地說,在一定情況下,具體地說,在一定情況下,有以下操作套接字的系統(tǒng)調(diào)用會引起進程阻塞有以下操作套接字的系統(tǒng)調(diào)用會引起進程阻塞: (1)accept() (2)read(

54、)、recv() 和和 readfrom() (3)write()、send() 和和 sendto() (4)connect() (5)select() (6)closesocket() 3 3阻塞工作模式帶來的問題阻塞工作模式帶來的問題圖圖2.9 采用阻塞工作模式的服務(wù)器不能很好地為多個客戶服務(wù)采用阻塞工作模式的服務(wù)器不能很好地為多個客戶服務(wù) 采用采用阻塞阻塞工作工作模式模式的的單進程服務(wù)器單進程服務(wù)器是是不能不能很很好地好地同時為同時為多個多個客戶客戶服務(wù)的。下圖是一個例子。服務(wù)的。下圖是一個例子。 4 4一種解決方案一種解決方案 利用利用 UNIX/Linux 操作系統(tǒng)的操作系統(tǒng)的 f

55、ork() 系系統(tǒng)調(diào)用,編制統(tǒng)調(diào)用,編制多進程多進程并發(fā)執(zhí)行的服務(wù)器程序并發(fā)執(zhí)行的服務(wù)器程序??梢钥梢詣?chuàng)建子進程創(chuàng)建子進程。對于。對于每一個每一個客戶端,用客戶端,用一一個專門的進程個專門的進程為它服務(wù),通過進程的并發(fā)執(zhí)為它服務(wù),通過進程的并發(fā)執(zhí)行,來實現(xiàn)對多個客戶的并發(fā)服務(wù)。行,來實現(xiàn)對多個客戶的并發(fā)服務(wù)。Unix / Linux 系統(tǒng)調(diào)用系統(tǒng)調(diào)用 fork() 的特點的特點n 進程在進程在調(diào)用調(diào)用fork()時,會將自己拷貝一份,一份為時,會將自己拷貝一份,一份為父進程父進程,另一份,另一份為為子進程子進程。CPU會會分別調(diào)度執(zhí)行分別調(diào)度執(zhí)行。n 在各進程中調(diào)用在各進程中調(diào)用fork()后

56、的返回值:后的返回值: 父進程父進程:fork() 返回值為返回值為正正(為新建的子進程的進程號為新建的子進程的進程號) 子進程子進程:fork() 返回值為返回值為 0, 出錯時出錯時:fork() 返回值為返回值為負負。n 因此,根據(jù)因此,根據(jù)fork()返回值就可返回值就可分清分清當前進程當前進程是是父進程父進程還是還是子進程子進程。n 另外,調(diào)用另外,調(diào)用fork()前的父進程中前的父進程中每個打開的套接字描述符,每個打開的套接字描述符,在在fork()返回后會被返回后會被父進程父進程和和子進程子進程共享。共享。此時因為有父、子此時因為有父、子2個進個進程共享,故每個套接字描述符引用計

57、數(shù)程共享,故每個套接字描述符引用計數(shù) reference count=2,以后以后,該共享的套接字描述符在各進程中該共享的套接字描述符在各進程中用用close()每關(guān)閉每關(guān)閉1次,次,引用計數(shù)引用計數(shù)值值count就會減就會減1,當套接字描述符的引用計數(shù)值當套接字描述符的引用計數(shù)值count被減為被減為0時時,此套接字所占用資源才被釋放。同時,該網(wǎng)絡(luò)結(jié)點會發(fā)送出一個此套接字所占用資源才被釋放。同時,該網(wǎng)絡(luò)結(jié)點會發(fā)送出一個報文首部報文首部FIN標志為標志為1的的TCP段,進入段,進入釋放釋放TCP連接連接的過程。的過程。父進程主代碼父進程主代碼 .If (pid = fork() = 0) .

58、子進程代碼子進程代碼 exit(0); else if (pid 0) 報錯信息報錯信息 .父進程主代碼父進程主代碼 .使用使用 fork() 時基本的編程框架是:時基本的編程框架是: 父進程 父進程 子進程 典型的并發(fā)服務(wù)器編程框架典型的并發(fā)服務(wù)器編程框架listenfd = socket(); /監(jiān)聽套接字bind(listenfd, ); /綁定監(jiān)聽套接字listen(listenfd, LISTENQ); /啟動監(jiān)聽for( ; ; ) connfd = accept(listenfd, ); /接受客戶連接,生成連接套接字 if (pid = fork() = 0) close(li

59、stenfd); /子進程關(guān)閉監(jiān)聽套接字 do_it(connfd); /在連接套接字上處理該客戶請求 close(connfd); /結(jié)束該客戶處理, 關(guān)閉連接套接字 exit(0); /子進程終止 close(connfd); /父進程關(guān)閉連接套接字 注:詳情可參見注:詳情可參見Unix網(wǎng)絡(luò)編程網(wǎng)絡(luò)編程第第2版版 第第1卷卷4.7 - 4.8舉例:#include #include #include #include void main(int argc, char* argv) int listenfd, clientfd, pid; struct sockaddr_in ssockad

60、dr, csockaddr; char buffer1024; int addrlen, n; Unix / Linux 多進程并發(fā)服務(wù)器例多進程并發(fā)服務(wù)器例Unix / Linux 多進程并發(fā)服務(wù)器例多進程并發(fā)服務(wù)器例/* 創(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(&ssockaddr, 0, sizeof(struct sockaddr_in);ssockaddr.sin_family = AF_INET;ssockaddr.sin_addr.s_addr =

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論