国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Unix > 正文

UNIX網(wǎng)絡(luò)編程讀書筆記:基本TCP套接口編程

2024-06-28 13:27:31
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
UNIX網(wǎng)絡(luò)編程讀書筆記:基本TCP套接口編程

編寫一個(gè)完整的TCP客戶和服務(wù)器程序所需要的基本套接口函數(shù):1、socket函數(shù)(客戶端、服務(wù)器端都必須調(diào)用)

image

參數(shù)family指明協(xié)議族(family),該參數(shù)也往往被稱為協(xié)議域(domain)。所以有的書上聲明如下:

image

而且對(duì)于socket函數(shù)第一個(gè)參數(shù),在不同書籍上可能會(huì)看到不同前綴的取值常量列表,如下兩圖所示:

image

image

AF_xxx與PF_xxx:

AF_前綴表地址族,PF_前綴表示協(xié)議族。歷史上曾有這樣的想法:?jiǎn)蝹€(gè)協(xié)議族可以支持多個(gè)地址族,PF_值用來(lái)創(chuàng)建套接口,而AF_值用于套接口地址結(jié)構(gòu)。但實(shí)際上,支持多個(gè)地址族的協(xié)議族從來(lái)就未實(shí)現(xiàn)過(guò),而且頭文件<sys/socket.h>中為一給定協(xié)議定義的PF_值總是與此協(xié)議的AF_值相等

2、connect函數(shù)(TCP客戶端調(diào)用)

image

客戶在調(diào)用函數(shù)connect前不必非得調(diào)用bind函數(shù),因?yàn)槿绻枰脑挘瑑?nèi)核會(huì)確定源ip地址,并選擇一個(gè)臨時(shí)端口作為源端口。

如果是TCP套接口,調(diào)用connect函數(shù)將激發(fā)TCP的三路握手過(guò)程,而且僅在連接建立成功或出錯(cuò)時(shí)才返回,其中出錯(cuò)返回可能有以下幾種情況:

(1)若TCP客戶沒(méi)有收到SYN分節(jié)的響應(yīng),則返回ETIMEDOUT錯(cuò)誤。

(2)若對(duì)客戶的SYN的響應(yīng)是RST(表示復(fù)位),則表明該服務(wù)器主機(jī)在我們指定的端口上沒(méi)有進(jìn)程在等待與之連接(例如服務(wù)器進(jìn)程也許沒(méi)在運(yùn)行)。這是一種硬錯(cuò)誤(hard error),客戶一接收到RST就馬上返回ECONNREFUSED錯(cuò)誤。

(3)若客戶發(fā)出的SYN在中間的某個(gè)路由器上引發(fā)了一個(gè)“destination unreachable”(目的地不可達(dá))ICMP錯(cuò)誤,則認(rèn)為是一種軟錯(cuò)(soft error)。客戶主機(jī)內(nèi)核保存該消息,并按一定時(shí)間間隔延遲重發(fā)SYN。若在某個(gè)規(guī)定的時(shí)間(4.4BSD規(guī)定為75秒)后仍未收到響應(yīng),則 把保存的消息(即ICMP錯(cuò)誤)作為EHOSTUNREACH或ENETUNREACH錯(cuò)誤返回給進(jìn)程。

若connect失敗則該套接口不再可用,必須關(guān)閉,我們不能對(duì)這樣的套接口再次調(diào)用connect函數(shù)。當(dāng)循環(huán)調(diào)用函數(shù)connect嘗試給定主機(jī)的各個(gè)IP地址直到有一個(gè)成功時(shí),每次connect失敗后,都必須close當(dāng)前的套接口描述字,重新調(diào)用socket。

3、bind函數(shù)(服務(wù)器調(diào)用、客戶端可以調(diào)用也可不調(diào)用)

image

進(jìn)程可以把一個(gè)特定的IP地址捆綁到它的套接口上,不過(guò)這個(gè)IP地址必須屬于其所在主機(jī)的網(wǎng)絡(luò)接口之一。對(duì)于TCP客戶,這就為在該套接口上發(fā)送的IP數(shù)據(jù)報(bào)指派了源IP地址。對(duì)于TCP服務(wù)器,這就限定該套接口只接收那些目的地為這個(gè)IP地址的客戶連接。

TCP客戶通常不把IP地址捆綁到它的套接口上。當(dāng)連接套接口時(shí),內(nèi)核將根據(jù)所用外出網(wǎng)絡(luò)接口來(lái)選擇源IP地址,而所用外出接口則取決于到達(dá)服務(wù)器所需的路徑。

