一随橘、TCP/IP協(xié)議
TCP/IP網(wǎng)絡(luò)協(xié)議分為:應(yīng)用層(Telnet喂分、FTP、e-mail...)机蔗、傳輸層(TCP蒲祈、UDP)、網(wǎng)絡(luò)層(IP萝嘁、ICMP...)梆掸、鏈路層(設(shè)備驅(qū)動程序及接口卡) 四層
傳輸層及其以下的機制由內(nèi)核提供,應(yīng)用層由用戶進程提供牙言,應(yīng)用程序?qū)νㄓ崝?shù)據(jù)的含義進行解釋酸钦,而傳輸層及其以下處理通訊的細節(jié),將數(shù)據(jù)從一臺計算機通過一定的路徑發(fā)送到另一臺計算機咱枉。應(yīng)用層數(shù)據(jù)通過協(xié)議棧發(fā)到網(wǎng)絡(luò)上時卑硫,每層協(xié)議都要加上一個數(shù)據(jù)首部(header),稱為封裝(Encapsulation)
不同的協(xié)議層對數(shù)據(jù)包有不同的稱謂蚕断,在傳輸層叫做段(segment)欢伏,在網(wǎng)絡(luò)層叫做數(shù)據(jù)報 (datagram),在鏈路層叫做幀(frame)亿乳。數(shù)據(jù)封裝成幀后發(fā)到傳輸介質(zhì)上硝拧,到達目的主機后每層協(xié)議再剝掉相應(yīng)的首部,最后將應(yīng)用層數(shù)據(jù)交給應(yīng)用程序處理
其實在鏈路層之下還有物理層葛假,指的是電信號的傳遞方式障陶,比如現(xiàn)在以太網(wǎng)通用的網(wǎng)線(雙絞線)、早期以太網(wǎng)采用的的同軸電纜(現(xiàn)在主要用于有線電視)聊训、光纖等都屬于物理層的概念抱究。物理層的能力決定了最大傳輸速率、傳輸距離带斑、抗干擾性等媳维。集線器(Hub)是工作在物理層的網(wǎng)絡(luò)設(shè)備酿雪,用于雙絞線的連接和信號中繼(將已衰減的信號再次放大使之傳得更遠)遏暴。
鏈路層有以太網(wǎng)侄刽、令牌環(huán)網(wǎng)等標(biāo)準(zhǔn),鏈路層負責(zé)網(wǎng)卡設(shè)備的驅(qū)動朋凉、幀同步(就是說從網(wǎng)線上檢測到什么信號算作新幀的開始)州丹、沖突檢測(如果檢測到?jīng)_突就自動重發(fā))、數(shù)據(jù)差錯校驗等工作杂彭。交換機是工作在鏈路層的網(wǎng)絡(luò)設(shè)備墓毒,可以在不同的鏈路層網(wǎng)絡(luò)之間轉(zhuǎn)發(fā)數(shù)據(jù)幀(比如十兆以太網(wǎng)和百兆以太網(wǎng)之間、以太網(wǎng)和令牌環(huán)網(wǎng)之間)亲怠,由于不同鏈路層的幀格式不同所计,交換機要將進來的數(shù)據(jù)包拆掉鏈路層首部重新封裝之后再轉(zhuǎn)發(fā)。
網(wǎng)絡(luò)層的IP協(xié)議是構(gòu)成Internet的基礎(chǔ)团秽。Internet上的主機通過IP地址來標(biāo)識主胧,Internet上有大量路由器負責(zé)根據(jù)IP地址選擇合適的路徑轉(zhuǎn)發(fā)數(shù)據(jù)包,數(shù)據(jù)包從Internet上的源主機到目的主機往往要經(jīng)過十多個路由器习勤。路由器是工作在第三層的網(wǎng)絡(luò)設(shè)備踪栋,同時兼有交換機的功能,可以在不同的鏈路層接口之間轉(zhuǎn)發(fā)數(shù)據(jù)包图毕,因此路由器需要將進來的數(shù)據(jù)包拆掉網(wǎng)絡(luò)層和鏈路層兩層首部并重新封裝夷都。IP協(xié)議不保證傳輸?shù)目煽啃裕瑪?shù)據(jù)包在傳輸過程中可能丟失予颤,可靠性可以在上層協(xié)議或應(yīng)用程序中提供支持囤官。
網(wǎng)絡(luò)層負責(zé)點到點(point-to-point)的傳輸(這里的“點”指主機或路由器),而傳輸層負責(zé)端到端(end-to-end)的傳輸(這里的“端”指源主機和目的主機)蛤虐。傳輸層可選擇TCP或UDP協(xié) 議党饮。TCP是一種面向連接的、可靠的協(xié)議笆焰,有點像打電話劫谅,雙方拿起電話互通身份之后就建立了連接,然后說話就行了嚷掠,這邊說的話那邊保證聽得到捏检,并且是按說話的順序聽到的,說完話掛機斷開連接不皆。也就是說TCP傳輸?shù)碾p方需要首先建立連接贯城,之后由TCP協(xié)議保證數(shù)據(jù)收發(fā)的可靠性,丟失的數(shù)據(jù)包自動重發(fā)霹娄,上層應(yīng)用程序收到的總是可靠的數(shù)據(jù)流能犯,通訊之后關(guān)閉連接鲫骗。UDP協(xié)議不面向連接,也不保證可靠性踩晶,有點像寄信执泰,寫好信放到郵筒里,既不能保證信件在郵遞過程中不會丟失渡蜻,也不能保證信件是按順序寄到目的地的术吝。使用UDP協(xié)議的應(yīng)用程序需要自己完成丟包重發(fā)、消息排序等工作茸苇。
以太網(wǎng)驅(qū)動程序首先根據(jù)以太網(wǎng)首部中的“上層協(xié)議”字段確定該數(shù)據(jù)幀的有效載荷(payload排苍,指除去協(xié)議首部之外實際傳輸?shù)臄?shù)據(jù))是IP、ARP還是RARP協(xié)議的數(shù)據(jù)報学密,然后交給相應(yīng)的協(xié)議處理淘衙。假如是IP數(shù)據(jù)報,IP協(xié)議再根據(jù)IP首部中的“上層協(xié)議”字段確定該數(shù)據(jù)報的有效載荷是TCP腻暮、UDP彤守、ICMP還是IGMP,然后交給相應(yīng)的協(xié)議處理西壮。假如是TCP段 或UDP段遗增,TCP或UDP協(xié)議再根據(jù)TCP首部或UDP首部的“端口號”字段確定應(yīng)該將應(yīng)用層數(shù)據(jù)交給哪個用戶進程。IP地址是標(biāo)識網(wǎng)絡(luò)中不同主機的地址款青,而端口號就是同一臺主機上標(biāo)識不同進程的地址做修,IP地址和端口號合起來標(biāo)識網(wǎng)絡(luò)中唯一的進程。
二抡草、TCP的三次握手與四次揮手
所謂三次握手(Three-Way Handshake)即建立TCP連接饰及,就是指建立一個TCP連接時,需要客戶端和服務(wù)端總共發(fā)送3個包以確認(rèn)連接的建立康震。在socket編程中燎含,這一過程由客戶端執(zhí)行connect來觸發(fā)
(1)第一次握手:Client將標(biāo)志位SYN置為1,隨機產(chǎn)生一個值seq=J腿短,并將該數(shù)據(jù)包發(fā)送給Server屏箍,Client進入SYN_SENT狀態(tài),等待Server確認(rèn)橘忱。
(2)第二次握手:Server收到數(shù)據(jù)包后由標(biāo)志位SYN=1知道Client請求建立連接赴魁,Server將標(biāo)志位SYN和ACK都置為1,ack=J+1钝诚,隨機產(chǎn)生一個值seq=K颖御,并將該數(shù)據(jù)包發(fā)送給Client以確認(rèn)連接請求,Server進入SYN_RCVD狀態(tài)凝颇。
(3)第三次握手:Client收到確認(rèn)后潘拱,檢查ack是否為J+1疹鳄,ACK是否為1,如果正確則將標(biāo)志位ACK置為1芦岂,ack=K+1瘪弓,并將該數(shù)據(jù)包發(fā)送給Server,Server檢查ack是否為K+1盔腔,ACK是否為1杠茬,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態(tài)弛随,完成三次握手,隨后Client與Server之間可以開始傳輸數(shù)據(jù)了宁赤。
SYN攻擊:
在三次握手過程中舀透,Server發(fā)送SYN-ACK之后,收到Client的ACK之前的TCP連接稱為半連接(half-open connect)决左,此時Server處于SYN_RCVD狀態(tài)愕够,當(dāng)收到ACK后,Server轉(zhuǎn)入ESTABLISHED狀態(tài)佛猛。SYN攻擊就是Client在短時間內(nèi)偽造大量不存在的IP地址惑芭,并向Server不斷地發(fā)送SYN包,Server回復(fù)確認(rèn)包继找,并等待Client的確認(rèn)遂跟,由于源地址是不存在的,因此婴渡,Server需要不斷重發(fā)直至超時幻锁,這些偽造的SYN包將產(chǎn)時間占用未連接隊列,導(dǎo)致正常的SYN請求因為隊列滿而被丟棄边臼,從而引起網(wǎng)絡(luò)堵塞甚至系統(tǒng)癱瘓哄尔。SYN攻擊時一種典型的DDOS攻擊,檢測SYN攻擊的方式非常簡單柠并,即當(dāng)Server上有大量半連接狀態(tài)且源IP地址是隨機的岭接,則可以斷定遭到SYN攻擊了
所謂四次揮手(Four-Way Wavehand)即終止TCP連接,就是指斷開一個TCP連接時臼予,需要客戶端和服務(wù)端總共發(fā)送4個包以確認(rèn)連接的斷開鸣戴。在socket編程中,這一過程由客戶端或服務(wù)端任一方執(zhí)行close來觸發(fā)
由于TCP連接時全雙工的瘟栖,因此葵擎,每個方向都必須要單獨進行關(guān)閉,這一原則是當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后半哟,發(fā)送一個FIN來終止這一方向的連接酬滤,收到一個FIN只是意味著這一方向上沒有數(shù)據(jù)流動了签餐,即不會再收到數(shù)據(jù)了,但是在這個TCP連接上仍然能夠發(fā)送數(shù)據(jù)盯串,直到這一方向也發(fā)送了FIN氯檐。首先進行關(guān)閉的一方將執(zhí)行主動關(guān)閉,而另一方則執(zhí)行被動關(guān)閉
(1)第一次揮手:Client發(fā)送一個FIN体捏,用來關(guān)閉Client到Server的數(shù)據(jù)傳送冠摄,Client進入FIN_WAIT_1狀態(tài)。
(2)第二次揮手:Server收到FIN后几缭,發(fā)送一個ACK給Client河泳,確認(rèn)序號為收到序號+1(與SYN相同,一個FIN占用一個序號)年栓,Server進入CLOSE_WAIT狀態(tài)拆挥。
(3)第三次揮手:Server發(fā)送一個FIN,用來關(guān)閉Server到Client的數(shù)據(jù)傳送某抓,Server進入LAST_ACK狀態(tài)邑雅。
(4)第四次揮手:Client收到FIN后乌叶,Client進入TIME_WAIT狀態(tài)塔鳍,接著發(fā)送一個ACK給Server愕乎,確認(rèn)序號為收到序號+1,Server進入CLOSED狀態(tài)备禀,完成四次揮手洲拇。
三、TCP的客戶端和服務(wù)端實現(xiàn)解析
(1)connect()函數(shù)
對于客戶端的 connect() 函數(shù)痹届,該函數(shù)的功能為客戶端主動連接服務(wù)器呻待,建立連接是通過三次握手,而這個連接的過程是由內(nèi)核完成队腐,不是這個函數(shù)完成的蚕捉,這個函數(shù)的作用僅僅是通知 Linux 內(nèi)核,讓 Linux 內(nèi)核自動完成 TCP 三次握手連接柴淘,最后把連接的結(jié)果返回給這個函數(shù)的返回值(成功連接為0迫淹, 失敗為-1)。
通常的情況为严,客戶端的 connect() 函數(shù)默認(rèn)會一直阻塞敛熬,直到三次握手成功或超時失敗才返回(正常的情況,這個過程很快完成)第股。
(2)listen()函數(shù)
int listen(int sockfd, int backlog);
對于服務(wù)器应民,它是被動連接的。listen() 函數(shù)的主要作用就是將套接字( sockfd )變成被動的連接監(jiān)聽套接字(被動等待客戶端的連接),至于參數(shù) backlog 的作用是設(shè)置內(nèi)核中連接隊列的長度
這里需要注意的是诲锹,listen()函數(shù)不會阻塞繁仁,它主要做的事情為,將該套接字和套接字對應(yīng)的連接隊列長度告訴 Linux 內(nèi)核归园,然后黄虱,listen()函數(shù)就結(jié)束。
這樣的話庸诱,當(dāng)有一個客戶端主動連接(connect())捻浦,Linux 內(nèi)核就自動完成TCP 3次握手,將建立好的鏈接自動存儲到隊列中桥爽,如此重復(fù)朱灿。
所以,只要 TCP 服務(wù)器調(diào)用了 listen()聚谁,客戶端就可以通過 connect() 和服務(wù)器建立連接母剥,而這個連接的過程是由內(nèi)核完成。
為了更好的理解 backlog 參數(shù)形导,我們必須認(rèn)識到內(nèi)核為任何一個給定的監(jiān)聽套接口維護兩個隊列:
1、未完成連接隊列(incomplete connection queue)习霹,每個這樣的 SYN 分節(jié)對應(yīng)其中一項:已由某個客戶發(fā)出并到達服務(wù)器朵耕,而服務(wù)器正在等待完成相應(yīng)的 TCP三次握手過程。這些套接口處于 SYN_RCVD 狀態(tài)淋叶。
2阎曹、已完成連接隊列(completed connection queue),每個已完成 TCP 三次握手過程的客戶對應(yīng)其中一項煞檩。這些套接口處于 ESTABLISHED 狀態(tài)处嫌。
當(dāng)來自客戶的 SYN 到達時,TCP 在未完成連接隊列中創(chuàng)建一個新項斟湃,然后響應(yīng)以三次握手的第二個分節(jié):服務(wù)器的 SYN 響應(yīng)熏迹,其中稍帶對客戶 SYN 的 ACK(即SYN+ACK),這一項一直保留在未完成連接隊列中凝赛,直到三次握手的第三個分節(jié)(客戶對服務(wù)器 SYN 的 ACK )到達或者該項超時為止(曾經(jīng)源自Berkeley的實現(xiàn)為這些未完成連接的項設(shè)置的超時值為75秒)注暗。
如果三次握手正常完成,該項就從未完成連接隊列移到已完成連接隊列的隊尾墓猎。
backlog 參數(shù)歷史上被定義為上面兩個隊列的大小之和捆昏,大多數(shù)實現(xiàn)默認(rèn)值為 5,當(dāng)服務(wù)器把這個完成連接隊列的某個連接取走后毙沾,這個隊列的位置又空出一個骗卜,這樣來回實現(xiàn)動態(tài)平衡,但在高并發(fā) web 服務(wù)器中此值顯然不夠。
(3)accept()函數(shù)
accept()函數(shù)功能是寇仓,從處于 established 狀態(tài)的連接隊列頭部取出一個已經(jīng)完成的連接举户,如果這個隊列沒有已經(jīng)完成的連接,accept()函數(shù)就會阻塞焚刺,直到取出隊列中已完成的用戶連接為止
四敛摘、UDP的實現(xiàn)
與 TCP 不同, UDP 并不提供對 IP 協(xié)議的可靠機制乳愉、流控制以及錯誤恢復(fù) 功能等兄淫。由于 UDP 比較簡單, UDP 頭包含很少的字節(jié)蔓姚,比TCP負載消耗少捕虽。 UDP適用于不需要TCP可靠機制的情形,比如坡脐,當(dāng)高層協(xié)議或應(yīng)用程序提供錯 誤和流控制功能的時候泄私。
UDP套接口是無連接的、不可靠的數(shù)據(jù)報協(xié)議备闲;既然他不可靠為什么還要用呢晌端?其一:當(dāng)應(yīng)用程序使用廣播或多播時只能使用UDP協(xié)議;其二:由于他是無連接的恬砂,所以速度快咧纠。因為UDP套接口是無連接的,如果一方的數(shù)據(jù)報丟失泻骤,那另一方將無限等待漆羔,解決辦法是設(shè)置一個超時。
建立UDP套接口時socket函數(shù)的第二個參數(shù)應(yīng)該是SOCK_DGRAM狱掂,說明是建立一個UDP套接口演痒;
由于UDP是無連接的,所以服務(wù)器端并不需要listen或accept函數(shù)趋惨。
使用UDP套接字編程可以實現(xiàn)基于TCP/IP協(xié)議的面向無連接的通信
參考文檔
- 1鸟顺、https://wenku.baidu.com/view/9fbd4013cc7931b765ce15c3.html
- 2、http://www.cnblogs.com/wuyuan2011woaini/p/4876588.html
- 3希柿、http://blog.csdn.net/zhenganzhong_csdn/article/details/51548976
- 4诊沪、http://blog.csdn.net/yueguanghaidao/article/details/7055985
- 5、https://wenku.baidu.com/view/0463a711866fb84ae45c8d19.html
- 6曾撤、http://web.jobbole.com/85541/