一、網(wǎng)絡(luò)編程概述
1.1 網(wǎng)絡(luò)概述
網(wǎng)絡(luò)編程技術(shù)是當(dāng)前一種主流的編程技術(shù),隨著聯(lián)網(wǎng)趨勢的逐步增強(qiáng)以及網(wǎng)絡(luò)應(yīng)用程序的大量出現(xiàn),所以在實(shí)際的開發(fā)中網(wǎng)絡(luò)編程技術(shù)獲得了大量的使用。本章中以淺顯的基礎(chǔ)知識(shí)說明和實(shí)際的案例使廣大初學(xué)者能夠進(jìn)入網(wǎng)絡(luò)編程技術(shù)的大門,至于以后的實(shí)際修行就要閱讀進(jìn)階的書籍以及進(jìn)行大量的實(shí)際練習(xí)。
1.2 客戶端網(wǎng)絡(luò)編程步驟
客戶端(Client)是指網(wǎng)絡(luò)編程中首先發(fā)起連接的程序,客戶端一般實(shí)現(xiàn)程序界面和基本邏輯實(shí)現(xiàn),在進(jìn)行實(shí)際的客戶端編程時(shí),無論客戶端復(fù)雜還是簡單,以及客戶端實(shí)現(xiàn)的方式,客戶端的編程主要由三個(gè)步驟實(shí)現(xiàn):
(1)建立網(wǎng)絡(luò)連接
客戶端網(wǎng)絡(luò)編程的第一步都是建立網(wǎng)絡(luò)連接。在建立網(wǎng)絡(luò)連接時(shí)需要指定連接到的服務(wù)器的IP地址和端口號(hào),建立完成以后,會(huì)形成一條虛擬的連接,后續(xù)的操作就可以通過該連接實(shí)現(xiàn)數(shù)據(jù)交換了。
(2)交換數(shù)據(jù)
連接建立以后,就可以通過這個(gè)連接交換數(shù)據(jù)了。交換數(shù)據(jù)嚴(yán)格按照請求響應(yīng)模型進(jìn)行,由客戶端發(fā)送一個(gè)請求數(shù)據(jù)到服務(wù)器,服務(wù)器反饋一個(gè)響應(yīng)數(shù)據(jù)給客戶端,如果客戶端不發(fā)送請求則服務(wù)器端就不響應(yīng)。
根據(jù)邏輯需要,可以多次交換數(shù)據(jù),但是還是必須遵循請求響應(yīng)模型。
(3)關(guān)閉網(wǎng)絡(luò)連接
在數(shù)據(jù)交換完成以后,關(guān)閉網(wǎng)絡(luò)連接,釋放程序占用的端口、內(nèi)存等系統(tǒng)資源,結(jié)束網(wǎng)絡(luò)編程。
最基本的步驟一般都是這三個(gè)步驟,在實(shí)際實(shí)現(xiàn)時(shí),步驟2會(huì)出現(xiàn)重復(fù),在進(jìn)行代碼組織時(shí),由于網(wǎng)絡(luò)編程是比較耗時(shí)的操作,所以一般開啟專門的現(xiàn)場進(jìn)行網(wǎng)絡(luò)通訊。
1.3 服務(wù)器端網(wǎng)絡(luò)編程步驟
服務(wù)器端(Server)是指在網(wǎng)絡(luò)編程中被動(dòng)等待連接的程序,服務(wù)器端一般實(shí)現(xiàn)程序的核心邏輯以及數(shù)據(jù)存儲(chǔ)等核心功能。服務(wù)器端的編程步驟和客戶端不同,是由四個(gè)步驟實(shí)現(xiàn),依次是:
(1)監(jiān)聽端口
服務(wù)器端屬于被動(dòng)等待連接,所以服務(wù)器端啟動(dòng)以后,不需要發(fā)起連接,而只需要監(jiān)聽本地計(jì)算機(jī)的某個(gè)固定端口即可。
這個(gè)端口就是服務(wù)器端開放給客戶端的端口,服務(wù)器端程序運(yùn)行的本地計(jì)算機(jī)的IP地址就是服務(wù)器端程序的IP地址。
(2)獲得連接
當(dāng)客戶端連接到服務(wù)器端時(shí),服務(wù)器端就可以獲得一個(gè)連接,這個(gè)連接包含客戶端的信息,例如客戶端IP地址等等,服務(wù)器端和客戶端也通過該連接進(jìn)行數(shù)據(jù)交換。
一般在服務(wù)器端編程中,當(dāng)獲得連接時(shí),需要開啟專門的線程處理該連接,每個(gè)連接都由獨(dú)立的線程實(shí)現(xiàn)。
(3)交換數(shù)據(jù)
服務(wù)器端通過獲得的連接進(jìn)行數(shù)據(jù)交換。服務(wù)器端的數(shù)據(jù)交換步驟是首先接收客戶端發(fā)送過來的數(shù)據(jù),然后進(jìn)行邏輯處理,再把處理以后的結(jié)果數(shù)據(jù)發(fā)送給客戶端。簡單來說,就是先接收再發(fā)送,這個(gè)和客戶端的數(shù)據(jù)交換數(shù)序不同。
其實(shí),服務(wù)器端獲得的連接和客戶端連接是一樣的,只是數(shù)據(jù)交換的步驟不同。
當(dāng)然,服務(wù)器端的數(shù)據(jù)交換也是可以多次進(jìn)行的。
在數(shù)據(jù)交換完成以后,關(guān)閉和客戶端的連接。
(4)關(guān)閉連接
當(dāng)服務(wù)器程序關(guān)閉時(shí),需要關(guān)閉服務(wù)器端,通過關(guān)閉服務(wù)器端使得服務(wù)器監(jiān)聽的端口以及占用的內(nèi)存可以釋放出來,實(shí)現(xiàn)了連接的關(guān)閉。
其實(shí)服務(wù)器端編程的模型和呼叫中心的實(shí)現(xiàn)是類似的,例如移動(dòng)的客服電話10086就是典型的呼叫中心,當(dāng)一個(gè)用戶撥打10086時(shí),轉(zhuǎn)接給一個(gè)專門的客服人員,由該客服實(shí)現(xiàn)和該用戶的問題解決,當(dāng)另外一個(gè)用戶撥打10086時(shí),則轉(zhuǎn)接給另一個(gè)客服,實(shí)現(xiàn)問題解決,依次類推。
在服務(wù)器端編程時(shí),10086這個(gè)電話號(hào)碼就類似于服務(wù)器端的端口號(hào)碼,每個(gè)用戶就相當(dāng)于一個(gè)客戶端程序,每個(gè)客服人員就相當(dāng)于服務(wù)器端啟動(dòng)的專門和客戶端連接的線程,每個(gè)線程都是獨(dú)立進(jìn)行交互的。
這就是服務(wù)器端編程的模型,只是TCP方式是需要建立連接的,對于服務(wù)器端的壓力比較大,而UDP是不需要建立連接的,對于服務(wù)器端的壓力比較小罷了。
二、TCP詳解
互聯(lián)網(wǎng)協(xié)議族(英語:Internet Protocol Suite,縮寫為IPS),是一個(gè)網(wǎng)絡(luò)通信模型,以及一整個(gè)網(wǎng)絡(luò)傳輸協(xié)議家族,為互聯(lián)網(wǎng)的基礎(chǔ)通信架構(gòu)。它常被通稱為TCP/IP協(xié)議族(英語:TCP/IP Protocol Suite,或TCP/IP Protocols),簡稱TCP/IP協(xié)議。因?yàn)檫@個(gè)協(xié)議家族的兩個(gè)核心協(xié)議,包括TCP(傳輸控制協(xié)議)和IP(網(wǎng)際協(xié)議),為這個(gè)家族中最早通過的標(biāo)準(zhǔn)。
對于應(yīng)用層開發(fā)人員,接觸最多的網(wǎng)絡(luò)協(xié)議通常都是傳輸層的TCP,為什么這么說,因?yàn)樵偻系膽?yīng)用層協(xié)議,如:HTTP、HTTPS、POP3、SMTP、RPC、FTP、TELNET等等都是基于TCP傳輸層協(xié)議。但對于IP協(xié)議,對于應(yīng)用程序員來說更多的印象還是IP地址這個(gè)東西,實(shí)際上IP協(xié)議是位于TCP協(xié)議之下的網(wǎng)絡(luò)層,對于應(yīng)用層程序員來說很難直接接觸。

