[TOC]
https://mp.weixin.qq.com/s/Tc09ovdNacOtnMOMeRc_uA
https://mp.weixin.qq.com/s/dET7DblCg1b6KUuE-FqH-g
https://mp.weixin.qq.com/s/_ilWHsMN0mr-wTP_n7MJSQ
## 簡述滑動窗口
每次tcp傳輸過程中,server和client會攜帶一個滑動窗口大小,意味著此時它能一次接受多少數據,因為數據在客戶端和服務器之間是有緩存的,滑動窗口也就相當于對方告訴自己目前緩沖區的大小,不需要每次發一個數據包就回一個ACK,通過滑動窗口來進行簡單的擁塞控制
## TCP如何實現可靠交付?
1. 序列號:TCP 傳輸時將每個字節的數據都進行了編號,這就是序列號。序列號的作用不僅僅是應答作用,有了序列號能夠將接收到的數據根據序列號進行排序,并且去掉重復的數據。
2. 校驗和:每個數據包保持一個端到端的校驗和,接收方收到之后檢查數據在傳輸過程中有沒有改變,若發生了改變則丟棄;
3. 流量控制:保證接收方緩沖區足夠接收數據,防止丟失;
>如果發送方的發送速度太快,會導致接收方的接收緩沖區填充滿了,這時候繼續傳輸數據,就會造成大量丟包,進而引起丟包重傳等等一系列問題。TCP 支持根據接收端的處理能力來決定發送端的發送速度,這就是流量控制機制。
具體實現方式:接收端將自己的接收緩沖區大小放入 TCP 首部的『窗口大小』字段中,通過 ACK 通知發送端。
4. 擁塞控制:降低網絡擁塞程度,防止數據包丟失;
5. 連接管理:三次握手、四次揮手的過程。
6. 超時重傳:若超時未接受到對方的確認,立即重傳數據包。
## TCP擁塞控制是什么?
擁塞控制是為了降低整個網絡的擁塞程度。當網絡出現擁塞時,分組丟失引發重傳,繼而加重擁塞程度,因此需要控制。發送方維護一個叫做擁塞窗口的狀態變量cwnd,實際決定發送數據量的還是發送窗口。
* 慢啟動 & 擁塞避免:
* 發送最初執行慢啟動,cwnd = 1,發送方只能發送一個報文段。發送方每次收到ACK后將cwnd加倍。
* 為避免成倍增加的cwnd使得網絡擁塞的可能增加,設置慢啟動閾值ssthreash。當cwnd >= ssthresh的時候,進入擁塞避免,每次只能將cwnd的值加一。
* 若出現超時,則將 ssthresh減半,cwnd=1,重新開始慢啟動。
* 快速重傳 & 快速恢復:
* 在接受方,每次只確認收到的最后一個有序報文段;
* 在發送方,若收到m2的3次重復ACK,則可以確認m3丟失,此時執行快速重傳,即立即重傳m3;同時,由于只是丟包而不是網絡擁塞,執行快速恢復:ssthresh = cwnd / 2 ,cwnd = ssthresh。
## TCP流量控制是什么?
流量控制是為了調整發送方的發送速率,使得接收方來得及接收。
接收方的確認報文中有一個窗口字段,用來控制發送方的窗口大小,從而控制發送速率。
> TCP需要提供一種機制:**讓發送端根據接收端實際的接收能力控制發送的數據量**。這就是所謂的流量控制。
TCP 利用**滑動窗口**實現流量控制的機制, 而滑動窗口大小是通過TCP首部的窗口大小字段來通知對方。
窗口大小的內容實際上是接收端接收數據緩沖區的剩余大小。**這個數字越大,證明接收端接收緩沖區的剩余空間越大,網絡的吞吐量越大。**
## 重傳機制?
* 超時重傳
重傳機制的其中一個方式,就是在發送數據時,設定一個定時器,當超過指定的時間后,沒有收到對方的`ACK`確認應答報文,就會重發該數據,也就是我們常說的**超時重傳**。
TCP 會在以下兩種情況發生超時重傳:
* 數據包丟失
* 確認應答丟失

