• SSE && WebSockets


    SSE && WebSockets

    参考
    http://www.bitscn.com/school/HTMLCSS/201402/194940.html

    WebSockets 定义了一个全双工的通信信道,只需Web上的一个 Socket即可进行通信,能减少不必要的网络流量并降低网络延迟。

    大部分是围绕轮询和其他服务器端推送技术展开的,其中最著名的是Comet。Comet技术可以让服务器主动以异步方式向客户端推送数据。

    Comet

    Comet是服务器端的推送,实现Comet有两种方式, 长轮询和流。

    • 长轮询
      长轮询是短轮询的一个翻版, 短轮询是浏览器定时向服务端发送请求看看有没有数据更新。长轮询则是浏览器发送了一个请求之后, 服务端一直保持连接打开状态,直到有数据可以相应,发送完数据后关闭连接。之后浏览器再发起请求。

    • Http流
      流不同于轮询 流在页面整个生命周期只内只有一个连接, 浏览器向服务器发送请求, 而服务器保持连接打开, 然后周期性的向浏览器发送数据。

    SSE 服务器发送事件

    参考
    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.asp

    简单说,所谓SSE,就是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送“信息”(message)。这种信息在格式上很简单,就是“信息”加上前缀“data: ”,然后以“ ”结尾。
    (对于多行数据 只有最后一行是 其他是 )
    比如这样

    $ 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
    ";
      echo "data:".date("Y-m-d H:i:s")."
    
    ";
      // @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() + "
    
    ";
        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);
    
    

    WebScockets

    为了建立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)
        }
    
  • 相关阅读:
    java中源代码和lib库中有包名和类名都相同的类(转)
    Python 入门之基本数据类型
    Python 学习经历分享
    String 与不可变对象
    String 的常用操作
    Java 中的国际化
    接口和工厂设计模式
    抽象类和模板设计模式
    Java中的访问控制权限
    Java 中类的初始化过程
  • 原文地址:https://www.cnblogs.com/cart55free99/p/4782428.html
Copyright © 2020-2023  润新知