找工做-——網絡IO

網絡層web

主要任務是把網絡協議數據單元或分組從源計算機通過適當的路徑發送到目的地計算機。從源計算機到目的計算機可能要通過若干個中間節點,這須要在通訊子網中進行路由選擇。編程

網絡層與數據鏈路層有很大的差異,數據鏈路層僅把數據幀從線纜或信道的一端傳送到另外一端(即在相鄰節點間進行數據傳送),網絡層的目的是實現兩個端系統之間的數據透明傳送,具體功能包括路由選擇、阻塞控制和網際互連等。設計模式

網絡層向上只提供簡單靈活的、無鏈接的、盡最大努力交付的數據報服務。
無鏈接的:網絡在發送分組時不須要先創建鏈接。每個分組(即 IP 數據報)獨立發送,與其先後的分組無關(不進行編號)。
盡最大努力交付:網絡層不提供服務質量的承諾。即所傳送的分組可能出錯、丟失、重複和失序(不按序到達終點),固然也不保證分組傳送的時限。 
盡最大努力交付的好處:
  因爲傳輸網絡不提供端到端的可靠傳輸服務,這就使網絡中的路由器能夠作得比較簡單,並且價格低廉(與電信網的交換機相比較)。
  若是主機(即端系統)中的進程之間的通訊須要是可靠的,那麼就由網絡的主機中的運輸層負責(包括差錯處理、流量控制等)。
  採用這種設計思路的好處是:網絡的造價大大下降,運行方式靈活,可以適應多種應用。
  因特網可以發展到今日的規模,充分證實了當初採用這種設計思路的正確性。 
網際協議 IP 是 TCP/IP 體系中兩個最主要的協議之一。與 IP 協議配套使用的還有四個協議:地址解析協議 ARP (Address Resolution Protocol)、逆地址解析協議 RARP( Reverse Address Resolution Protocol)、網際控制報文協議 ICMP(Internet Control Message Protocol)、網際組管理協議 IGMP(Internet Group Management Protocol)
地址解析協議 ARP: 無論網絡層使用的是什麼協議,在實際網絡的鏈路上傳送數據幀時,最終仍是必須使用硬件地址。 當主機 A 欲向本局域網上的某個主機 B 發送 IP 數據報時,就先在其 ARP 高速緩存中查看有無主機 B 的 IP 地址。若有,就可查出其對應的硬件地址,再將此硬件地址寫入 MAC 幀,而後經過局域網將該 MAC 幀發往此硬件地址。
IP 數據報的格式 :
  一個 IP 數據報由首部和數據兩部分組成。
  首部的前一部分是固定長度,共 20 字節,是全部 IP 數據報必須具備的。
  在首部的固定部分的後面是一些可選字段,其長度是可變的。
  首部長度最大可達60字節。
傳輸層
主要任務:
根據下面通訊子網的特性最佳的利用網絡資源,並以可靠和經濟的方式在兩端主機的進程之間,創建一條運輸鏈接,以透明地傳送報文,也就是說,運輸層向上一層進行通訊的兩個進程之間提供一個可靠的端到端的服務,使它們看不見運輸層如下的數據通訊細節。在通訊子網內的各個交換節點以及鏈接各通訊子網的路由器都沒有運輸層。運輸層只能存在於通訊子網外面的主機中。運輸層以上的各層就再也不關心信息傳輸問題了。 
從通訊和信息處理的角度看,運輸層向它上面的應用層提供通訊服務,它屬於面向通訊部分的最高層,同時也是用戶功能中的最低層。
當網絡的邊緣部分中的兩個主機使用網絡的核心部分的功能進行端到端的通訊時,只有位於網絡邊緣部分的主機的協議棧纔有運輸層,而網絡核心部分中的路由器在轉發分組時都只用到下三層的功能。 
運輸層爲應用進程之間提供端到端的邏輯通訊(但網絡層是爲主機之間提供邏輯通訊)。
運輸層還要對收到的報文進行差錯檢測。
運輸層須要有兩種不一樣的運輸協議,即面向鏈接的 TCP 和無鏈接的 UDP。   
當運輸層採用面向鏈接的 TCP 協議時,儘管下面的網絡是不可靠的(只提供盡最大努力服務),但這種邏輯通訊信道就至關於一條全雙工的可靠信道。
當運輸層採用無鏈接的 UDP 協議時,這種邏輯通訊信道是一條不可靠信道。 
UDP 在傳送數據以前不須要先創建鏈接。對方的運輸層在收到 UDP 報文後,不須要給出任何確認。雖然 UDP 不提供可靠交付,但在某些狀況下 UDP 是一種最有效的工做方式。
TCP 則提供面向鏈接的服務。TCP 不提供廣播或多播服務。因爲 TCP 要提供可靠的、面向鏈接的運輸服務,所以不可避免地增長了許多的開銷。這不只使協議數據單元的首部增大不少,還要佔用許多的處理機資源。  
用戶數據報協議 UDP(User Datagram Protocol)
UDP 傳送的數據單位協議是 UDP 報文或用戶數據報。 
UDP 只在 IP 的數據報服務之上增長了不多一點的功能,即端口的功能和差錯檢測的功能。
  UDP 是無鏈接的,即發送數據以前不須要創建鏈接。
  UDP 使用盡最大努力交付,即不保證可靠交付,同時也不使用擁塞控制。
  UDP 是面向報文的。( 發送方 UDP 對應用程序交下來的報文,在添加首部後就向下交付 IP 層。UDP 對應用層交下來的報文,既不合並,也不拆分,而是保留這些報文的邊界。應用層交給 UDP 多長的報文,UDP 就照樣發送,即一次發送一個報文。接收方 UDP 對 IP 層交上來的 UDP 用戶數據報,在去除首部後就原封不動地交付上層的應用進程,一次交付一個完整的報文。應用程序必須選擇合適大小的報文。)
  UDP 沒有擁塞控制,很適合多媒體通訊的要求。
  UDP 支持一對1、一對多、多對一和多對多的交互通訊。
  UDP 的首部開銷小,只有 8 個字節