* 快速重傳
**不以時間為驅動,而是以數據驅動重傳**。
快速重傳的工作方式是當收到三個相同的 ACK 報文時,會在定時器過期之前,重傳丟失的報文段。
快速重傳機制只解決了一個問題,就是超時時間的問題,但是它依然面臨著另外一個問題。就是**重傳的時候,是重傳之前的一個,還是重傳所有的問題。**
## 擁塞控制與流量控制的區別
* **流量控制**是作用于接收者的,它是控制發送者的發送速度從而使接收者來得及接收,防止丟失數據包的。
* **擁塞控制**擁塞控制是作用于網絡的,它是防止過多的數據注入到網絡中,避免出現網絡負載過大的情況
* **流量控制**( 發送方一直發送數據,但是接收方處理不過來怎么辦?(流量控制))
TCP需要提供一種機制:**讓發送端根據接收端實際的接收能力控制發送的數據量**。這就是所謂的流量控制。
TCP 利用**滑動窗口**實現流量控制的機制, 而滑動窗口大小是通過TCP首部的窗口大小字段來通知對方。
窗口大小的內容實際上是接收端接收數據緩沖區的剩余大小。**這個數字越大,證明接收端接收緩沖區的剩余空間越大,網絡的吞吐量越大。**
不過,當接收端這個接收緩沖區面臨數據溢出時,窗口大小的值就會隨之設置成一個更小值,告訴發送端要控制一下發送的數據量了。
**流量控制的具體操作就是**:接收端會在確認應答發送ACK報文時,將自己的即時窗口大小rwnd(receiver window)填入,并跟隨ACK報文一起發送過去。而發送方根據ACK報文里的窗口大小的值進而改變自己的發送速度。

**發送端停止發送數據后,什么時候可以繼續發送數據呢?**
我們繼續看上圖,答案就是等接收端處理完了緩沖區的數據后發送一個**窗口更新**的數據包通知,發送端才可以繼續根據窗口大小發送數據。
**但是如果發送端在重發超時的時間內都沒有收到窗口更新的通知或者窗口更新的包丟失了,就沒法正常通信了,那怎么辦呢?**
TCP為每一個連接設有一個**持續計時器(persistence timer)。**只要TCP連接的一方收到對方的零窗口通知,就啟動持續計時器。若持續計時器設置的時間到期,就發送一個零窗口控測數據段(這個數據段只包含一個字節),那么收到這個報文段的一方就重新設置持續計時器。
所以發送端會定時向接收端發送一個**窗口探測**的數據段,這目的是為了獲取最新的窗口大小信息。
## TCP 半連接隊列和全連接隊列是什么?
* TCP三次握手時,客戶端發送SYN到服務端,服務端收到之后,便回復**ACK和SYN**,狀態由**LISTEN變為SYN\_RCVD**,此時這個連接就被推入了**SYN隊列**,即半連接隊列。
* 當客戶端回復ACK, 服務端接收后,三次握手就完成了。這時連接會等待被具體的應用取走,在被取走之前,它被推入ACCEPT隊列,即全連接隊列。
這兩個隊列都是有大小限制的,當超過容量后就會將鏈接丟棄,或者返回 RST 包。
## 擁塞控制原理
有了TCP的滑動窗口控制,收發主機之間即使不再以一個“段”為單位,而是以一個“窗口”為單位發送確認應答信號,所以發送主機夠連續發送大量數據包。然而,**如果在通信剛開始的時候就發送大量的數據包,也有可能會導致網絡的癱瘓。**
在擁塞控制中,發送方維持一個叫做**擁塞窗口cwnd**(congestion window)的狀態變量。**擁塞窗口的大小取決于網絡的擁塞程度,并且動態地在變化**。
發送窗口取擁塞窗口和接收端窗口的最小值,避免發送接收端窗口還大的數據。
擁塞控制使用了兩個重要的算法:**慢啟動算法**,**擁塞避免算法**。
**慢啟動算法**:
慢啟動算法的思路是,不要一開始就發送大量的數據,先試探一下網絡的擁塞程度,也就是說由小到大逐漸增加擁塞窗口的大小。慢算法中,**每個傳輸輪次后將 cwnd 加倍**。慢啟動,不是指擁塞窗口增長慢,而是相對于一開始就上來傳輸大窗口的數據要顯得慢。
**擁塞避免算法**:
擁塞避免算法也是逐漸的增大 cwnd 的大小,只是采用的是**線性增長**而不是像慢啟動算法那樣的指數增長。
具體來說就是每個傳輸輪次后將 cwnd 的大小加一(加法增大),如果發現出現網絡擁塞的話就按照上面的方法重新設置ssthresh的大小(乘法減小,原來的二分之一)并從cwnd=1開始重新執行慢開始算法。
## 慢啟動算法和擁塞避免算法結合:
問題:在擁塞控制中, 慢啟動算法 和 擁塞避免算法 是怎么配合使用的呢?
像上面所說,慢啟動算法下的cwnd大小是指數增長,所以不能任 cwnd 任意增長,所以我們引入一個慢啟動門限(ssthresh)的閾值來控制 cwnd 的增長。
ssthresh的作用是:
* 當cwnd < ssthresh時,使用慢開始算法。
* 當cwnd > ssthresh時,改用擁塞避免算法。
* 當cwnd = ssthresh時,慢開始與擁塞避免算法隨機
還有一個問題就是這個 ssthresh 是怎么設置的呢?
**TCP/IP 中規定無論是在慢開始階段還是在擁塞避免階段,只要發現網絡中出現擁塞(沒有按時收到確認),就要把ssthresh設置為此時發送窗口的一半大小**(不能小于2)。

