應用層協議@傳輸層協議

應用層協議:應用層是面對程序員的一層,應用程序是程序員自己寫的,因此應用層協議由程序員自己決定。

    1、自定製協議:

  • 序列化:將多個數據對象按照指定的協議進行組織成爲持久化存儲/數據傳輸的二進制數據串。
  • 反序列化:將二進制數據串通過指定協議進行解析得到各個數據對象。
  • 序列化方式:結構體二進制序列化,json,protobuf.

    2、知名協議:

  • HTTP-應用層的超文本傳輸協議-html。
  • 網址:URL-統一資源定位符-定位網絡中某臺主機上的某個資源。
  • 如何定位:url包含的要素-協議方案名稱://用戶名:用戶密碼@服務器IP:服務器PORT/資源路徑?查詢字符串#片段標識符
  • 協議方案名稱:確定本次請求使用什麼協議。
  • 用戶名/密碼:本次訪問的客戶端認證信息(很少使用)。
  • 服務器IP/PORT:定位網絡中的一臺主機上的處理進程。
  • 資源路徑:請求服務器上的某個資源。
  • 查詢字符串:客戶端提交給服務端的數據,由key=value鍵值對組成,鍵值對之間以&符號進行間隔。
  • urlencode:url編碼,提交的數據中不能出現特殊字符,一旦包含就要進行轉義,將特殊字符每個字節轉換爲16進制數字字符,使用%標識。
  • urldecode:url解碼,在查詢字符串中遇到%,將其第一個字符轉換爲數字乘以16加上第二個字符轉換後的數字。

      HTTP協議實現

  • 抓包工具:wireshark/fiddler.
  • wireshark:網卡抓包工具,抓取流經網卡的所有數據流量-什麼包都能抓。
  • fiddler:瀏覽器的代理工具,通過代理實現數據抓包-專業的http抓包工具。
  • http/https:https是加密後的http協議,若要抓取https中的數據,則需要進行配置。

      HTTP協議格式

    請求:

首行GET http://123.207.58.25/admin HTTP/1.1 以空格進行間隔包含三個要素,最終以\r\n作爲結尾。

請求方法:GET/POST/HEAD/PUT/DELETE/CONNECT/PATCH/OPTIONS/TRACE

  • GET-請求實體資源-也可以通過url中查詢字符串向服務器提交數據-數據不安全/url長度有限制(各個服務器應用商的限制)
  • POST-主要用於向服務器提交數據,提交的數據在正文中;GET請求沒有正文,POST請求有正文。
  • HEAD-類似於GET,相較於GET,HEAD只響應頭部,而不響應正文。

URL: http://123.207.58.25/admin

協議版本:HTTP://1.1   0.9/1.0/1.1/2.0

  • 0.9:僅用於傳輸html數據,並且只有GET請求方法且協議格式不完整。
  • 1.0:正式規定了http協議格式,並且增加了多種請求方法且支持了不同文件格式的數據流。
  • 1.1:在1.0的基礎上增加了更多請求方法和頭部描述信息且支持了長連接,管線化傳輸(響應的順序必須與請求的順序保持一致)。
  • 2.0:採用二進制流傳輸,並且進行多路複用(響應順序可以不用與請求順序保持一致,頭部標識了請求信息)且允許服務端主動推送數據。
  • 短連接:http基於在傳輸層tcp實現通信,建立連接,發送一個請求,得到響應後,則關閉連接。
  • 長連接:一次連接可以發送多條請求。

頭部:描述本次請求的關鍵字段信息,由key:val形式的鍵值對組成,並且每個鍵值對以\r\rn作爲結尾 key:val\r\rnkey:val\r\rn

  • Connection-控制長/短連接
  • Cache-Control-緩存控制
  • User-Agent-客戶端屬性
  • Accept-描述自己所能接收的數據屬性
  • Content-Length-描述正文長度
  • Content-Type-描述正文數據類型

