參考
http://www.bitscn.com/school/HTMLCSS/201402/194940.htmljavascript
WebSockets 定義了一個全雙工的通訊信道,只需Web上的一個 Socket便可進行通訊,能減小沒必要要的網絡流量並下降網絡延遲。php
大部分是圍繞輪詢和其餘服務器端推送技術展開的,其中最著名的是Comet。Comet技術可讓服務器主動以異步方式向客戶端推送數據。html
Comet是服務器端的推送,實現Comet有兩種方式, 長輪詢和流。html5
長輪詢
長輪詢是短輪詢的一個翻版, 短輪詢是瀏覽器定時向服務端發送請求看看有沒有數據更新。長輪詢則是瀏覽器發送了一個請求以後, 服務端一直保持鏈接打開狀態,直到有數據能夠相應,發送完數據後關閉鏈接。以後瀏覽器再發起請求。java
Http流
流不一樣於輪詢 流在頁面整個生命週期只內只有一個鏈接, 瀏覽器向服務器發送請求, 而服務器保持鏈接打開, 而後週期性的向瀏覽器發送數據。node
參考
http://www.cnblogs.com/wintersun/p/3735160.html
http://www.cnblogs.com/goody9807/p/4257192.html
http://www.w3school.com.cn/html5/html_5_serversentevents.aspweb
簡單說,所謂SSE,就是瀏覽器向服務器發送一個HTTP請求,而後服務器不斷單向地向瀏覽器推送「信息」(message)。這種信息在格式上很簡單,就是「信息」加上前綴「data: 」,而後以「\n\n」結尾。
(對於多行數據 只有最後一行是\n\n 其餘是\n)
好比這樣跨域
$ curl http://example.com/dates data: 1394572346452 data: 1394572347457 data: 1394572348463
SSE對象有三個事件:open、error和message瀏覽器
SSE是單向通道, 只能服務端向瀏覽器發送數據
使用SSE, 瀏覽器不用頻繁的發送請求, 實際上在Network中就看不到請求卻能夠獲得服務端的數據安全
var source = new EventSource('sse.php'); source.onmessage = function(e){ console.log(e.data); };
服務端
<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); while(true){ echo "data: start\n"; echo "data:".date("Y-m-d H:i:s")."\n\n"; // @ob_flush(); // @flush(); ob_flush(); flush(); sleep(1); } ?>
PS SSE有跨域限制
接下來用NodeJS 來實現SSE
以前提到了SSE不能跨域, 所以咱們的這個NodeJS服務器不單單要完成SSE的處理, 還要有完成頁面的請求
http://www.cnblogs.com/wintersun/p/3735160.html
var http = require("http"), fs = require("fs"); var port = parseInt( process.argv[2] || 1234 ); http.createServer(function(request, response){ console.log("Client connected:" + request.url); if(request.url!="/sse"){ fs.readFile("sseNode.html", function(err,file){ response.writeHead(200, { 'Content-Type': 'text/html' }); var s = file.toString(); //file is a buffer s = s.replace("basic_sse.php","sse"); response.end(s); }); return; } //Below is to handle SSE request. It never returns. response.writeHead(200, { "Content-Type": "text/event-stream" }); var timer = setInterval(function(){ var content = "data:" + new Date().toISOString() + "\n\n"; var b = response.write(content); if(!b)console.log("Data got queued in memory (content=" + content + ")"); else console.log("Flushed! (content=" + content + ")"); },1000); request.connection.on("close", function(){ response.end(); clearInterval(timer); console.log("Client closed connection. Aborting."); }); }).listen(port); console.log("Server running at http://localhost:" + port);
爲了創建WebSocket通訊,客戶端和服務器在初始握手時,將HTTP協議升級到WebSocket協議。一旦鏈接創建成功,就能夠在全雙工模式下在客戶端和服務器之間來回傳送WebSocket消息。
ws://和wss://前綴分別表示WebSocket鏈接和安全的WebSocket鏈接。
事件 | 處理程序 | 說明 |
---|---|---|
open | Socket.onopen | z此事件發生在套接字創建鏈接。 |
message | Socket.onmessage | 此事件發生時,客戶端收到來自服務器的數據。 |
error | Socket.onerror | 此事件發生時有任何通訊錯誤。 |
close | Socket.onclose | 此事件發生在鏈接關閉。 |
須要知道的是socket都是創建在一個HTTP服務的基礎上的,所以建立一個socket以前須要建立一個HTTP
一個簡單的例子
服務端部分(NodeJS)
來自http://my.oschina.net/fuckboogie/blog/201615
var http = require('http'); var io = require('socket.io'); var yourserver = http.createServer(function (request, response) { response.writeHead(250, { 'Content-Type': 'text/html' }); response.end('Your WebSocket server is running'); }).listen(1234); var yoursocket = io.listen(yourserver); yoursocket.on('connection', function (client) { client.on('message', function (data) { console.log('Client Message: ', data); var current = new Date().getTime(); client.emit('YourMessageResponse', data + '->' + current); }); client.on('disconnect', function () { console.log('Your Client disconnected'); }); });
客戶端部分
客戶端須要引入socket.io.js 這個文件纔有io對象, 這個文件在node_modules的socket.io中 以前咱們啓動了一個端口是1234的服務器 服務器會自動尋找這個文件
<script src='http://localhost:1234/socket.io/socket.io.js'></script>
var yoursocket = null; yoursocket = io.connect('http://localhost:1234'); yoursocket.on('connect', function() { console.log('You are connected to Server'); yoursocket.send(new Date()); }); yoursocket.on('YourMessageResponse', function(data) { console.log('Server Response: ' + data + '<br />'); setTimeout(function(){ yoursocket.send(data + new Date()); },1000); }); yoursocket.on('disconnect', function() { console.log('You are disconnected from Server<br />'); });
不用socket.io 就用W3C的socket
參考
http://codular.com/node-web-sockets
服務端
var WebSocketServer = require('websocket').server; var http = require('http'); var server = http.createServer(function(request, response) { console.log((new Date()) + ' Received request for ' + request.url); response.writeHead(404); response.end(); }); server.listen(8080, function() { console.log((new Date()) + ' Server is listening on port 8080'); }); wsServer = new WebSocketServer({ httpServer: server, // You should not use autoAcceptConnections for production // applications, as it defeats all standard cross-origin protection // facilities built into the protocol and the browser. You should // *always* verify the connection's origin and decide whether or not // to accept it. autoAcceptConnections: false }); function originIsAllowed(origin) { // put logic here to detect whether the specified origin is allowed. return true; } wsServer.on('request', function(request) { if (!originIsAllowed(request.origin)) { // Make sure we only accept requests from an allowed origin request.reject(); console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.'); return; } var connection = request.accept('echo-protocol', request.origin); console.log((new Date()) + ' Connection accepted.'); connection.sendUTF('first message from server'); connection.on('message', function(message) { if (message.type === 'utf8') { console.log('Received Message: ' + message.utf8Data); connection.sendUTF(message.utf8Data); } else if (message.type === 'binary') { console.log('Received Binary Message of ' + message.binaryData.length + ' bytes'); connection.sendBytes(message.binaryData); } }); connection.on('close', function(reasonCode, description) { console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.'); }); });
客戶端(原生的websocket)
var soc = null; var websocket = new WebSocket('ws://localhost:8080','echo-protocol'); websocket.onopen = function(e){ console.log(e); // setInterval(function(){ // websocket.send('hehe') // }, 1000); } websocket.onmessage = function(e){ console.log(e); setTimeout(function(){ websocket.send('client'); },1000) }