javaScript
,HTML
,CSS
.Dom
操做EventLoop
和渲染機制IM
以及超大型高併發網站應用等,例如B站
)在使用某個技術的時候,必定要去追尋原理和底層的實現,久而久之堅持,只要自身底層的基礎紮實,不管技術怎麼變化,學習起來都不會太累,總的來講就是拒絕5分鐘技術
url
地址,到顯示頁面發生了什麼出發:TCP
連接之上TCP
呢TCP三次握手的過程以下:
SYN
報文給服務器端,進入SYN_SEND
狀態。SYN
報文,迴應一個SYN
(SEQ=y)ACK(ACK=x+1)報文,進入SYN_RECV狀態。如圖所示:
TCP
的四次揮手:
注意:FIN的接收也做爲一個文件結束符(end-of-file)傳遞給接收端應用進程,放在已排隊等候該應用進程接收的任何其餘數據以後,由於,FIN的接收意味着接收端應用進程在相應鏈接上再無額外數據可接收。css
既然每一個方向都須要一個FIN和一個ACK,所以一般須要4個分節。html
特別提示:SYN
報文用來通知,FIN
報文是用來同步的
以上就是面試官常問的三次握手,四次揮手,可是這不只僅面試題,上面僅僅答到了一點皮毛,學習這些是爲了讓咱們後續方便了解他的優缺點。
TCP
鏈接創建後,咱們能夠有多種協議的方式通訊交換數據:http 1.0
Http 1.0
的致命缺點,就是沒法複用TCP
鏈接和並行發送請求,這樣每次一個請求都須要三次握手,並且其實創建鏈接和釋放鏈接的這個過程是最耗時的,傳輸數據相反卻不那麼耗時。還有本地時間被修改致使響應頭expires
的緩存機制失效的問題~(後面會詳細講)
Http 1.1
,這也是技術的發展必然結果~Http 1.1
出現,繼承了Http1.0
的優勢,也克服了它的缺點,出現了keep-alive
這個頭部字段,它表示會在創建TCP
鏈接後,完成首次的請求,並不會馬上斷開TCP
鏈接,而是保持這個鏈接狀態~進而能夠複用這個通道Http 1.1
而且支持請求管道化,「並行」發送請求,可是這個並行,也不是真正意義上的並行,而是可讓咱們把先進先出隊列從客戶端(請求隊列)遷移到服務端(響應隊列)例如:客戶端同時發了兩個請求分別來獲取html和css,假如說服務器的css資源先準備就緒,服務器也會先發送html再發送css。
B站
首頁,就有keep-alive
,由於他們也有IM
的成分在裏面。須要大量複用TCP
鏈接~HTTP1.1
好像仍是沒法解決隊頭阻塞的問題實際上,現階段的瀏覽器廠商採起了另一種作法,它容許咱們打開多個TCP的會話。也就是說,上圖咱們看到的並行,實際上是不一樣的TCP鏈接上的HTTP請求和響應。這也就是咱們所熟悉的瀏覽器對同域下並行加載6~8個資源的限制。而這,纔是真正的並行!
Http 1.1
的致命缺點:
咱們也能夠用
dns-prefetch和 preconnect tcp
來優化~
<link rel="preconnect" href="//example.com" crossorigin> <link rel="dns=prefetch" href="//example.com">
Tip
: webpack
能夠作任何事情,這些均可以用插件實現Http 2.0
Demo
的性能對比:
Http
的那些致命缺陷,並無徹底解決,因而有了https
,也是目前應用最廣的協議之一HTTP+ 加密 + 認證 + 完整性保護 =HTTPS
?由於頗有可能並非和本來預想的通訊方在實際通訊。而且還須要考慮到接收到的報文在通訊途中已經遭到篡改這一可能性。前端
不加密的重要內容被
wireshark
這類工具抓到包,後果很嚴重~
一般,HTTP 直接和 TCP 通訊。java
加密和解密都會用到密鑰。沒有密鑰就沒法對密碼解密,反過來講,任何人只要持有密鑰就能解密了。若是密鑰被攻擊者得到,那加密也就失去了意義。
Https
加密篇幅太長,這篇文章寫得很好,你們能夠去看看。HTTPS
雖好,非對稱加密雖好,可是不要濫用針對速度變慢這一問題,並無根本性的解決方案,咱們會使用 SSL 加速器這種(專用服務器)硬件來改善該問題。該硬件爲 SSL 通訊專用硬件,相對軟件來說,可以提升數倍 SSL 的計算速度。僅在 SSL 處理時發揮 SSL加速器的功效,以分擔負載。react
其中一個緣由是,由於與純文本通訊相比,加密通訊會消耗更多的 CPU 及內存資源。若是每次通訊都加密,會消耗至關多的資源,平攤到一臺計算機上時,可以處理的請求數量一定也會隨之減小。webpack
特別是每當那些訪問量較多的 Web 網站在進行加密處理時,它們所承擔着的負載不容小覷。在進行加密處理時,並不是對全部內容都進行加密處理,而是僅在那些須要信息隱藏時纔會加密,以節約資源。git
要進行 HTTPS 通訊,證書是必不可少的。而使用的證書必須向認證機構(CA)購買。證書價格可能會根據不一樣的認證機構略有不一樣。一般,一年的受權須要數萬日元(如今一萬日元大約摺合 600 人民幣)。那些購買證書並不合算的服務以及一些我的網站,可能只會選擇採用HTTP 的通訊方式。github
所謂響應頭,請求頭,其實均可以本身添加字段,只要先後端給對應的處理機制便可
Node.js
代碼實現響應頭的設置if (config.cache.expires) { res.setHeader("expries", new Date(Date.now() + (config.cache.maxAge * 1000))) } if (config.cache.lastModified) { res.setHeader("last-modified", stat.mtime.toUTCString()) } if (config.cache.etag) { res.setHeader('Etag', etagFn(stat)) } }
Node.js
靜態資源服務器,https://github.com/JinJieTan/...,歡迎 star
~websocket
協議開始:
傳統的協議沒法服務端主動
push
數據,因而有了這些騷操做:
webSocket
.webSockets
的目標是在一個單獨的持久鏈接上提供全雙工、雙向通訊。在Javascript建立了Web Socket以後,會有一個HTTP請求發送到瀏覽器以發起鏈接。在取得服務器響應後,創建的鏈接會將HTTP升級從HTTP協議交換爲WebSocket協議。webSocket
原理: 在TCP
鏈接第一次握手的時候,升級爲ws
協議。後面的數據交互都複用這個TCP
通道。const ws = new WebSocket('ws://localhost:8080'); ws.onopen = function () { ws.send('123') console.log('open') } ws.onmessage = function () { console.log('onmessage') } ws.onerror = function () { console.log('onerror') } ws.onclose = function () { console.log('onclose') }
Node.js
語言實現const express = require('express') const { Server } = require("ws"); const app = express() const wsServer = new Server({ port: 8080 }) wsServer.on('connection', (ws) => { ws.onopen = function () { console.log('open') } ws.onmessage = function (data) { console.log(data) ws.send('234') console.log('onmessage' + data) } ws.onerror = function () { console.log('onerror') } ws.onclose = function () { console.log('onclose') } }); app.listen(8000, (err) => { if (!err) { console.log('監聽OK') } else { console.log('監聽失敗') } })
webSocket
的報文格式有一些不同:![圖片上傳中...]web
客戶端和服務端進行Websocket消息傳遞是這樣的:面試
ping
andpong
Go
實現:package main import ( "net/http" "time" "github.com/gorilla/websocket" ) var ( //完成握手操做 upgrade = websocket.Upgrader{ //容許跨域(通常來說,websocket都是獨立部署的) CheckOrigin:func(r *http.Request) bool { return true }, } ) func wsHandler(w http.ResponseWriter, r *http.Request) { var ( conn *websocket.Conn err error data []byte ) //服務端對客戶端的http請求(升級爲websocket協議)進行應答,應答以後,協議升級爲websocket,http創建鏈接時的tcp三次握手將保持。 if conn, err = upgrade.Upgrade(w, r, nil); err != nil { return } //啓動一個協程,每隔5s向客戶端發送一次心跳消息 go func() { var ( err error ) for { if err = conn.WriteMessage(websocket.TextMessage, []byte("heartbeat")); err != nil { return } time.Sleep(5 * time.Second) } }() //獲得websocket的長連接以後,就能夠對客戶端傳遞的數據進行操做了 for { //經過websocket長連接讀到的數據能夠是text文本數據,也能夠是二進制Binary if _, data, err = conn.ReadMessage(); err != nil { goto ERR } if err = conn.WriteMessage(websocket.TextMessage, data); err != nil { goto ERR } } ERR: //出錯以後,關閉socket鏈接 conn.Close() } func main() { http.HandleFunc("/ws", wsHandler) http.ListenAndServe("0.0.0.0:7777", nil) }
Node.js
實現):this.heartTimer = setInterval(() => { if (this.heartbeatLoss < MAXLOSSTIMES) { events.emit('network', 'sendHeart'); this.heartbeatLoss += 1; this.phoneLoss += 1; } else { events.emit('network', 'offline'); this.stop(); } if (this.phoneLoss > MAXLOSSTIMES) { this.PhoneLive = false; events.emit('network', 'phoneDisconnect'); } }, 5000);
new Socket
開始:SDK
接入,可是逼格高些仍是本身重寫比較好。IM
桌面應用開發的~const {Socket} = require('net') const tcp = new Socket() tcp.setKeepAlive(true); tcp.setNoDelay(true); //保持底層tcp連接不斷,長鏈接 指定對應域名端口號連接 tcp.connect(80,166.166.0.0) 創建鏈接後 根據後端傳送的數據類型 使用對應不一樣的解析 readUInt8 readUInt16LE readUInt32LE readIntLE等處理後獲得myBuf const myBuf = buffer.slice(start);//從對應的指針開始的位置截取buffer const header = myBuf.slice(headstart,headend)//截取對應的頭部buffer const body = JSON.parse(myBuf.slice(headend-headstart,bodylength).tostring()) //精確截取數據體的buffer,而且轉化成js對象
即時通信強烈推薦使用Golang
,GRPC
,Prob
傳輸數據。
webpack-electron-react-websocket
的Demo, https://github.com/JinJieTan/... 以爲寫得不錯,能夠點個贊支持下,文章也借鑑了一下其餘大佬的文章,可是地址都貼上來了~ 歡迎gitHub
點個star
哦~