早期http是短連接通信,是一個無狀態協議,不會保存客戶端的狀態,每次訪問都需要進行登錄,因此引入Cookie保存客戶端狀態,Cookie-持續在通信中描述客戶端的通信狀態,但是不夠安全。

空行:間隔頭部與正文;接收http數據的時候,當連續收到兩個\r\n(\r\n\r\n)的時候,則認爲頭部到此結束。

先獲取完整頭部,通過頭部中的Content-Length獲取正文長度,然後獲取指定長度正文,通過這種方式每次獲取完整一條http請求數據。

正文:提交給服務端的數據。

    響應:

首行HTTP/1.1 303 See Other 包含三個要素,以空格進行間隔,以\r\n作爲結尾

協議版本:0.9/1.0/1.1/2.0

響應狀態碼:表示對本次的請求服務端所做出的響應結果

  • 1xx:描述信息
  • 2xx:表示本次請求正確處理完畢  典型 200
  • 3xx:重定向-請求的資源在另一個位置,要求客戶端重新請求新位置;301-永久/302-臨時
  • 4xx:表示客戶端請求錯誤;400-請求錯誤/404-表示請求的資源不存在
  • 5xx:表示服務端錯誤;500-服務器內部錯誤 / 502-代理請求失敗,無效響應 / 504-代理請求超時

狀態碼描述:對狀態碼的描述信息,可以是官方文檔對應描述,也可以自定義。

頭部:關於本次響應的一些關鍵字段描述信息,以key:val鍵值對組成,以\r\n作爲結尾

  • Transfer-Encoding:實體正文的傳輸方式
  • Expires:緩存過期時間
  • Location-3xx 重定向的新位置
  • Set-Cookie-服務端通過set-cookie向客戶端傳遞信息,會被保存在客戶端瀏覽器的cookie文件中。
  • Cookie-客戶端每次通信從cookie文件讀取數據通過cookie向服務端傳遞信息(維持客戶端狀態信息),cookie的使用不夠安全,因此使用Session搭配使用。
  • Session-會話,服務端會爲每個登錄的客戶端創建會話,在服務端描述一些會話信息(客戶端身份信息,狀態信息),保存在服務端,可以通過set-cookie將session id 返回給客戶端,客戶端每次通信都會通過cookie帶有自己的sessio id;
  • cookie和session區別:cookie持續傳遞客戶端狀態信息的字段,保存在客戶端,用於持續與服務端進行信息傳遞的一種手段。session是一種會話的控制,服務端保存的會話信息包含客戶端的身份狀態信息,通過cookie/set-cookie傳遞的session id 進行客戶端的身份狀態識別。

   3. UDP協議

    3.1 UDP協議端格式:UDP協議報頭只有8個字節

              

  •  16位源端端口/16位目的端端口:描述端與端之間的通信;
  • 16位UDP長度:表示整個數據報(udp首部+udp數據)的最大長度,即數據報最大大小位2^16byte=64kb;
  • 16位校驗和:使用二進制反碼求和算法,校驗接收的數據與發送的數據是否一致;(二進制反碼求和算法->對報文從頭開始每個字節進行取反相加,高出16位則截斷高位,與低16位繼續相加,得到校驗和)

3.2 UDP特點

  • 無連接:知道對端的IP和端口號就直接進行傳輸, 不需要建立連接;
  • 不可靠:沒有確認機制, 沒有重傳機制;如果因爲網絡故障該段無法發到對方, UDP協議層也不會給應用層
    返回任何錯誤信息;UDP不保證數據的可靠, 有序到達, 因此有可能亂序, 需要在應用層進行包序管理;
  • 面向數據報:應用層交給UDP多長的報文, UDP原樣發送, 既不會拆分, 也不會合並, 並且最大長度64KB;如果我們需要傳輸的數據超過64K, 就需要在應用層手動的分包, 多次發送, 並在接收端手動拼裝。

