目的:重新梳理TCP,全局理解協(xié)議中的細節(jié),知道是怎樣實現(xiàn)的,理解為什么要這樣做,了解可能會帶來什么問題。
PS:圖片有空了慢慢貼。
簡要介紹:
TCP協(xié)議是基于網(wǎng)絡(luò)層IP協(xié)議的傳輸層協(xié)議,提供一種面向連接的,可靠的字節(jié)流服務(wù)(byte stream service )。在TCP連接中, 僅支持兩方進行彼此通信。
TCP的可靠性由以下方式 來提供:
1) 恰當?shù)臄?shù)據(jù)分段。即將字節(jié)流根據(jù)MSS來封包發(fā)送。
2) 確認機制、重傳機制。
3) 首部的檢驗和。
4) 網(wǎng)絡(luò)層的IP數(shù)據(jù)報可能會失序,因此TCP需要將數(shù)據(jù)進行重新排序。
5) 數(shù)據(jù)報可能會重復(fù),必須恰當?shù)膩G棄重復(fù)的數(shù)據(jù)報。
6) TCP提供流量控制,可根據(jù)另一端的緩沖區(qū)情況發(fā)送恰當?shù)臄?shù)據(jù)(滑動窗口協(xié)議)。
7) TCP協(xié)議對字節(jié)流不作解釋。由應(yīng)用層對數(shù)據(jù)進行語義上的解釋。
隨便抓個包:
IP數(shù)據(jù)頭
TCP數(shù)據(jù)頭

頭部中比較重要的數(shù)據(jù)結(jié)構(gòu)
源端口,目的端口,序號,確認序號。 標志位,窗口大小。
URG:緊急指針,一般用不上,忽略。
ACK:經(jīng)常用,接收端發(fā)給源端,確認前一個包已收到。
PSH:個人沒怎么碰到過。
RST:可以理解為重置連接,普通情況下當目標端口未開放會發(fā)送此RST回來,此外,連接中間的防火墻等網(wǎng)絡(luò)設(shè)備也會發(fā)。

SYN:發(fā)起連接的標志,SYN Flood是基于的一種DOS攻擊手法。
FIN:shutdown 時發(fā)送,告訴對方,我這邊完成了,要送掉連接了。
1、 TCP連接的建議,三步握手。
1) 源端發(fā)送SYN到服務(wù)器,表示喜娃懷與服務(wù)器的某個端口建立TCP連接,在TCP首部帶上初始的序號(client ISN)。此報文中設(shè)置SYN=1;
2) 服務(wù)器返回SYN包,帶上服務(wù)器的初始序號(server ISN),并且ACK=client ISN+1設(shè)置SYN=1,ACK=1;
3) 源端返回服務(wù)器ACK包, ack = server ISN+1;

PS:這邊的Seq居然從0開始,之前都沒注意過~~
關(guān)于ISN的選擇,根據(jù)文獻內(nèi)容,應(yīng)當隨時間變化,避免網(wǎng)絡(luò)中被延遲的分組被重新傳遞后導(dǎo)致的錯誤解釋。
2、 TCP連接的終止,四步握手。
1) 首先關(guān)閉的一方(A)發(fā)送FIN包。FIN在應(yīng)用層、開發(fā)者面前就是socket.read 將返回EOF。
2) 接受端(B)返回FIN的ACK包。
3) B關(guān)閉連接,發(fā)送FIN。
4) A發(fā)送ACK。
關(guān)閉階段存在另外兩衍生的流程。1) 2與3 兩步可以合并, 當B端無數(shù)據(jù)發(fā)送時,無需發(fā)放兩個包,可以在一個包里面同時設(shè)置FIN+ACK,也就是上面的截圖。2)當僅一端調(diào)用shutdown,另一端還存在數(shù)據(jù)發(fā)送時,存在半關(guān)閉連接的情況。即第2步結(jié)束后,B端繼續(xù)發(fā)送數(shù)據(jù),A端對這些數(shù)據(jù)仍然發(fā)送ACK,一直到B端發(fā)送FIN。
以下是一個簡單的client + server 測試代碼,通過簡單的Sleep可以看出, 當收到FIN包時,緩沖區(qū)的數(shù)據(jù)仍然存在,僅在后面多了一個EOF而已。
1 #!/usr/bin/env python
2 import socket
3 import time
4
5 host="192.168.5.106"
6 port=10000
7 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
8 s.bind((host,port))
9 s.listen(5)
10 sock,addr=s.accept()
11 print "got connection form ",sock.getpeername()
12 while 1:
13 data=sock.recv(1)
14 time.sleep(0.1)
15 if not data:
16 print("~~~~~")
17 break
18 else:
19 print data
20
1 #!/usr/bin/env python
2 import socket
3 host="192.168.5.106"
4 port=10000
5 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
6 s.connect((host,port))
7 s.send("hello from client")
8 s.close()