擁塞控制的大致流程如下:
* 一開始把ssthresh初始值設置成16,開始慢啟動增加擁塞窗口cwnd,直到cwnd=16 停止慢啟動,開始擁塞避免算法。
* 使用擁塞避免算法線性增加cwnd,直到cwnd=24,這時候網絡出現擁塞(ACK確認信號沒有及時到達),把ssthresh設置成原來的一半,也就是ssthresh=12,同時把cwnd設為1。
* 重新開始慢啟動,直到cwnd到達ssthresh=12,然后執行擁塞避免算法進行加法增大,直到遇到網絡擁塞,把ssthresh調成原來的一一半。
* 如此反復動態計算cwnd,以達到擁塞控制的目的。
## 快恢復
**快恢復算法是與快重傳算法配合使用的一個算法。**
快恢復主要是指,當快重傳的時候,發送方快速收到了**3個重復的確認**,因此會認為網絡不是擁塞狀態,所以在**乘法減小過程(設置sstresh為原來一半)**,會啟動**“擁塞避免”**,而不是TCP超時重發機制的重新啟動的**慢啟動**
**TCP協議在實現傳輸可靠性上面做了很多:**
* 通過**序列號和確認應答信號**確保了數據不會重復發送和重復接收。
* 同時通過**超時重發控制**保證即使數據包在傳輸過程中丟失,也能重發保持數據完整。
* 通過三次握手,四次揮手建立和關閉連接的**連接管理**保證了端對端的通信可靠性。
* TCP還使用了**滑動窗口控制**提高了數據傳輸效率
* 通過**流量控制**控制發送者的發送速度從而使接收者來得及接收,防止丟包。
* 通過**擁塞控制**就是防止過多的數據注入到網絡中,避免網絡中的路由器或鏈路不致過載,導致數據丟失。從而保證了TCP傳輸的可靠性。
## 為什么會產生粘包和拆包呢?
* 要發送的數據小于TCP發送緩沖區的大小,TCP將多次寫入緩沖區的數據一次發送出去,將會發生粘包;
* 接收數據端的應用層沒有及時讀取接收緩沖區中的數據,將發生粘包;
* 要發送的數據大于TCP發送緩沖區剩余空間大小,將會發生拆包;
* 待發送數據大于MSS(最大報文長度),TCP在傳輸前將進行拆包。即TCP報文長度-TCP頭部長度>MSS。
**解決方案:**
* 發送端將每個數據包封裝為固定長度
* 在數據尾部增加特殊字符進行分割
* 將數據分為兩部分,一部分是頭部,一部分是內容體;其中頭部結構大小固定,且有一個字段聲明內容體的大小。
## 為什么選擇在傳輸層就將數據“大卸八塊”分成多個段,而不是等到網絡層再分片傳遞給數據鏈路層?
因為可以提高重傳的性能
需要明確的是:可靠傳輸是在傳輸層進行控制的
如果在傳輸層不分段,一旦出現數據丟失,整個傳輸層的數據都得重傳
如果在傳輸層分了段,一旦出現數據丟失,只需要重傳丟失的那些段即可