3.3 UDP的緩衝區

  • UDP沒有真正意義上的 發送緩衝區. 調用sendto會直接交給內核, 由內核將數據傳給網絡層協議進行後續的傳輸動作;
  • UDP具有接收緩衝區. 但是這個接收緩衝區不能保證收到的UDP報的順序和發送UDP報的順序一致; 如果緩衝區滿了, 再到達的UDP數據就會被丟棄;
  • UDP的socket既能讀, 也能寫, 這個概念叫做 全雙工。

3.4 基於UDP的知名協議

  • DHCP: 動態主機配置協議;
  • DNS: 域名解析協議

    4. TCP協議

    4.1 TCP協議端格式

               

  • 源/目的端口號: 表示數據是從哪個進程來, 到哪個進程去;
  • 32位序號/32位確認號: 實現tcp的包序管理->tcp數據是有序交付的;
  • 4位TCP報頭長度: 以4字節位單位描述tcp報頭長度,tcp報頭是不定長的,最小20字節, 最大15 * 4 = 60字節;
  • 6位標誌位:
  1. URG: 緊急指針是否有效
  2. ACK: 確認號是否有效
  3. PSH: 提示接收端應用程序立刻從TCP緩衝區把數據讀走
  4. RST: 對方要求重新建立連接; 我們把攜帶RST標識的稱爲復位報文段
  5. SYN: 請求建立連接; 我們把攜帶SYN標識的稱爲同步報文段
  6. FIN: 通知對方, 本端要關閉了, 我們稱攜帶FIN標識的爲結束報文段
  • 16位窗口大小: 實現滑動窗口機制,進行流量控制;
  • 16位校驗和: 二進制反碼求和算法,校驗數據一致性;
  • 16位緊急指針: 標識哪部分數據是緊急數據;
  • 0~40字節選項數據:主要用於協商以及描述一些信息。

4.2 TCP數據傳輸格式

  • TCP發送數據,是以字節流的形式發送。它不關心數據是什麼類型,但是爲了確保數據正確性,重發控制和重複控制等, 這些功能都以序列號來實現. 序列號初始值並非爲0,而是由客戶端建立連接時候,隨機產生的;
  • TCP的數據長度並未寫入TCP首部。實際通信中求得TCP包的長度的計算公式是:IP首部中的數據包長度 – IP首部長度TCP首部長度;
  • TCP將每個字節的數據都進行了編號. 即爲序列號. 每一個ACK都帶有對應的確認序列號, 意思是告訴發送者, 我已經收到了哪些數據; 下一次你從哪裏開始發。

                           

4.3 確認應答機制

                                                 

  • 當數據從主機A發送給主機B時,主機B會返回給主機A一個確認應答。 

4.4 超時傳輸機制

                                                   

  • 主機A發送數據給B之後, 可能因爲網絡擁堵等原因, 數據無法到達主機B; 如果主機A在一個特定時間間隔內沒有收到B發來的確認應答, 就會進行重發

                                                    

  •  主機A未收到B發來的確認應答, 也可能是因爲ACK丟失了,因此主機B會收到很多重複數據. 那麼TCP協議需要能夠識別出那些包是重複的包, 並且把重複的丟棄掉.  這時候我們可以利用前面提到的序列號, 就可以很容易做到去重的效果。

那麼, 如果超時的時間如何確定?

  • 最理想的情況下, 找到一個最小的時間, 保證 “確認應答一定能在這個時間內返回”.
  • 但是這個時間的長短, 隨着網絡環境的不同, 是有差異的.
  • 如果超時時間設的太長, 會影響整體的重傳效率;
  • 如果超時時間設的太短, 有可能會頻繁發送重複的包;

TCP爲了保證無論在任何環境下都能比較高性能的通信, 因此會動態計算這個最大超時時間.

  • Linux中(BSD Unix和Windows也是如此), 超時以500ms爲一個單位進行控制, 每次判定超時重發的超時時間都是500ms的整數倍.
  • 如果重發一次之後, 仍然得不到應答, 等待 2*500ms 後再進行重傳.
  • 如果仍然得不到應答, 等待 4*500ms 進行重傳. 依次類推, 以指數形式遞增.
  • 累計到一定的重傳次數, TCP認爲網絡或者對端主機出現異常, 強制關閉連接