2.1 TCP編程的服務(wù)器端一般步驟是
(1)創(chuàng)建一個(gè)socket,用函數(shù)socket();?
(2)設(shè)置socket屬性,用函數(shù)setsockopt(); * 可選?
(3)綁定IP地址、端口等信息到socket上,用函數(shù)bind();?
(4)開啟監(jiān)聽,用函數(shù)listen();?
(5)接收客戶端上來的連接,用函數(shù)accept();?
(6)收發(fā)數(shù)據(jù),用函數(shù)send()和recv(),或者read()和write();?
(7)關(guān)閉網(wǎng)絡(luò)連接;
(8)關(guān)閉監(jiān)聽;
2.2 TCP編程的客戶端一般步驟是
(1)創(chuàng)建一個(gè)socket,用函數(shù)socket();?
(2)設(shè)置socket屬性,用函數(shù)setsockopt();* 可選?
(3)綁定IP地址、端口等信息到socket上,用函數(shù)bind();* 可選?
(4)設(shè)置要連接的對方的IP地址和端口等屬性;?
(5)連接服務(wù)器,用函數(shù)connect();?
(6)收發(fā)數(shù)據(jù),用函數(shù)send()和recv(),或者read()和write();?
(7)關(guān)閉網(wǎng)絡(luò)連接;
2.3 TCP補(bǔ)充
TCP充分實(shí)現(xiàn)了數(shù)據(jù)傳輸時(shí)各種控制功能,可以進(jìn)行丟包的重發(fā)控制,還可以對次序亂掉的分包進(jìn)行順序控制。而這些在UDP中都沒有。此外,TCP作為一種面向有連接的協(xié)議,只有在確認(rèn)通信對端存在時(shí)才會(huì)發(fā)送數(shù)據(jù),從而可以控制通信流量的浪費(fèi)。TCP通過檢驗(yàn)和、序列號(hào)、確認(rèn)應(yīng)答、重發(fā)控制、連接管理以及窗口控制等機(jī)制實(shí)現(xiàn)可靠性傳輸。
2.4 TCP的狀態(tài)轉(zhuǎn)換圖:

2.5 三次握手
(1)第一次握手:客戶端發(fā)送syn包(syn=x)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);
(2)第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=x+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=y),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
(3)第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=y+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。
握手過程中傳送的包里不包含數(shù)據(jù),三次握手完畢后,客戶端與服務(wù)器才正式開始傳送數(shù)據(jù)。理想狀態(tài)下,TCP連接一旦建立,在通信雙方中的任何一方主動(dòng)關(guān)閉連接之前,TCP 連接都將被一直保持下去。

2,6為什么會(huì)采用三次握手,若采用二次握手可以嗎?四次呢?
建立連接的過程是利用客戶服務(wù)器模式,假設(shè)主機(jī)A為客戶端,主機(jī)B為服務(wù)器端。
采用三次握手是為了防止失效的連接請求報(bào)文段突然又傳送到主機(jī)B,因而產(chǎn)生錯(cuò)誤。
失效的連接請求報(bào)文段是指:主機(jī)A發(fā)出的連接請求沒有收到主機(jī)B的確認(rèn),于是經(jīng)過一段時(shí)間后,主機(jī)A又重新向主機(jī)B發(fā)送連接請求,且建立成功,順序完成數(shù)據(jù)傳輸??紤]這樣一種特殊情況,主機(jī)A第一次發(fā)送的連接請求并沒有丟失,而是因?yàn)榫W(wǎng)絡(luò)節(jié)點(diǎn)導(dǎo)致延遲達(dá)到主機(jī)B,主機(jī)B以為是主機(jī)A又發(fā)起的新連接,于是主機(jī)B同意連接,并向主機(jī)A發(fā)回確認(rèn),但是此時(shí)主機(jī)A根本不會(huì)理會(huì),主機(jī)B就一直在等待主機(jī)A發(fā)送數(shù)據(jù),導(dǎo)致主機(jī)B的資源浪費(fèi)。
采用兩次握手不行,原因就是上面說的失效的連接請求的特殊情況。而在三次握手中,client和server都有一個(gè)發(fā)syn和收ack的過程, 雙方都是發(fā)后能收, 表明通信則準(zhǔn)備工作OK。
為什么不是四次握手呢?大家應(yīng)該知道通信中著名的藍(lán)軍紅軍約定,這個(gè)例子說明,通信不可能100%可靠, 而上面的三次握手已經(jīng)做好了通信的準(zhǔn)備工作, 再增加握手, 并不能顯著提高可靠性, 而且也沒有必要。
2.7 四次揮手
數(shù)據(jù)傳輸完畢后,雙方都可釋放連接。最開始的時(shí)候,客戶端和服務(wù)器都是處于ESTABLISHED狀態(tài),假設(shè)客戶端主動(dòng)關(guān)閉,服務(wù)器被動(dòng)關(guān)閉。