image

如果指定端口號(hào)為0,那么內(nèi)核就在bind被調(diào)用時(shí)選擇一個(gè)臨時(shí)端口;

如果指定IP地址為通配地址,那么內(nèi)核將等到套接口已連接(TCP)或已在套接口上發(fā)出數(shù)據(jù)報(bào)(UDP)時(shí)才選擇一個(gè)本地IP地址。

對(duì)于IPv4來(lái)說(shuō),通配地址由常值INADDR_ANY來(lái)指定,其值一般為0. 它告知內(nèi)核去選擇IP地址。

無(wú)論是網(wǎng)絡(luò)字節(jié)序還是主機(jī)字節(jié)序,INADDR_ANY的值(為0)都一樣,因此使用htonl并非必須。不過(guò)既然頭文件<netinet/in.h>中定義的所有INADDR_常值都是按照主機(jī)字節(jié)序定義的,我們應(yīng)該對(duì)所有這些常值都使用htonl。

4、listen函數(shù)(TCP服務(wù)器調(diào)用)

image

listen函數(shù)做兩件事情:

(1)當(dāng)socket函數(shù)創(chuàng)建一個(gè)套接口時(shí),它被假設(shè)為一個(gè)主動(dòng)套接口,也就是說(shuō),它是一個(gè)將調(diào)用connect發(fā)起連接的客戶套接口。listen函數(shù)把一個(gè)未連接的套接口轉(zhuǎn)換成一個(gè)被動(dòng)套接口,指示內(nèi)核應(yīng)該接受指向該套接口的連接請(qǐng)求。調(diào)用listen導(dǎo)致套接口從CLOSED狀態(tài)轉(zhuǎn)換到LISTEN狀態(tài)。

(2)backlog參數(shù)規(guī)定了內(nèi)核應(yīng)該為相應(yīng)套接口排隊(duì)的最大連接個(gè)數(shù)。

為了理解其中的backlog參數(shù),我們必須認(rèn)識(shí)到內(nèi)核為任何一個(gè)給定的監(jiān)聽(tīng)套接口維護(hù)兩個(gè)隊(duì)列:

(1)未完成連接隊(duì)列(incomplete connection queue),每個(gè)這樣的SYN分節(jié)對(duì)應(yīng)其中一項(xiàng):已由客戶發(fā)出并到達(dá)服務(wù)器,而服務(wù)器正在等待完成相應(yīng)的TCP三路握手過(guò)程。這些套接口處于SYN_RCVD狀態(tài)。

(2)已完成連接隊(duì)列(completed connection queue),每個(gè)已完成TCP三路握手過(guò)程的客戶對(duì)應(yīng)其中一項(xiàng)。這些套接口處于ESTABLISHED狀態(tài)。

image

當(dāng)進(jìn)程調(diào)用accept時(shí),已完成連接隊(duì)列中的隊(duì)頭項(xiàng)將返回給進(jìn)程,或者如果該隊(duì)列為空,那么進(jìn)程將被投入睡眠,直到TCP在該隊(duì)列中放入一項(xiàng)才喚醒它。

不要把backlog定義為0,因?yàn)椴煌膶?shí)現(xiàn)對(duì)此有不同的解釋。如果不想讓客戶連接到你的監(jiān)聽(tīng)套接口上,那就關(guān)掉該監(jiān)聽(tīng)套接口。

5、accept函數(shù)(TCP服務(wù)器調(diào)用)

image

accept函數(shù)由TCP服務(wù)器調(diào)用,用于從已完成連接隊(duì)列隊(duì)頭返回下一個(gè)已完成連接。如果已完成連接隊(duì)列為空,那么進(jìn)程被投入睡眠(假定套接口為缺省的阻塞方式)。

參數(shù)cliaddr和addrlen用來(lái)返回已連接的對(duì)端進(jìn)程(客戶)的協(xié)議地址。

如果accept成功,那么其返回值是由內(nèi)核自動(dòng)生成的一個(gè)全新描述字,代表與所返回客戶的TCP連接。

在討論accept函數(shù)時(shí),我們稱它的第一個(gè)參數(shù)為監(jiān)聽(tīng)套接口(listening socket)描述字(由socket創(chuàng)建,隨后用作bind和listen的第一個(gè)參數(shù)的描述字),稱它的返回值為已連接套接口(connected socket)描述字。區(qū)分這兩個(gè)套接口非常重要。一個(gè)服務(wù)器通常僅僅創(chuàng)建一個(gè)監(jiān)聽(tīng)套接口,它在服務(wù)器的生命期內(nèi)一直存在。內(nèi)核為每個(gè)由服務(wù)器進(jìn)程接受的客戶連接創(chuàng)建一個(gè)已連接套接口(也就是說(shuō)對(duì)于它的TCP三路握手過(guò)程已經(jīng)完成)。當(dāng)服務(wù)器完成對(duì)于某個(gè)給定客戶的服務(wù)時(shí),相應(yīng)的已連接套接口就被關(guān)閉。