4.5 TCP應答管理機制

                           

服務端狀態轉化:

  • [CLOSED -> LISTEN] 服務器端調用listen後進入LISTEN狀態, 等待客戶端連接;
  • [LISTEN -> SYN_RCVD] 一旦監聽到連接請求(同步報文段), 就將該連接放入內核等待隊列中, 並向客戶端發送SYN確認報文.
  • [SYN_RCVD -> ESTABLISHED] 服務端一旦收到客戶端的確認報文, 就進入ESTABLISHED狀態, 可以進行讀寫數據了.
  • [ESTABLISHED -> CLOSE_WAIT] 當客戶端主動關閉連接(調用close), 服務器會收到結束報文段, 服務器返回確認報文段並進入CLOSE_WAIT;
  • [CLOSE_WAIT -> LAST_ACK] 進入CLOSE_WAIT後說明服務器準備關閉連接(需要處理完之前的數據); 當服務器真正調用close關閉連接時, 會向客戶端發送FIN, 此時服務器進入LAST_ACK狀態, 等待最後一個ACK到來(這個ACK是客戶端確認收到了FIN)
  • [LAST_ACK -> CLOSED] 服務器收到了對FIN的ACK, 徹底關閉連接

客戶端狀態轉化:

  • [CLOSED -> SYN_SENT] 客戶端調用connect, 發送同步報文段;
  • [SYN_SENT -> ESTABLISHED] connect調用成功, 則進入ESTABLISHED狀態, 開始讀寫數據;
  • [ESTABLISHED -> FIN_WAIT_1] 客戶端主動調用close時, 向服務器發送結束報文段, 同時進入FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客戶端收到服務器對結束報文段的確認, 則進入FIN_WAIT_2, 開始等待服務器的結束報文段;
  • [FIN_WAIT_2 -> TIME_WAIT] 客戶端收到服務器發來的結束報文段, 進入TIME_WAIT, 併發出LAST_ACK;
  • [TIME_WAIT -> CLOSED] 客戶端要等待一個2MSL(Max Segment Life, 報文最大生存時間)的時間, 纔會進入CLOSED狀態

爲什麼是三次握手

  • 如果client發送的連接請求由於網絡延時到client連接釋放後纔到達server,這是早已失效的報文,如果只進行二次握手,服務器就認爲有新連接請求,但是client並沒有建立連接,不會給server發送數據,但是server爲了這個連接,會一直有資源消耗。

爲什麼是四次揮手

  • 客戶端發送FIN包,表示客戶端不再發送數據,不表示客戶端不再接收數據,因此被動關閉方進行ACK回覆之後有可能還會繼續發送數據,等到不再發送數據,纔會發送下一個FIN包,因此FIN和ACK是分開的。

TIME_WAIT狀態有什麼用?爲什麼主動關閉方沒有直接進入closed釋放資源?

  • 假設主動關閉方最後一次的ACK丟失,被動關閉方沒有收到最後一次ACK,超時後就會重傳一個FIN。
  • 假設客戶端沒有TIME_WAIT而是直接釋放資源,就有可能啓動新的客戶端且使用與之前客戶端相同的地址信息。剛啓動新的客戶端綁定地址成功,收到重傳的FIN包,對新連接造成影響;新啓動的客戶端,若是向相同的服務端發送SYN,因爲服務端處於LAST_ACK,需求的是ACK而不是SYN,因此就會發送RST。
  • 因此若主動關閉方最後一次回覆後直接釋放資源,就有可能會對新啓動的新連接造成影響,因此必須等待一段時間,能夠處理有可能重傳的FIN。
  • 等待比較合適的時間->2個MSL時間(MSL->報文最大生存週期)。1、處理重傳的FIN包;2、等到本次通信的所有報文都消失在網絡中,避免對新連接造成影響。

