介紹下websocket:
webSocket協議本質上是一個基於tcp的協議;
建立一個websocket連接,大體的過程:
1.客戶端瀏覽器首先向服務器發起一個http請求,這個請求和平常的請求有什么不同呢?
多了一點附加頭信息:"upgrade:web Socket” 表明我這申請的是一個websocket的http請求;
2.服務器收到請求后,解析這些附加的頭信息,然后產生應答信息返回給客戶端,這樣,連接就建立了;
3.雙方就可以通過這個連接通道自由的信息傳遞,這個連接會一直存在,直到一方自動關閉連接;
客戶端到服務端: GET /demo HTTP/1.1 Host: example.com Connection: Upgrade Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Upgrade: WebSocket Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5 Origin: http://example.com [8-byte security key] 服務端到客戶端: HTTP/1.1 101 WebSocket Protocol Handshake Upgrade: WebSocket Connection: Upgrade WebSocket-Origin: http://example.com WebSocket-Location: ws://example.com/demo [16-byte hash response]
從客戶端到服務端請求的信息里面包含:‘Sec-webSocket-key1","Sec-WebSocket-key2"和“[8-byte security key]”這樣的信息;這是客戶端瀏覽器需要向服務端提供的握手信息,服務端解析這些頭信息,並且在握手的過程中依據這些信息生成一個16位的安全密鑰並返回給客戶端,以表明服務器端獲取了客戶端的請求;
大致步驟:
1. 逐個字符讀取 Sec-WebSocket-Key1 頭信息中的值,將數值型字符連接到一起放到一個臨時字符串里,同時統計所有空格的數量; 2. 將在第 1 步里生成的數字字符串轉換成一個整型數字,然后除以第 1 步里統計出來的空格數量,將得到的浮點數轉換成整數型; 3. 將第 2 步里生成的整型值轉換為符合網絡傳輸的網絡字節數組; 4. 對 Sec-WebSocket-Key2 頭信息同樣進行第 1 到第 3 步的操作,得到另外一個網絡字節數組; 5. 將 [8-byte security key] 和在第 3,第 4 步里生成的網絡字節數組合並成一個 16 字節的數組; 6. 對第 5 步生成的字節數組使用 MD5 算法生成一個哈希值,這個哈希值就作為安全密鑰返回給客戶端,以表明服務器端獲取了客戶端的請求,同意創建 WebSocket 連接
var wsServer = 'ws://localhost:8888/Demo'; //連接地址
var websocket = new WebSocket(wsServer); //建立連接
websocket.onopen = function (evt) { onOpen(evt) }; //4個事件
websocket.onclose = function (evt) { onClose(evt) };
websocket.onmessage = function (evt) { onMessage(evt) };
websocket.onerror = function (evt) { onError(evt) };
function onOpen(evt) {
console.log("Connected to WebSocket server.");
}
function onClose(evt) {
console.log("Disconnected");
}
function onMessage(evt) {
console.log('Retrieved data from server: ' + evt.data);
}
function onError(evt) {
console.log('Error occured: ' + evt.data);
}
瀏覽器的支持情況:
瀏覽器 支持情況 Chrome Supported in version 4+ Firefox Supported in version 4+ Internet Explorer Supported in version 10+ Opera Supported in version 10+ Safari Supported in version 5+
正文來了:基於websocket制作的簡單聊天系統;
client.html:
<style>
.kuang {
width: 600px;
min-height: 50px;
max-height: 296px;
border: 1px solid;
float: left;
display: block;
position: relative;
overflow-y: scroll;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="jumbotron bg-dark">
<h1 class="jumbotron-heading">WebSocket chat,歡迎使用:</h1>
</div>
<div class="input-group text-left">
<label>輸入用戶名:</label>
<input type="text" id="name" />
<button id="conn">連接</button>
<button id="close">斷開</button>
</div>
<div class="input-group text-muted">
<div class="kuang" id="mess"></div>
</div>
<hr class="featurette-divider">
<div class="input-group text-left">
<input type="text" class="value" id="value1" />
<button id="send">發送</button>
</div>
</div>
</div>
簡單的界面,大致效果就是這樣的:

然后實現邏輯代碼:
var ws = new WebSocket('ws://127.0.0.1:8082');
ws.onopen = function (e) {
console.log("連接服務器成功");
}
ws.onmessage = function (e) {
value1.removeAttribute("readOnly");
var time = new Date();
mess.innerHTML += time.toUTCString() + ":" + e.data + "<br>";
document.getElementById("send").onclick = function (e) {
ws.send(input.value + "說:" + value1.value);
value1.value = " ";
}
document.onkeydown = function (e) {
e = e || window.event;
if (e.keyCode == 13) {
document.getElementById("send").onclick();
return false;
}
}
}
ws.onclose = function (e) {
console.log("服務器關閉");
}
ws.onerror = function () {
console.log("連接出錯");
}
連接地址:ws://127.0.0.1:8082 那是哪里來的呢? (注意http請求則是寫成http://xxx,https請求則是https://xxx;ws當然是ws://xxx);
wbsocket只是客服端,地址當然是從我們的服務端給的呀;
服務端的搭建采用了一個這樣的庫:
var server = ws.createServer(function (conn) {
conn.on('text', function (str) {
})
conn.on("close", function (code, reason) {
console.log("關閉連接");
})
conn.on("error", function (code, reason) {
console.log("異常關閉");
});
}).listen(8082);
console.log("websocket連接完畢")
好了,websocket連接算是建立啦!
下面展示下具體代碼:
client.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="bootstrap-3.3.7-dist/css/bootstrap.min.css" />
<script src="jquery.min.js"></script>
<script src="bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
<style>
.kuang {
width: 600px;
min-height: 50px;
max-height: 296px;
border: 1px solid;
float: left;
display: block;
position: relative;
overflow-y: scroll;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="jumbotron bg-dark">
<h1 class="jumbotron-heading">WebSocket chat,歡迎使用:</h1>
</div>
<div class="input-group text-left">
<label>輸入用戶名:</label>
<input type="text" id="name" />
<button id="conn">連接</button>
<button id="close">斷開</button>
</div>
<div class="input-group text-muted">
<div class="kuang" id="mess"></div>
</div>
<hr class="featurette-divider">
<div class="input-group text-left">
<input type="text" class="value" id="value1" />
<button id="send">發送</button>
</div>
</div>
</div>
<script>
var input = document.getElementById("name");
var conn = document.getElementById("conn");
var close = document.getElementById("close");
var mess = document.getElementById("mess");
var value1 = document.getElementById("value1");
var pattern = /^[\u4e00-\u9fa5]{2,10}$/;
close.disabled = true;
if (window.WebSocket) {
conn.onclick = function () {
if (!pattern.test(input.value)) {
alert("名稱不能為空且必須為中文");
return;
}
var ws = new WebSocket('ws://127.0.0.1:8082');
conn.disabled = true;
close.disabled = false;
ws.onopen = function (e) {
console.log("連接服務器成功");
ws.send(input.value);
input.setAttribute("readOnly", 'true');
value1.setAttribute("readOnly", 'true');
}
ws.onmessage = function (e) {
value1.removeAttribute("readOnly");
var time = new Date();
mess.innerHTML += time.toUTCString() + ":" + e.data + "<br>";
document.getElementById("send").onclick = function (e) {
ws.send(input.value + "說:" + value1.value);
value1.value = " ";
}
document.onkeydown = function (e) {
e = e || window.event;
if (e.keyCode == 13) {
document.getElementById("send").onclick();
return false;
}
}
}
ws.onclose = function (e) {
console.log("服務器關閉");
}
ws.onerror = function () {
console.log("連接出錯");
}
close.onclick = function () {
ws.onclose();
ws.send(input.value + 'close' + "了連接");
input.removeAttribute("readOnly");
conn.disabled = false;
close.disabled = true;
}
}
}
</script>
</body>
</html>
server.js
var ws = require("nodejs-websocket");
console.log("開始建立連接...");
var str1 = null, str2 = null, clientReady = false, serverReady = false;
var a = [];
var server = ws.createServer(function (conn) {
conn.on('text', function (str) {
a.push(str);
if (!clientReady) {
if (a[0] === str) {
str1 = conn;
clientReady = true;
str1.sendText("歡迎你" + str);
}
} else if (!serverReady) {
if (str.indexOf('close') >= 0) {
a.splice(2,1);
clientReady = false;
str1=null;
return;
}
if (a[1] === str) {
str2 = conn;
serverReady = true;
str2.sendText("歡迎你" + str);
str1.sendText(str + "在線啦,你們可以聊天啦");
return;
}
} else if (clientReady && serverReady) {
str2.sendText(str);
str1.sendText(str);
if (str.indexOf('close') >= 0) {
a.splice(2, a.length);
var len = a.length;
for (var i = 0; i < len; i++) {
// 定位該元素位置
if (str.indexOf(a[i])>=0) {
a.splice(i,1);
if(i==0){
str1=str2;
}
serverReady = false;
str2=null;
return;
}
}
}
}
})
conn.on("close", function (code, reason) {
console.log("關閉連接");
clientReady = false;
serverReady = false;
})
conn.on("error", function (code, reason) {
console.log("異常關閉");
});
}).listen(8082);
console.log("websocket連接完畢")
實現雙人聊天,client.html開啟兩個窗口就行!
詳細代碼在github上:
https://github.com/sulishibaobei/websocket-
