內容:css
1.websocket介紹html
2.websocket原理前端
3.websocket實例node
參考:http://www.javashuo.com/article/p-nmcskqka-be.htmlgit
1.websocket介紹github
(1)什麼是WebSocketweb
WebSocket 是一種網絡通訊協議。RFC6455 定義了它的通訊標準。後端
WebSocket 是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。瀏覽器
另外基於多線程或多進程的服務器沒法適用於 WebSockets,由於它旨在打開鏈接,儘量快地處理請求,而後關閉鏈接。任何實際的 WebSockets 服務器端實現都須要一個異步服務器服務器
(2)websocket的特色
2.websocket原理
(1)websocket在服務端和客戶端
在客戶端,沒有必要爲 WebSockets 使用 JavaScript 庫。實現 WebSockets 的 Web 瀏覽器將經過 WebSockets 對象公開全部必需的客戶端功能(主要指支持 Html5 的瀏覽器)
而WebSocket 在服務端的實現很是豐富。Node.js、Java、C++、Python 等多種語言都有本身的解決方案
node中:
而Java 的 web 通常都依託於 servlet 容器(Tomcat、Jetty、Resin),此外Spring框架對 WebSocket 也提供了支持
(2)websocket核心原理
關於websocket:
ws
(若是加密,則爲wss
),服務器網址就是 URL底層協議包裝:
(3)HTTP 和 WebSocket 有什麼關係?
Websocket 實際上是一個新協議,跟 HTTP 協議基本沒有關係,只是爲了兼容現有瀏覽器的握手規範而已,也就是說它是 HTTP 協議上的一種補充
而HTTP2.0(將來推行,如今還未推行)中其實要實現全雙工通訊,故也有人說websocket最終將被HTTP2.0替代
(4)WebSocket屬性
WebSocket是前臺的東西,是HTML5帶的一種東西:
3.websocket實例
(1)原生websocket
雖然原生的websocket實現起來麻煩,寫起來麻煩,可是咱們仍是要對其有所瞭解
1 原生WebSocket: 2 i.net模塊 3 ii.流程 4 a.握手 5 C:version:1三、sec-websocket-key:xxxxx、sha1(key+mask)=>base64 6 S:101 Switching Protocols、sec-websocket-accept: base64 7 C <-> S 8 9 Client: 10 onopen 11 onmessage 12 onclose 13 14 Server: 15 net.createServer(sock=>{}); 16 sock.once('data', 握手); 17 sock.on('data', 數據請求); 18 sock.on('end'); 19 20 b.數據幀解析
原生websocket使用實例以下:
1 // 服務端 2 const http = require('http'); // HTTP 非原生Socket 3 const net = require('net'); // TCP 原生Socket 4 const crypto = require('crypto'); 5 6 /* 7 let server=http.createServer((req, res)=>{ 8 console.log('鏈接'); 9 }); 10 server.listen(8080); 11 */ 12 13 let server = net.createServer(sock => { 14 console.log('鏈接'); 15 16 //數據過來 — 握手只有一次 17 sock.once('data', function(data){ 18 console.log('hand shake start...'); 19 20 // 下面都是解析HTTP頭 21 let str = data.toString(); 22 let lines = str.split('\r\n'); 23 24 //捨棄第一行和最後兩行 25 lines = lines.slice(1, lines.length - 2); 26 //切開headers中的每一項key-value數據 27 let headers = {}; 28 lines.forEach(function(line) { 29 let [key, val] = line.split(': '); 30 headers[key.toLowerCase()] = val; 31 }); 32 console.log(headers); 33 34 if (headers['upgrade'] !== 'websocket') { 35 console.log('其餘協議: ', headers['upgrade']); 36 sock.end(); 37 } else if (headers['sec-websocket-version'] !== '13') { 38 console.log('版本不對', headers['sec-websocket-version']); 39 sock.end(); 40 } else { 41 let key = headers['sec-websocket-key']; 42 let mask = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; 43 44 //sha1(key+mask)->base64=>client 45 let hash = crypto.createHash('sha1'); 46 hash.update(key + mask); 47 let key2 = hash.digest('base64'); 48 sock.write(`HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ${key2}\r\n\r\n`); 49 50 console.log('hand shake end'); 51 52 //真正的數據 53 sock.on('data', data => { 54 console.log('有數據'); 55 console.log(data); 56 }); 57 } 58 }); 59 60 //斷開了 61 sock.on('end', () => { 62 console.log('客戶端已斷開'); 63 }); 64 }); 65 server.listen(8080);
1 // 客戶端 2 <!DOCTYPE html> 3 <html> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 <script> 8 let sock=new WebSocket('ws://localhost:8080/'); 9 10 // 原生websocket中沒有sock.emit 本身用sock.send封裝一個sock.emit: 11 sock.emit=function (name, ...args){ 12 alert(JSON.stringify({name, data: [...args]})); 13 sock.send(JSON.stringify({name, data: [...args]})); 14 }; 15 16 // 連上了 17 sock.onopen=function (){ 18 alert('鏈接上了'); 19 20 sock.emit('msg', 12, 5); 21 }; 22 23 // 有數據 24 sock.onmessage=function (){ 25 alert('有消息過來'); 26 }; 27 28 // 斷開了 29 sock.onclose=function (){ 30 alert('斷了'); 31 }; 32 </script> 33 </head> 34 <body> 35 36 </body> 37 </html>
(2)socket.io實現websocket
實現套路:
1 // 服務端: 2 const http = require('http') 3 const io = require('socket.io') 4 5 let httpServer = http.createServer(function (req, res) { 6 7 }) 8 httpServer.listen(8080) 9 10 let wsServer = io.listen(httpServer) 11 12 wsServer.on('connection', function (sock) { 13 // sock.emit() --> 發送 14 // sock.on() --> 接收 15 // sock.on('connection') --> 開始鏈接 16 // sock.on('disconnect') --> 斷開鏈接 17 })
1 // 客戶端: 2 let sock = io.connect('ws://localhost:8080/') 3 4 sock.emit() // 發送 5 sock.on() // 接收 6 sock.on('connect') // 開始鏈接 7 sock.on('disconnect') // 斷開鏈接
(3)socket.io實現聊天室
1 // 前端代碼: 2 <!-- author: wyb --> 3 <!DOCTYPE html> 4 <html lang="en"> 5 <head> 6 <meta charset="UTF-8"> 7 <meta name="viewport" content="width=device-width, initial-scale=1"> 8 <title>聊天室</title> 9 <style> 10 *{ 11 margin: 0; 12 padding: 0; 13 } 14 .container{ 15 width: 93%; 16 margin: 0 auto; 17 padding: 15px; 18 } 19 .err_box{ 20 width: 100%; 21 height: 20px; 22 line-height: 20px; 23 text-align: center; 24 color: red; 25 display: none; 26 } 27 #u1{ 28 width: 100%; 29 height: 360px; 30 border: 1px solid black; 31 overflow: auto; 32 margin: 15px 0; 33 } 34 #u1 li.me{ 35 color: green; 36 } 37 #form{ 38 width: 100%; 39 text-align: center; 40 margin: 15px 0; 41 } 42 #form textarea{ 43 width: 100%; 44 min-height: 130px; 45 margin: 10px 0; 46 } 47 </style> 48 <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css" 49 integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous"> 50 <script src="http://localhost:8080/socket.io/socket.io.js"></script> 51 <script> 52 let sock = io.connect('ws://localhost:8080/') 53 54 sock.on('connect', function () { 55 console.log('已鏈接') 56 document.querySelector('.err_box').style.display = "none" 57 }) 58 sock.on('disconnect', function () { 59 console.log('已斷開') 60 document.querySelector('.err_box').style.display = "block" 61 }) 62 63 window.onload = function(){ 64 let oTxt = document.querySelector('#txt1') 65 let oBtn = document.querySelector('#btn1') 66 let oUl = document.querySelector('#u1') 67 68 oBtn.onclick = function () { 69 sock.emit('msg', oTxt.value) 70 71 // 把本身輸入的信息添加到本身頁面中並將顏色設置爲綠色 72 let oLi = document.createElement('li') 73 oLi.innerHTML = oTxt.value 74 oLi.className = 'me' 75 76 oTxt.value = '' 77 oUl.appendChild(oLi) 78 } 79 80 sock.on('msg', function (str) { 81 let oLi = document.createElement('li') 82 oLi.innerHTML = str 83 oUl.appendChild(oLi) 84 }) 85 86 } 87 88 // 聊天室 89 // sock.emit() 90 // sock.on() 91 92 </script> 93 94 </head> 95 <body> 96 97 <div class="container"> 98 <div class="err_box">沒法鏈接到服務器,請檢查網絡</div> 99 <ul id="u1"></ul> 100 <form class="pure-form" id="form"> 101 <textarea class="pure-input-1" id="txt1" name="" placeholder="請輸入聊天內容"></textarea> <br> 102 <input type="button" value="發送" id="btn1" class="pure-button pure-button-primary"> 103 </form> 104 </div> 105 </body> 106 </html>
1 // 後端代碼 2 const http = require('http') 3 const io = require('socket.io') 4 5 let httpServer = http.createServer(function (req, res) { 6 7 }) 8 httpServer.listen(8080) 9 10 let wsServer = io.listen(httpServer) 11 12 let aSock = [] 13 wsServer.on('connection', function (sock) { 14 aSock.push(sock) 15 console.log(aSock.length) 16 17 // sock.emit() 18 sock.on('msg', function (str) { 19 aSock.forEach(function (s) { 20 if(s!==sock){ 21 s.emit('msg', str) 22 } 23 }) 24 }) 25 26 // 斷開鏈接 27 sock.on('disconnect', function () { 28 let n = aSock.indexOf(sock) 29 30 if(n!==-1){ 31 aSock.splice(n, 1) 32 } 33 }) 34 }) 35 36 // 每隔0.5秒打印鏈接數 37 setInterval(function () { 38 console.log(aSock.length) 39 }, 500)
使用方法:啓動服務器後,在瀏覽器中打開多個前端頁面便可開始使用