## 什么是SYN攻擊?怎么解決?

服務端在收到SYN信號后會將ACK信號和新的SYN信號返回給客戶端,并將該連接計入半連接隊列數目中,當半連接數目大于系統設定的最大值(/proc/sys/net/ipv4/tcp\_max\_syn\_backlog)時系統將不能再接收其他的連接,所以攻擊者利用這個原理,在服務器向客戶端發送SYN和ACK信號后不做任何回應,這樣鏈接將一直不會被釋放,直到累計到鏈接最大值而不能再創建新的鏈接,從而達到了讓服務器無法響應正常請求的目的。
**解決方案:**
使syncookies生效,將`/proc/sys/net/ipv4/tcp_syncookies`值置改為1即可,這樣即使是半連接隊列syn queue已經滿了,也可以接收正常的非惡意攻擊的客戶端的請求,
- 消息隊列
- 為什么要用消息隊列
- 各種消息隊列產品的對比
- 消息隊列的優缺點
- 如何保證消息隊列的高可用
- 如何保證消息不丟失
- 如何保證消息不會重復消費?如何保證消息的冪等性?
- 如何保證消息消費的順序性?
- 基于MQ的分布式事務實現
- Beanstalk
- PHP
- 函數
- 基礎
- 基礎函數題
- OOP思想及原則
- MVC生命周期
- PHP7.X新特性
- PHP8新特性
- PHP垃圾回收機制
- php-fpm相關
- 高級
- 設計模式
- 排序算法
- 正則
- OOP代碼基礎
- PHP運行原理
- zavl
- 網絡協議new
- 一面
- TCP和UDP
- 常見狀態碼和代表的意義以及解決方式
- 網絡分層和各層有啥協議
- TCP
- http
- 二面
- TCP2
- DNS
- Mysql
- 鎖
- 索引
- 事務
- 高可用?高并發?集群?
- 其他
- 主從復制
- 主從復制數據延遲
- SQL的語?分類
- mysqlQuestions
- Redis
- redis-question
- redis為什么那么快
- redis的優缺點
- redis的數據類型和使用場景
- redis的數據持久化
- 過期策略和淘汰機制
- 緩存穿透、緩存擊穿、緩存雪崩
- redis的事務
- redis的主從復制
- redis集群架構的理解
- redis的事件模型
- redis的數據類型、編碼、數據結構
- Redis連接時的connect與pconnect的區別是什么?
- redis的分布式鎖
- 緩存一致性問題
- redis變慢的原因
- 集群情況下,節點較少時數據分布不均勻怎么辦?
- redis 和 memcached 的區別?
- 基本算法
- MysqlNew
- 索引new
- 事務new
- 鎖new
- 日志new
- 主從復制new
- 樹結構
- mysql其他問題
- 刪除
- 主從配置
- 五種IO模型
- Kafka
- Nginx
- trait
- genergtor 生成器
- 如何實現手機掃碼登錄功能
- laravel框架的生命周期