本函數(shù)最多返回三個(gè)值:一個(gè)既可能是新套接口描述字也可能是出錯(cuò)指示的整數(shù)、客戶進(jìn)程的協(xié)議地址(由cliaddr指針?biāo)福┮约霸摰刂返拇笮。ㄓ蒩ddrlen指針?biāo)福H绻覀儗?duì)返回客戶協(xié)議地址不感興趣,那么可以把cliaddr和addrlen均設(shè)置為空指針。

6、fork和exec函數(shù)(構(gòu)建并發(fā)服務(wù)器)

fork函數(shù):http://www.CUOXin.com/nufangrensheng/p/3509492.html。

exec函數(shù):http://www.CUOXin.com/nufangrensheng/p/3510821.html。

7、close函數(shù)

UNIX通常的close函數(shù)也用來(lái)關(guān)閉套接口,并終止TCP連接。

image

close一個(gè)TCP套接口的缺省行為是把該套接口標(biāo)記成已關(guān)閉,然后立即返回到調(diào)用進(jìn)程。該套接口描述字不能再由調(diào)用進(jìn)程使用,也就是說(shuō)它不能再作為read或write的第一個(gè)參數(shù)。然而TCP將嘗試發(fā)送已排隊(duì)等待發(fā)送到對(duì)端的任何數(shù)據(jù),發(fā)送完畢后發(fā)生的是正常的TCP連接終止序列。

8、getsockname和getpeername函數(shù)

image

getsockname:返回與某個(gè)套接口關(guān)聯(lián)的本地協(xié)議地址。

getpeername:返回與某個(gè)套接口關(guān)聯(lián)的遠(yuǎn)地協(xié)議地址。

這兩個(gè)函數(shù)返回與某個(gè)網(wǎng)絡(luò)連接的兩端中任何一端相關(guān)聯(lián)的協(xié)議地址,對(duì)于IPv4和IPv6來(lái)說(shuō),就是IP地址和端口號(hào)的組合。

需要這兩個(gè)函數(shù)的理由如下:

(1)在沒(méi)有調(diào)用bind的TCP客戶上,connect成功返回后,getsockname用于返回由內(nèi)核賦予該連接的本地IP地址和本地端口號(hào)。

(2)在以端口號(hào)0調(diào)用bind(告知內(nèi)核去選擇本地端口號(hào))后,getsockname用于返回由內(nèi)核賦予的本地端口號(hào)。

(3)getsockname可用于獲取某個(gè)套接口的地址族。

(4)在一個(gè)以通配IP地址調(diào)用bind之后的TCP服務(wù)器上,與某個(gè)客戶的連接一旦建立(accept成功返回),getsockname就可以用于返回由內(nèi)核賦予該連接的本地IP地址。在這樣的調(diào)用中,套接口描述字必須是已連接套接口的描述字,而不是監(jiān)聽(tīng)套接口的描述字。

(5)當(dāng)一個(gè)服務(wù)器是由調(diào)用過(guò)accept的某個(gè)進(jìn)程通過(guò)調(diào)用exec更換了程序時(shí),它能夠獲取客戶身份的唯一途徑便是調(diào)用getpeername。

總結(jié):

所有客戶和服務(wù)器都從調(diào)用socket開(kāi)始,它返回一個(gè)套接口描述字。客戶隨后調(diào)用connect,服務(wù)器則調(diào)用bind、listen和accept。套接口通常使用標(biāo)準(zhǔn)的close函數(shù)關(guān)閉。

image


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 马关县| 太谷县| 夏河县| 策勒县| 长葛市| 望江县| 横峰县| 贵南县| 丹棱县| 广东省| 五大连池市| 延津县| 寻乌县| 福安市| 施甸县| 那曲县| 金川县| 周宁县| 无棣县| 渝中区| 博湖县| 乌海市| 东丰县| 宝山区| 四子王旗| 望奎县| 永济市| 荆州市| 密山市| 梁平县| 灌云县| 德清县| 苍梧县| 南通市| 永兴县| 富蕴县| 贵阳市| 建宁县| 杭锦后旗| 固镇县| 故城县|