傳輸控制協議 TCP(Transmission Control Protocol)
TCP 傳送的數據單位協議是 TCP 報文段(segment)
TCP 最主要的特色
  • TCP 是面向鏈接的運輸層協議。
  • 每一條 TCP 鏈接只能有兩個端點(endpoint),每一條 TCP 鏈接只能是點對點的(一對一)。
  • TCP 提供可靠交付的服務。
  • TCP 提供全雙工通訊。
  • 面向字節流。

TCP 鏈接是一條虛鏈接而不是一條真正的物理鏈接。瀏覽器

TCP 根據對方給出的窗口值和當前網絡擁塞的程度來決定一個報文段應包含多少個字節(UDP 發送的報文長度是應用進程給出的)。

TCP 可把太長的數據塊劃分短一些再傳送。TCP 也可等待積累有足夠多的字節後再構成報文段發送出去。緩存

使用上述的確認和重傳機制,咱們就能夠在不可靠的傳輸網絡上實現可靠的通訊。
接收方通常採用累積確認的方式。即沒必要對收到的分組逐個發送確認,而是對按序到達的最後一個分組發送確認,這樣就表示:到這個分組爲止的全部分組都已正確收到了。
累積確認有的優勢是:容易實現,即便確認丟失也沒必要重傳。缺點是:不能向發送方反映出接收方已經正確收到的全部分組的信息。
在某段時間,若對網絡中某資源的需求超過了該資源所能提供的可用部分,網絡的性能就要變壞——產生擁塞(congestion)。
擁塞控制所要作的都有一個前提,就是網絡可以承受現有的網絡負荷。
擁塞控制是一個全局性的過程,涉及到全部的主機、全部的路由器,以及與下降網絡傳輸性能有關的全部因素。
流量控制每每指在給定的發送端和接收端之間的點對點通訊量的控制。
流量控制所要作的就是抑制發送端發送數據的速率,以便使接收端來得及接收。 
創建TCP鏈接:
1)第一次握手:創建鏈接時,客戶端A發送SYN包(SYN=j)到服務器B,並進入SYN_SEND狀態,等待服務器B確認。
2)第二次握手:服務器B收到SYN包,必須確認客戶A的SYN(ACK=j+1),同時本身也發送一個SYN包(SYN=k),即SYN+ACK包,此時服務器B進入SYN_RECV狀態。
3)第三次握手:客戶端A收到服務器B的SYN+ACK包,向服務器B發送確認包ACK(ACK=k+1),此包發送完畢,客戶端A和服務器B進入ESTABLISHED狀態,完成三次握手。
完成三次握手,客戶端與服務器開始傳送數據。
斷開TCP鏈接:
因爲TCP鏈接是全雙工的,所以每一個方向都必須單獨進行關閉。這個原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的鏈接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP鏈接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另外一方執行被動關閉。

(1)客戶端A發送一個FIN,用來關閉客戶A到服務器B的數據傳送(報文段4)。
(2)服務器B收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1(報文段5)。和SYN同樣,一個FIN將佔用一個序號。
(3)服務器B關閉與客戶端A的鏈接,發送一個FIN給客戶端A(報文段6)。
(4)客戶端A發回ACK報文確認,並將確認序號設置爲收到序號加1(報文段7)。服務器

