tcp是網絡七層模型當中傳輸層的協議,由IETF的RFC 793定義,是面向鏈接的、可靠的、基於字節流的通訊協議。而傳輸層位於七層模型的中間,下面是網絡層,上面的話有應用層,承上啓下,地位仍是很重要的。在傳輸層中還有一種協議udp(無鏈接、不保證可靠性)。相比來講tcp有如下特色html
- 傳輸可靠,數據丟失有重傳機制
- 數據分段打包傳輸,對每一個數據編號,控制順序
- 流量控制,避免擁塞,由於TCP鏈接雙方有固定大小緩衝空間。TCP的接收端只容許另外一端發送接收端緩衝區所能接納的數據。
針對上面圖中的結構劃分,下面進行下解釋node
source port 和 destination port 都是16位,計算機端口識別訪問那個服務, 其中source port 是隨機的,而destination port決定接受方由那個程序來接受而且由於是16位,因此說程序的最大端口號65535編程
sequence Number 是發送數據包中的第一個字節的序列號,假設當前的序列號爲 s,發送數據長度爲 l,則下次發送數據時的序列號爲 s + l。在創建鏈接時一般由計算機生成一個隨機數做爲序列號的初始值api
Acknowledgment Number 它等於下一次應該接收到的數據的序列號。能夠認爲這個位置之前全部的數據都已被正常接收。
header length TCP 首部的長度,單位爲 4 字節。若是沒有可選字段,那麼這裏的值就是 5。表示 TCP 首部的長度爲 20 字節(除掉data和option,恰好20字節)。
reserved瀏覽器
- URG表示Urgent Pointer字段有意義
- ACK表示Acknowledgment Number字段有意義
- PSH表示有 DATA數據傳輸
- RST表示復位TCP鏈接
- SYN表示SYN報文(在創建TCP鏈接的時候使用)
- FIN表示沒有數據須要發送了(在關閉TCP鏈接的時候使用)
Windows 表示接收緩衝區的空閒空間,16位,用來告訴TCP鏈接另外一端本身可以接收的最大數據長度,流量控制的機制就基於此。
Checksum 差錯控制,TCP校驗和的計算包括TCP首部、數據和其它填充字節。在發送TCP數據段時,由發送端計算校驗和,當到達目的地時又進行一次檢驗和計算。若是兩次校驗和一致說明數據是正確的,不然將認爲數據被破壞,接收端將丟棄該數據。
Urgent 是緊急指針,16位,只有URG標誌位被設置時該字段纔有意義,表示緊急數據相對序列號(Sequence Number字段的值)的偏移。服務器
說明 上面是一個我寫的測試demo,是一個普通的http請求,下面咱們抓包分析一下tcp三次握手的細節網絡
說明 第一次握手client經過發送一個SYN標識位和Sequence Numbers(同步序列號)的數據段給server請求鏈接,經過該數據段告訴server但願創建鏈接
說明 第二次握手是server用一個確認應答ACK標誌位和Acknowledgment Number告訴client收到了數據段,同時本身也發送一個syn包(syn標誌位和Sequence Numbers)。
說明 第三次客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK,此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP鏈接成功)狀態,完成三次握手。
說明 三次握手完畢,連接通道創建成功,下面開始正式數據傳輸
針對上面整個過程下面再來一幅圖詳細總結說明下
socket
- 客戶端經過向服務器端發送一個SYN來代表但願創建鏈接,做爲三次握手的一部分。客戶端把這段鏈接的序號設定爲隨機數c。
- 服務器端應當爲一個合法的SYN回送一個SYN/ACK。ACK的確認碼應爲c+1,SYN/ACK包自己又有一個隨機產生的序號s。
- 最後,客戶端再發送一個ACK。當服務端收到這個ACK的時候,就完成了三次握手,並進入了鏈接建立狀態。此時包的序號被設定爲收到的確認號c+1,而響應號則爲s+1。
下面描述下整個過程,過程和三次握手機制同樣,也是用一些標誌位來實現斷開的過程,詳細步驟過程不在圖形化,由於須要四幅步驟圖,太佔篇幅了,下面根據上面的流程圖大體解釋說明一下。tcp
- client發送FIN標誌位,表示出要斷開鏈接的請求的含義
- server進行響應,發送ack標識,表示確認收到斷開鏈接請求
- server 發送FIN標誌位,提出反方向的關閉要求
- client 發送ack標誌位,標識確認收到的主機B的關閉鏈接請求
適合對傳輸數據要求比較可靠的地方,例如常見的ftp,http,https,smtp等等這些應用層的協議都是基於tcp的封裝;還有實戰中常見套接字編程,能夠用來開發瀏覽器通訊模塊,以及p2p的下載工具等等,這些底層都是都是基於tcp協議。工具
協議只是一個規範,實現形式有多種,具體而言在node當中使用的話以下形式
let net = require('net'); let path = require('path'); let ws = require('fs').createWriteStream(path.join(__dirname, 'msg.txt')); let server = net.createServer(function (socket) { socket.pipe(ws, { end: false }); }); server.listen(8080); 建立一個tcp服務器監聽8080端口,並將接受的數據存儲到msg.txt文件中,上面的socket是一個雙工流,既可寫又能夠讀,下面是測試的輸出結果
說明 上面只是一個簡單的實例,更多用法,能夠參考node當中net模塊
參考連接
https://zh.wikipedia.org/wiki...
http://nodejs.cn/api/
http://www.freebuf.com/column...