TCP三次握手失敗,服務端如何處理?

  1. 沒有收到SYN,什麼都不做;
  2. 回覆了SYN+ACK,但長時間沒有收到響應,則超時後發送RST重置連接報文,釋放資源。

一臺主機上出現大量的TIME_WAIT是什麼原因?如何處理?

  • TIME_WAIT是主動關閉方出現的,一臺主機上出現大量的TIME_WAIT說明這臺主機主動關閉了大量的連接,常見於一些爬蟲服務器。
  • 處理方法:調整TIME_WAIT等待時間,也可使用開啓地址重用的套接字選項->setsockopt。(地址重用->允許套接字綁定使用中的地址端口,常用於防止socket處於TIME_WAIT無法使用相同地址信息進行綁定新的套接字)

一臺主機上出現大量的CLOSE_WAIT是什麼原因?如何處理?

  • CLOSE_WAIT是被動關閉方收到FIN請求進行回覆之後的狀態,等待上層程序進行進一步處理。若出現大量CLOSE_WAIT,有可能是被動關閉方主機程序中忘記了最後一步斷開連接後調用close釋放資源。

TCP連接管理中的保活機制:

  • tcp通信中,若兩端長時間沒有數據往來,則這時候每隔一段時間,服務端向客戶端發送一個保活探測數據報,要求客戶端進行修復,若連接多次沒有收到響應,則認爲連接斷開。
  • 長時間沒有數據往來:默認7200s--->可配置,通過設置套接字選項配置。
  • 每隔一段時間:默認75s--->可配置,通過設置套接字選項配置。
  • 連續多次無響應:默認9次--->可配置,通過設置套接字選項配置。

可靠傳輸:

  1. 面向連接;
  2. 確認應答機制->發送數據後要求對方進行確認回覆,才能知道對方是否收到了這條數據,通過序號與確認序號實現;
  3. 超時重傳機制->發送數據等待確認響應超時之後,認爲數據丟失,則進行重新傳輸;
  4. 通過序號/確認序號字段實現數據有序交付;
  5. 通過校驗和字段校驗數據一致性,不一致則要求對方進行重傳。

                                               

  • seq:本條數據的起始序號,
  • ack:對對方發送數據的確認序號,告訴對方確認序號之前的數據已收到
  • 三次握手時,雙方會協商起始序號(上面例子從0開始,實際中不一定,是一個隨機值),三次握手時,雖然數據長度爲0,但是確認序號時對方發送的數據起始序號+1。(ack=seq+1,seq=ack)
  • 數據通信時,確認序號是對方發送的數據起始序號+數據長度(ack=seq+len),告訴對方這個確認序號之前的數據都已收到。
  • 數據連續發送時,第一條數據丟失,接收方直接收到了第二條和第三條,接收方就不會對第二條和第三條進行回覆->因爲確認序號確認的是這個序號之前的數據全部已收到。這麼做的目的是->防止因爲確認回覆的丟失而導致的重傳。如果因爲網絡原因,後發的數據先到,接收方也會根據協商的起始序號,根據每條數據中的起始序號,將數據在接收緩衝區中進行排序。

額外的丟包問題處理:

  1. 發送方發送數據過快,接收方來不及處理取出,接收緩衝區滿溢,那麼以後的數據都會被丟棄;
  2. 發送方發送大量的數據,但是因爲網絡狀態不好導致大量丟包造成重傳。