中斷鏈接端能夠是Client端,也能夠是Server端網絡

假設Client端發起中斷鏈接請求,也就是發送FIN報文。Server端接到FIN報文後,意思是說"我Client端沒有數據要發給你了",可是若是你還有數據沒有發送完成,則沒必要急着關閉Socket,能夠繼續發送數據。因此你先發送ACK,"告訴Client端,你的請求我收到了,可是我還沒準備好,請繼續你等個人消息"。這個時候Client端就進入FIN_WAIT狀態,繼續等待Server端的FIN報文。當Server端肯定數據已發送完成,則向Client端發送FIN報文,"告訴Client端,好了,我這邊數據發完了,準備好關閉鏈接了"。Client端收到FIN報文後,"就知道能夠關閉鏈接了,可是他仍是不相信網絡,怕Server端不知道要關閉,因此發送ACK後進入TIME_WAIT狀態,若是Server端沒有收到ACK則能夠重傳。「,Server端收到ACK後,"就知道能夠斷開鏈接了"。Client端等待了2MSL後依然沒有收到回覆,則證實Server端已正常關閉,那好,我Client端也能夠關閉鏈接了。Ok,TCP鏈接就這樣關閉了!多線程

1.爲何創建鏈接協議是三次握手,而關閉鏈接倒是四次握手呢?less

這是由於服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它能夠把ACK和SYN(ACK起應答做用,而SYN起同步做用)放在一個報文裏來發送。但關閉鏈接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你全部的數據都所有發送給對方了,因此你能夠未必會立刻會關閉SOCKET,也即你可能還須要發送一些數據給對方以後,再發送FIN報文給對方來表示你贊成如今能夠關閉鏈接了,因此它這裏的ACK報文和FIN報文多數狀況下都是分開發送的。tcp

2.爲何TIME_WAIT狀態還須要等2MSL後才能返回到CLOSED狀態?

這是由於雖然雙方都贊成關閉鏈接了,並且握手的4個報文也都協調和發送完畢,按理能夠直接回到CLOSED狀態(就比如從SYN_SEND狀態到ESTABLISH狀態那樣);可是由於咱們必需要假想網絡是不可靠的,你沒法保證你最後發送的ACK報文會必定被對方收到,所以對方處於LAST_ACK狀態下的SOCKET可能會由於超時未收到ACK報文,而重發FIN報文,因此這個TIME_WAIT狀態的做用就是用來重發可能丟失的ACK報文。

粘包問題能夠用下圖來表示:

1. 先接收到data1,而後接收到data2.

2. 一次性接收到了data1和data2的所有數據. 

3. 先接收到了data1的所有數據和data2的部分數據,而後接收到了data2的餘下的數據. 

4. 先接收到data1的部分數據,而後接收到data1餘下的部分以及data2的所有.

後三種就是粘包了

粘包出現緣由

在流傳輸中出現,UDP不會出現粘包,由於它有消息邊界(參考Windows 網絡編程)
1 發送端須要等緩衝區滿才發送出去,形成粘包
2 接收方不及時接收緩衝區的包,形成多個包接收

何時須要考慮粘包問題?

1 :  若是利用tcp每次發送數據,就與對方創建鏈接,而後雙方發送完一段數據後,就關閉鏈接,這樣就不會出現粘包問題
2:若是發送數據無結構,如文件傳輸,這樣發送方只管發送,接收方只管接收存儲就ok,也不用考慮粘包
3:若是雙方創建鏈接,須要在鏈接後一段時間內發送不一樣結構數據,如鏈接後,有好幾種結構:
1)"hello give me sth abour yourself" 
2)"Don't give me sth abour yourself" 
那這樣的話,若是發送方連續發送這個兩個包出去,接收方一次接收可能會是"hello give me sth abour yourselfDon't give me sth abour yourself" 這樣接收方就傻了,究竟是要幹嗎?不知道,由於協議沒有規定這麼詭異的字符串,因此要處理把它分包,怎麼分也須要雙方組織一個比較好的包結構,因此通常可能會在頭加一個數據長度之類的包,以確保接收。

TCP短鏈接和UDP不須要考慮粘包問題。

解決辦法

本質上是要在應用層維護消息與消息的邊界(下文的「包」能夠認爲是「消息」)
一、定長包
二、包尾加\r\n(ftp)缺點是若是消息自己含有\r\n字符,則也分不清消息的邊界
三、包頭加上包體長度
四、更復雜的應用層協議

HTTP:

HTTP是hypertext transfer protocol(超文本傳輸協議)的簡寫,它是TCP/IP協議的一個應用層協議,用於定義WEB瀏覽器與WEB服務器之間交換數據的過程。