(1)第一次揮手:客戶端發(fā)送一個(gè)FIN,用來關(guān)閉客戶端到服務(wù)器的數(shù)據(jù)傳送,也就是客戶端告訴服務(wù)器:我已經(jīng)不 會(huì)再給你發(fā)數(shù)據(jù)了(當(dāng)然,在fin包之前發(fā)送出去的數(shù)據(jù),如果沒有收到對應(yīng)的ack確認(rèn)報(bào)文,客戶端依然會(huì)重發(fā)這些數(shù)據(jù)),但是,此時(shí)客戶端還可 以接受數(shù)據(jù)。
FIN=1,其序列號(hào)為seq=u(等于前面已經(jīng)傳送過來的數(shù)據(jù)的最后一個(gè)字節(jié)的序號(hào)加1),此時(shí),客戶端進(jìn)入FIN-WAIT-1(終止等待1)狀態(tài)。 TCP規(guī)定,F(xiàn)IN報(bào)文段即使不攜帶數(shù)據(jù),也要消耗一個(gè)序號(hào)。
(2)第二次揮手:服務(wù)器收到FIN包后,發(fā)送一個(gè)ACK給對方并且?guī)献约旱男蛄刑?hào)seq,確認(rèn)序號(hào)為收到序號(hào)+1(與SYN相同,一個(gè)FIN占用一個(gè)序號(hào))。此時(shí),服務(wù)端就進(jìn)入了CLOSE-WAIT(關(guān)閉等待)狀態(tài)。TCP服務(wù)器通知高層的應(yīng)用進(jìn)程,客戶端向服務(wù)器的方向就釋放了,這時(shí)候處于半關(guān)閉狀態(tài),即客戶端已經(jīng)沒有數(shù)據(jù)要發(fā)送了,但是服務(wù)器若發(fā)送數(shù)據(jù),客戶端依然要接受。這個(gè)狀態(tài)還要持續(xù)一段時(shí)間,也就是整個(gè)CLOSE-WAIT狀態(tài)持續(xù)的時(shí)間。
此時(shí),客戶端就進(jìn)入FIN-WAIT-2(終止等待2)狀態(tài),等待服務(wù)器發(fā)送連接釋放報(bào)文(在這之前還需要接受服務(wù)器發(fā)送的最后的數(shù)據(jù))。
(3)第三次揮手:服務(wù)器發(fā)送一個(gè)FIN,用來關(guān)閉服務(wù)器到客戶端的數(shù)據(jù)傳送,也就是告訴客戶端,我的數(shù)據(jù)也發(fā)送完了,不會(huì)再給你發(fā)數(shù)據(jù)了。由于在半關(guān)閉狀態(tài),服務(wù)器很可能又發(fā)送了一些數(shù)據(jù),假定此時(shí)的序列號(hào)為seq=w,此時(shí),服務(wù)器就進(jìn)入了LAST-ACK(最后確認(rèn))狀態(tài),等待客戶端的確認(rèn)。
(4)第四次揮手:主動(dòng)關(guān)閉方收到FIN后,發(fā)送一個(gè)ACK給被動(dòng)關(guān)閉方,確認(rèn)序號(hào)為收到序號(hào)+1,此時(shí),客戶端就進(jìn)入了TIME-WAIT(時(shí)間等待)狀態(tài)。注意此時(shí)TCP連接還沒有釋放,必須經(jīng)過2?MSL(最長報(bào)文段壽命)的時(shí)間后,當(dāng)客戶端撤銷相應(yīng)的TCB后,才進(jìn)入CLOSED狀態(tài)。
服務(wù)器只要收到了客戶端發(fā)出的確認(rèn),立即進(jìn)入CLOSED狀態(tài)。同樣,撤銷TCB后,就結(jié)束了這次的TCP連接??梢钥吹?,服務(wù)器結(jié)束TCP連接的時(shí)間要比客戶端早一些。至此,完成四次揮手。
2.8 為什么客戶端最后還要等待2MSL?
MSL(Maximum Segment Lifetime),TCP允許不同的實(shí)現(xiàn)可以設(shè)置不同的MSL值。
(1)第一,保證客戶端發(fā)送的最后一個(gè)ACK報(bào)文能夠到達(dá)服務(wù)器,因?yàn)檫@個(gè)ACK報(bào)文可能丟失,站在服務(wù)器的角度看來,我已經(jīng)發(fā)送了FIN+ACK報(bào)文請求斷開了,客戶端還沒有給我回應(yīng),應(yīng)該是我發(fā)送的請求斷開報(bào)文它沒有收到,于是服務(wù)器又會(huì)重新發(fā)送一次,而客戶端就能在這個(gè)2MSL時(shí)間段內(nèi)收到這個(gè)重傳的報(bào)文,接著給出回應(yīng)報(bào)文,并且會(huì)重啟2MSL計(jì)時(shí)器。
(2)第二,防止類似與“三次握手”中提到了的“已經(jīng)失效的連接請求報(bào)文段”出現(xiàn)在本連接中。客戶端發(fā)送完最后一個(gè)確認(rèn)報(bào)文后,在這個(gè)2MSL時(shí)間中,就可以使本連接持續(xù)的時(shí)間內(nèi)所產(chǎn)生的所有報(bào)文段都從網(wǎng)絡(luò)中消失。這樣新的連接中不會(huì)出現(xiàn)舊連接的請求報(bào)文。
2.9 為什么建立連接是三次握手,關(guān)閉連接確是四次揮手呢?
建立連接的時(shí)候,服務(wù)器在LISTEN狀態(tài)下,收到建立連接請求的SYN報(bào)文后,把ACK和SYN放在一個(gè)報(bào)文里發(fā)送給客戶端。
而關(guān)閉連接時(shí),服務(wù)器收到對方的FIN報(bào)文時(shí),僅僅表示對方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),而自己也未必全部數(shù)據(jù)都發(fā)送給對方了,所以己方可以立即關(guān)閉,也可以發(fā)送一些數(shù)據(jù)給對方后,再發(fā)送FIN報(bào)文給對方來表示同意現(xiàn)在關(guān)閉連接,因此,己方ACK和FIN一般都會(huì)分開發(fā)送,從而導(dǎo)致多了一次。
2.10 TCP粘包和拆包產(chǎn)生的原因
(1)應(yīng)用程序?qū)懭霐?shù)據(jù)的字節(jié)大小大于套接字發(fā)送緩沖區(qū)的大小
(2)進(jìn)行MSS大小的TCP分段。MSS是最大報(bào)文段長度的縮寫。MSS是TCP報(bào)文段中的數(shù)據(jù)字段的最大長度。數(shù)據(jù)字段加上TCP首部才等于整個(gè)的TCP報(bào)文段。所以MSS并不是TCP報(bào)文段的最大長度,而是:MSS=TCP報(bào)文段長度-TCP首部長度
(3)以太網(wǎng)的payload大于MTU進(jìn)行IP分片。MTU指:一種通信協(xié)議的某一層上面所能通過的最大數(shù)據(jù)包大小。如果IP層有一個(gè)數(shù)據(jù)包要傳,而且數(shù)據(jù)的長度比鏈路層的MTU大,那么IP層就會(huì)進(jìn)行分片,把數(shù)據(jù)包分成托干片,讓每一片都不超過MTU。注意,IP分片可以發(fā)生在原始發(fā)送端主機(jī)上,也可以發(fā)生在中間路由器上。
2.11 TCP粘包和拆包的解決策略
(1)消息定長。例如100字節(jié)。
(2)在包尾部增加回車或者空格符等特殊字符進(jìn)行分割,典型的如FTP協(xié)議
(3)將消息分為消息頭和消息尾。
(4)其它復(fù)雜的協(xié)議,如RTMP協(xié)議等。
2.12 TCP的四種定時(shí)器
TCP中有四種計(jì)時(shí)器(Timer),分別為:
(1)重傳計(jì)時(shí)器:Retransmission Timer
(2)堅(jiān)持計(jì)時(shí)器:Persistent Timer
(3)?;钣?jì)時(shí)器:Keeplive Timer
(4)時(shí)間等待計(jì)時(shí)器:Timer_Wait Timer
1、重傳計(jì)時(shí)器
大家都知道TCP是保證數(shù)據(jù)可靠傳輸?shù)摹T趺幢WC呢?帶確認(rèn)的重傳機(jī)制。在滑動(dòng)窗口協(xié)議中,接受窗口會(huì)在連續(xù)收到的包序列中的最后一個(gè)包向接收端發(fā)送一個(gè)ACK,當(dāng)網(wǎng)絡(luò)擁堵的時(shí)候,發(fā)送端的數(shù)據(jù)包和接收端的ACK包都有可能丟失。
TCP為了保證數(shù)據(jù)可靠傳輸,就規(guī)定在重傳的“時(shí)間片”到了以后,如果還沒有收到對方的ACK,就重發(fā)此包,以避免陷入無限等待中。
當(dāng)TCP發(fā)送報(bào)文段時(shí),就創(chuàng)建該特定報(bào)文的重傳計(jì)時(shí)器??赡馨l(fā)生兩種情況:
1)若在計(jì)時(shí)器截止時(shí)間到之前收到了對此特定報(bào)文段的確認(rèn),則撤銷此計(jì)時(shí)器。
2)若在收到了對此特定報(bào)文段的確認(rèn)之前計(jì)時(shí)器截止時(shí)間到,則重傳此報(bào)文段,并將計(jì)時(shí)器復(fù)位。
2、堅(jiān)持計(jì)時(shí)器
專門對付零窗口通知而設(shè)立的
先來考慮一下情景:發(fā)送端向接收端發(fā)送數(shù)據(jù)包知道接受窗口填滿了,然后接受窗口告訴發(fā)送方接受窗口填滿了停止發(fā)送數(shù)據(jù)。此時(shí)的狀態(tài)稱為“零窗口”狀態(tài),發(fā)送端和接收端窗口大小均為0.直到接受TCP發(fā)送確認(rèn)并宣布一個(gè)非零的窗口大小。但這個(gè)確認(rèn)會(huì)丟失。
我們知道TCP中,對確認(rèn)是不需要發(fā)送確認(rèn)的。若確認(rèn)丟失了,接受TCP并不知道,而是會(huì)認(rèn)為他已經(jīng)完成了任務(wù),并等待著發(fā)送TCP接著會(huì)發(fā)送更多的報(bào)文段。
但發(fā)送TCP由于沒有收到確認(rèn),就等待對方發(fā)送確認(rèn)來通知窗口大小。雙方的TCP都在永遠(yuǎn)的等待著對方。
要打開這種死鎖,TCP為每一個(gè)鏈接使用一個(gè)持久計(jì)時(shí)器。當(dāng)發(fā)送TCP收到窗口大小為0的確認(rèn)時(shí),就堅(jiān)持啟動(dòng)計(jì)時(shí)器。當(dāng)堅(jiān)持計(jì)時(shí)器期限到時(shí),發(fā)送TCP就發(fā)送一個(gè)特殊的報(bào)文段,叫做探測報(bào)文。
這個(gè)報(bào)文段只有一個(gè)字節(jié)的數(shù)據(jù)。他有一個(gè)序號(hào),但他的序號(hào)永遠(yuǎn)不需要確認(rèn);甚至在計(jì)算機(jī)對其他部分的數(shù)據(jù)的確認(rèn)時(shí)該序號(hào)也被忽略。探測報(bào)文段提醒接受TCP:確認(rèn)已丟失,必須重傳。
堅(jiān)持計(jì)時(shí)器的值設(shè)置為重傳時(shí)間的數(shù)值。但是,若沒有收到從接收端來的響應(yīng),則需發(fā)送另一個(gè)探測報(bào)文段,并將堅(jiān)持計(jì)時(shí)器的值加倍和復(fù)位。
發(fā)送端繼續(xù)發(fā)送探測報(bào)文段,將堅(jiān)持計(jì)時(shí)器設(shè)定的值加倍和復(fù)位,直到這個(gè)值增大到門限值(通常是60秒)為止。在這以后,發(fā)送端每個(gè)60秒就發(fā)送一個(gè)探測報(bào)文,直到窗口重新打開。
3、?;钣?jì)時(shí)器
?;钣?jì)時(shí)器使用在某些實(shí)現(xiàn)中,用來防止在兩個(gè)TCP之間的連接出現(xiàn)長時(shí)間的空閑。假定客戶打開了到服務(wù)器的連接,傳送了一些數(shù)據(jù),然后就保持靜默了。也許這個(gè)客戶出故障了。在這種情況下,這個(gè)連接將永遠(yuǎn)的處理打開狀態(tài)。
要解決這種問題,在大多數(shù)的實(shí)現(xiàn)中都是使服務(wù)器設(shè)置?;钣?jì)時(shí)器。每當(dāng)服務(wù)器收到客戶的信息,就將計(jì)時(shí)器復(fù)位。通常設(shè)置為兩小時(shí)。
若服務(wù)器過了兩小時(shí)還沒有收到客戶的信息,他就發(fā)送探測報(bào)文段。若發(fā)送了10個(gè)探測報(bào)文段(每一個(gè)像個(gè)75秒)還沒有響應(yīng),就假定客戶除了故障,因而就終止了該連接。
這種連接的斷開當(dāng)然不會(huì)使用四次握手,而是直接硬性的中斷和客戶端的TCP連接。
4、時(shí)間等待計(jì)時(shí)器
時(shí)間等待計(jì)時(shí)器是在四次握手的時(shí)候使用的。四次握手的簡單過程是這樣的:假設(shè)客戶端準(zhǔn)備中斷連接,首先向服務(wù)器端發(fā)送一個(gè)FIN的請求關(guān)閉包(FIN=final),然后由established過渡到FIN-WAIT1狀態(tài)。
服務(wù)器收到FIN包以后會(huì)發(fā)送一個(gè)ACK,然后自己有established進(jìn)入CLOSE-WAIT.此時(shí)通信進(jìn)入半雙工狀態(tài),即留給服務(wù)器一個(gè)機(jī)會(huì)將剩余數(shù)據(jù)傳遞給客戶端,傳遞完后服務(wù)器發(fā)送一個(gè)FIN+ACK的包,表示我已經(jīng)發(fā)送完數(shù)據(jù)可以斷開連接了,就這便進(jìn)入LAST_ACK階段。
客戶端收到以后,發(fā)送一個(gè)ACK表示收到并同意請求,接著由FIN-WAIT2進(jìn)入TIME-WAIT階段。服務(wù)器收到ACK,結(jié)束連接。
此時(shí)(即客戶端發(fā)送完ACK包之后),客戶端還要等待2MSL(MSL=maxinum segment lifetime最長報(bào)文生存時(shí)間,2MSL就是兩倍的MSL)才能真正的關(guān)閉連接。
三、UDP詳解
2.1 UDP是什么
UDP(User Datagram Protocol),中文意思是用戶數(shù)據(jù)報(bào)協(xié)議,方式類似于發(fā)短信息,是一種物美價(jià)廉的通訊方式,使用該種方式無需建立專用的虛擬連接,由于無需建立專用的連接,所以對于服務(wù)器的壓力要比TCP小很多,所以也是一種常見的網(wǎng)絡(luò)編程方式。但是使用該種方式最大的不足是傳輸不可靠,當(dāng)然也不是說經(jīng)常丟失,就像大家發(fā)短信息一樣,理論上存在收不到的可能,這種可能性可能是1%,反正比較小,但是由于這種可能的存在,所以平時(shí)我們都覺得重要的事情還是打個(gè)電話吧(類似TCP方式),一般的事情才發(fā)短信息(類似UDP方式)。網(wǎng)絡(luò)編程中也是這樣,必須要求可靠傳輸?shù)男畔⒁话闶褂肨CP方式實(shí)現(xiàn),一般的數(shù)據(jù)才使用UDP方式實(shí)現(xiàn)。
UDP方式的網(wǎng)絡(luò)編程也在Java語言中獲得了良好的支持,由于其在傳輸數(shù)據(jù)的過程中不需要建立專用的連接等特點(diǎn),所以在Java API中設(shè)計(jì)的實(shí)現(xiàn)結(jié)構(gòu)和TCP方式不太一樣。當(dāng)然,需要使用的類還是包含在java.net包中。
2.2 UDP主要實(shí)現(xiàn)
DatagramSocket:
DatagramSocket類實(shí)現(xiàn)“網(wǎng)絡(luò)連接”,包括客戶端網(wǎng)絡(luò)連接和服務(wù)器端網(wǎng)絡(luò)連接。雖然UDP方式的網(wǎng)絡(luò)通訊不需要建立專用的網(wǎng)絡(luò)連接,但是畢竟還是需要發(fā)送和接收數(shù)據(jù),DatagramSocket實(shí)現(xiàn)的就是發(fā)送數(shù)據(jù)時(shí)的發(fā)射器,以及接收數(shù)據(jù)時(shí)的監(jiān)聽器的角色。類比于TCP中的網(wǎng)絡(luò)連接,該類既可以用于實(shí)現(xiàn)客戶端連接,也可以用于實(shí)現(xiàn)服務(wù)器端連接。
DatagramPacket:
DatagramPacket類實(shí)現(xiàn)對于網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)封裝,也就是說,該類的對象代表網(wǎng)絡(luò)中交換的數(shù)據(jù)。在UDP方式的網(wǎng)絡(luò)編程中,無論是需要發(fā)送的數(shù)據(jù)還是需要接收的數(shù)據(jù),都必須被處理成DatagramPacket類型的對象,該對象中包含發(fā)送到的地址、發(fā)送到的端口號(hào)以及發(fā)送的內(nèi)容等。其實(shí)DatagramPacket類的作用類似于現(xiàn)實(shí)中的信件,在信件中包含信件發(fā)送到的地址以及接收人,還有發(fā)送的內(nèi)容等,郵局只需要按照地址傳遞即可。在接收數(shù)據(jù)時(shí),接收到的數(shù)據(jù)也必須被處理成DatagramPacket類型的對象,在該對象中包含發(fā)送方的地址、端口號(hào)等信息,也包含數(shù)據(jù)的內(nèi)容。和TCP方式的網(wǎng)絡(luò)傳輸相比,IO編程在UDP方式的網(wǎng)絡(luò)編程中變得不是必須的內(nèi)容,結(jié)構(gòu)也要比TCP方式的網(wǎng)絡(luò)編程簡單一些。
2.3 UDP應(yīng)用場景
(1)面向數(shù)據(jù)報(bào)方式
(2)網(wǎng)絡(luò)數(shù)據(jù)大多為短消息?
(3)擁有大量Client
(4)對數(shù)據(jù)安全性無特殊要求
(5)網(wǎng)絡(luò)負(fù)擔(dān)非常重,但對響應(yīng)速度要求高
2.4 UDP編程的服務(wù)器端一般步驟是
(1)創(chuàng)建一個(gè)socket,用函數(shù)socket();
(2)設(shè)置socket屬性,用函數(shù)setsockopt();* 可選
(3)綁定IP地址、端口等信息到socket上,用函數(shù)bind();
(4)循環(huán)接收數(shù)據(jù),用函數(shù)recvfrom();
(5)關(guān)閉網(wǎng)絡(luò)連接;
2.5UDP編程的客戶端一般步驟
(1)創(chuàng)建一個(gè)socket,用函數(shù)socket();
(2)設(shè)置socket屬性,用函數(shù)setsockopt();* 可選
(3)綁定IP地址、端口等信息到socket上,用函數(shù)bind();* 可選
(4)設(shè)置對方的IP地址和端口等屬性;
(5)發(fā)送數(shù)據(jù),用函數(shù)sendto();
(6)關(guān)閉網(wǎng)絡(luò)連接;
2.6 UDP補(bǔ)充
UDP不提供復(fù)雜的控制機(jī)制,利用IP提供面向無連接的通信服務(wù)。并且它是將應(yīng)用程序發(fā)來的數(shù)據(jù)在收到的那一刻,立刻按照原樣發(fā)送到網(wǎng)絡(luò)上的一種機(jī)制。即使是出現(xiàn)網(wǎng)絡(luò)擁堵的情況下,UDP也無法進(jìn)行流量控制等避免網(wǎng)絡(luò)擁塞的行為。此外,傳輸途中如果出現(xiàn)了丟包,UDO也不負(fù)責(zé)重發(fā)。甚至當(dāng)出現(xiàn)包的到達(dá)順序亂掉時(shí)也沒有糾正的功能。如果需要這些細(xì)節(jié)控制,那么不得不交給由采用UDO的應(yīng)用程序去處理。換句話說,UDP將部分控制轉(zhuǎn)移到應(yīng)用程序去處理,自己卻只提供作為傳輸層協(xié)議的最基本功能。UDP有點(diǎn)類似于用戶說什么聽什么的機(jī)制,但是需要用戶充分考慮好上層協(xié)議類型并制作相應(yīng)的應(yīng)用程序。
四、TCP和UDP的區(qū)別
4.1 TCP與UDP基本區(qū)別
(1)TCP面向連接(如打電話要先撥號(hào)建立連接);UDP是無連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接(2)TCP提供可靠的服務(wù)。也就是說,通過TCP連接傳送的數(shù)據(jù),無差錯(cuò),不丟失,不重復(fù),且按序到達(dá);UDP盡最大努力交付,即不保 ? 證可靠交付(3)TCP面向字節(jié)流,實(shí)際上是TCP把數(shù)據(jù)看成一連串無結(jié)構(gòu)的字節(jié)流;UDP是面向報(bào)文的UDP沒有擁塞控制,因此網(wǎng)絡(luò)出現(xiàn)擁塞不會(huì)使源主機(jī)的發(fā)送速率降低(對實(shí)時(shí)應(yīng)用很有用,如IP電話,實(shí)時(shí)視頻會(huì)議等)
(4)每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對一,一對多,多對一和多對多的交互通信(5)TCP首部開銷20字節(jié);UDP的首部開銷小,只有8個(gè)字節(jié)(6)TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道
4.2具體編程時(shí)的區(qū)別
(1)socket()的參數(shù)不同?
(2)UDP Server不需要調(diào)用listen和accept?
(3)UDP收發(fā)數(shù)據(jù)用sendto/recvfrom函數(shù)?
(4)TCP:地址信息在connect/accept時(shí)確定?
(5)UDP:在sendto/recvfrom函數(shù)中每次均 需指定地址信息?
(6)UDP:shutdown函數(shù)無效