滑動窗口機制:依靠協議中的窗口大小字段實現流量控制

  • 接收方通過協議中的窗口大小字段,告訴發送方,最多可以發送多少數據(窗口大小不大於接收方的接收緩衝區剩餘空間大小->避免了發送的數據太多而緩衝區滿了沒處放的丟包)。
  • MSS:最大數據段大小,表示tcp數據通信時一條數據的最大大小,通信時雙方進行協商,取雙方mss中較小的一方作爲最大數據段大小。
  • 滑動窗口在發送方維護髮送窗口/接收方維護接收窗口->窗口通過一個後沿序號/前沿序號實現。
  • 發送窗口:表示一次最多從後沿到前沿最多發送多少數據->不超過接收方的窗口大小。
  • 後沿:所要發送數據的起始序號,後延的移動取決於是否收到數據確認回覆。
  • 前沿:根據接收方窗口大小計算的結束序號,取決於接收方響應的窗口大小(前沿減去後沿就是接收方的窗口大小)
  • 接收窗口:表示從哪裏開始接收數據,接收到多少序號爲止->不超過剩餘空間大小,進行包序管理,哪個包應該放在緩衝區的什麼位置。
  • 後沿:接收數據的起始序號,後沿的移動取決於是否收到了數據。
  • 前沿:根據接收緩衝區剩餘空間大小計算得到的接收的數據的結束序號,前沿的移動取決於剩餘空間大小。
  • 窗口大小指的是無需等待確認應答而可以繼續發送數據的最大值。
  • 操作系統內核爲了維護這個滑動窗口, 需要開闢發送緩衝區來記錄當前還有哪些數據沒有應答; 只有確認應答過的數據, 才能從緩衝區刪掉;
  • 窗口越大, 則網絡的吞吐率就越高;

å¨è¿éæå¥å¾çæè¿°

  • 停等協議:得到一條回覆,然後才能發送下一條數據。
  • 回退n步協議:一條數據丟失了,則需要發送端將丟失這條數據以後的數據都進行重傳。
  • 選擇重傳協議:一條數據丟失了,則僅僅針對丟失的這條數據進行重傳。
  • 因爲網絡狀態不好,導致發送的數據越多丟包的越多->擁塞控制。
  • 擁塞控制:進行網絡探測,以一種慢啓動,快增長的傳輸方式,根據網絡狀態調整發送速度的機制。

提高傳輸性能的方式:

  • 快速重傳機制:發送端連續發送多條數據,若接收端接收數據並非是接收後沿數據,則認爲有可能後沿數據丟失了,首先不會進行接收到的數據的確認回覆,其次向發送端間隔連續發送三次後沿數據的重傳請求,要求對方對後沿數據進行重傳。發送方連續收到三條同一重傳請求,則對這條數據進行重傳。
  • 爲什麼是三次:避免因爲網絡延遲,數據報的延遲到達,三次可以有一個緩衝時間,若在第二次的時候收到了後沿數據報,則不再發送第三條重傳請求,這時候發送端也不用重傳了。
  • 快速重傳,可以一定程度避免發送端必須的超時重傳。
  • 延時應答機制:接收方接收到數據之後,並不立即進行確認回覆(因爲如果立即進行確認回覆,因爲接收緩衝區剩餘空間變小了,窗口就變小了,導致傳輸的吞吐量變小了),而是延遲應答,則有可能應答的時候程序在上層已經將數據取出,保證窗口大小不會變小。
  • 捎帶應答機制:接收方接收到數據之後,進行確認回覆,確認回覆就是一個報頭中的確認序號進行的,爲了減少空報頭的響應占據帶寬,則使用捎帶應答,在即將要發送的數據頭部中進行上一條接收到的數據的確認回覆。

面向字節流:字節流傳輸服務是面向連接的,有序的一種最小以字節爲傳輸單元的傳輸方式。

  • 發送端在send發送數據的時候,並不會立即封裝報頭,而是將數據先放到發送緩衝區中,選擇合適的時候再去從緩衝區中取出合適大小的數據進行傳輸。
  • 接收端在recv接收數據的時候,並非一條一條向上交付,而是根據recv想要的數據長度從接收緩衝區中取出指定長度的數據進行交付。
  • 優點:傳輸比較靈活,大量小的數據會集合成一條大的數據進行一次性傳輸,減少了IO次數提高了性能(延遲發送可以關閉,可配置),接收方接收也更加靈活,想要多少取多少。
  • 缺陷:tcp交付的這條數據可能並非一條完整的數據,也有可能是多條數據(tcp對於上層給與的數據邊界並不敏感,不關注是幾條數據,只關注自己可以傳輸多少字節的數據/recv想要多少字節的數據)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章