HTTP 的主要特色

  HTTP 1.0 協議是無狀態的(stateless)。
  HTTP 協議自己也是無鏈接的,雖然它使用了面向鏈接的 TCP 向上提供的服務。

在HTTP1.0協議中,客戶端與web服務器創建鏈接後,只能得到一個web資源。
在HTTP1.1協議,容許客戶端與web服務器創建鏈接後,在一個鏈接上獲取多個web資源。

HTTP請求包括的內容:

一個完整的HTTP請求包括以下內容:一個請求行、若干消息頭、以及實體內容

accept:瀏覽器經過這個頭告訴服務器,它所支持的數據類型
  Accept-Charset: 瀏覽器經過這個頭告訴服務器,它支持哪一種字符集
  Accept-Encoding:瀏覽器經過這個頭告訴服務器,支持的壓縮格式
  Accept-Language:瀏覽器經過這個頭告訴服務器,它的語言環境
  Host:瀏覽器經過這個頭告訴服務器,想訪問哪臺主機
  If-Modified-Since: 瀏覽器經過這個頭告訴服務器,緩存數據的時間
  Referer:瀏覽器經過這個頭告訴服務器,客戶機是哪一個頁面來的  防盜鏈
  Connection:瀏覽器經過這個頭告訴服務器,請求完後是斷開連接仍是何持連接

HTTP響應:

個HTTP響應表明服務器向客戶端回送的數據,它包括: 一個狀態行、若干消息頭、以及實體內容 。

HTTP響應中的經常使用響應頭(消息頭)
  Location: 服務器經過這個頭,來告訴瀏覽器跳到哪裏
  Server:服務器經過這個頭,告訴瀏覽器服務器的型號
  Content-Encoding:服務器經過這個頭,告訴瀏覽器,數據的壓縮格式
  Content-Length: 服務器經過這個頭,告訴瀏覽器回送數據的長度
  Content-Language: 服務器經過這個頭,告訴瀏覽器語言環境
  Content-Type:服務器經過這個頭,告訴瀏覽器回送數據的類型
  Refresh:服務器經過這個頭,告訴瀏覽器定時刷新
  Content-Disposition: 服務器經過這個頭,告訴瀏覽器如下載方式打數據
  Transfer-Encoding:服務器經過這個頭,告訴瀏覽器數據是以分塊方式回送的
  Expires: -1  控制瀏覽器不要緩存
  Cache-Control: no-cache  
  Pragma: no-cache

NIO

阻塞I/O已有了必定了解,咱們知道阻塞I/O在調用InputStream.read()方法時是阻塞的,它會一直等到數據到來時(或超時)纔會返回;一樣,在調用ServerSocket.accept()方法時,也會一直阻塞到有客戶端鏈接纔會返回,每一個客戶端鏈接過來後,服務端都會啓動一個線程去處理該客戶端的請求。

阻塞I/O通訊模型,它的兩點缺點:
1. 當客戶端多時,會建立大量的處理線程。且每一個線程都要佔用棧空間和一些CPU時間
2. 阻塞可能帶來頻繁的上下文切換,且大部分上下文切換多是無心義的。

 NIO的工做原理:

NIO經過Selector、Channel、和Buffer來實現非阻塞IO,NIO非阻塞的實現主要採用了Reactor(反應器)設計模式,這個設計模式與Observer設計模式相似,只不過Observer設計模式只能處理一個時間源,而Reactor設計模式能夠處理多個事件源。Channel是一個雙向的非阻塞通道,在通道的兩邊均可以進行數據的讀寫工做。Selector實現了用一個線程來管理多個通道(採用了複用與解複用的方式使得一個線程可以管理多個通道,便可以把多個流合併成爲一個流,或者把一個流分紅多個流的方式),它相似於一個觀察者。在實現時須要把Channel的IO事件(例如connect,read,write等)註冊給Selector。Selector內部實現原理爲:對全部註冊的Channel進行輪詢訪問,一旦輪詢到一個Channel有註冊的事件發生,例若有數據來了,它就經過傳回SelectionKey的方式來通知開發人員對Channel進行數據的讀或寫操做。這種經過輪詢的方式在處理多線程時不須要上下文的切換,而採用多線程的實現方式在線程之間切換須要上下文的切換,同時也須要進行壓棧與彈棧的操做,所以NIO具備較高的執行效率。
1. 由一個專門的線程來處理全部的 IO 事件,並負責分發。 
2. 事件驅動機制:事件到的時候觸發,而不是同步的去監視事件。 

Java NIO的服務端只需啓動一個專門的線程來處理全部的 IO 事件

相關文章
相關標籤/搜索