通过Socket.IO与nodeJs实现即时消息推送

http://book.mixu.net/ch13.html


很早开始就想用WebSocket完成即时消息推送功能。之前本打算用WebSocket + C#实现的,结果人上了年纪变笨了,弄了一天也没弄好 ⊙﹏⊙
今天参考了几篇资料,终于搞定了一个Socket.IO结合nodeJs的Demo。
用Socket.IO有个很大的好处就是开发者不需要去关心浏览器差异。Chrome下会用WebSocket,如果是用的IE它就会轮询。
nodeJs的环境搭建之类的知识这里就不提了,暂提供一个入门的文章Node入门 ,Socket.IO的官网

再推荐一篇不错的外文:Comet and Socket.io deployment


后台代码 server.js

复制代码
var fs = require('fs'),
    http = require('http'),
    sio = require('socket.io');

var server = http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-type': 'text/html' });
    res.end(fs.readFileSync('./index.htm'));
});
server.listen(8888, function() {
    console.log('Server listening at http://localhost:8888/');
});
// Attach the socket.io server
io = sio.listen(server);
// store messages
var messages = [];
// Define a message handler
io.sockets.on('connection', function(socket) {
    socket.on('message', function(msg) {
        console.log('Received: ', msg);
        messages.push(msg);
        socket.broadcast.emit('message', msg);
    });
    // send messages to new clients
    messages.forEach(function(msg) {
        socket.send(msg);
    })
});
复制代码

前台代码 index.htm

复制代码
<html>
<head>
  <style type="text/css">
    #messages { padding: 0px; list-style-type: none;}
    #messages li { padding: 2px 0px; border-bottom: 1px solid #ccc; }
  style>
  <script src="http://code.jquery.com/jquery-1.7.1.min.js">script>
  <script src="/socket.io/socket.io.js">script>
  <script>
      $(function() {
          var socket = io.connect();
          socket.on('connect', function() {
              socket.on('message', function(message) {
                  $('#messages').append($('
  • ').text(message)); }); socket.on('disconnect', function() { $('#messages').append('
  • Disconnected
  • '); }); }); var el = $('#chatmsg'); $('#chatmsg').keypress(function(e) { if (e.which == 13) { e.preventDefault(); socket.send(el.val()); $('#messages').append($('
  • ').text(el.val())); el.val(''); } }); }); script> head> <body> <ul id="messages">ul> <hr> <input type="text" id="chatmsg"> body> html>
    复制代码

    运行方法

    1. 在命令行输入 node server.js 打开服务器
    2. 打开两个页面,分别输入地址 http://localhost:8888/

    注意一点:在index.htm中引用了一个文件"/socket.io/socket.io.js",这个是由后台的Socket.IO模块自动提供的,我们不需要去管它。

    在Socket.IO官网给的例子里,没有说明这里点,害得我乱折腾一天也没明白,直到看到上面的那篇外文才明白。。。

    这个小Demo连聊天室都算不上,只是完成了即时信息推送而已。接下来有时间了再继续完善吧!


    In this chapter, I:
    • present an overview of the techniques to implement Comet
    • introduce Socket.io and a basic application
    • discuss the complexities of real-world deployment with Socket.io

    So... do you want to build a chat? Or a real-time multiplayer game?

    In order to build a (soft-) real-time app, you need the ability to update information quickly within the end user's browser.

    HTTP was not designed to support full two-way communication. However, there are multiple ways in which the client can receive information in real time or almost real time:

    Techniques to implement Comet

    Periodic polling. Essentially, you ask the server whether it has new data every n seconds, and idle meanwhile:

    Client: Are we there yet?
    Server: No
    Client: [Wait a few seconds]
    Client: Are we there yet?
    Server: No
    Client: [Wait a few seconds]
    ... (repeat this a lot)
    Client: Are we there yet?
    Server: Yes. Here is a message for you.
    

    The problem with periodic polling is that: 1) it tends to generate a lot of requests and 2) it's not instant - if messages arrive during the time the client is waiting, then those will only be received later.

    Long polling. This is similar to periodic polling, except that the server does not return the response immediately. Instead, the response is kept in a pending state until either new data arrives, or the request times out in the browser. Compared to periodic polling, the advantage here is that clients need to make fewer requests (requests are only made again if there is data) and that there is no "idle" timeout between making requests: a new request is made immediately after receiving data.

    Client: Are we there yet?
    Server: [Wait for ~30 seconds]
    Server: No
    Client: Are we there yet?
    Server: Yes. Here is a message for you.
    

    This approach is slightly better than periodic polling, since messages can be delivered immediately as long as a pending request exists. The server holds on to the request until the timeout triggers or a new message is available, so there will be fewer requests.

    However, if you need to send a message to the server from the client while a long polling request is ongoing, a second request has to be made back to the server since the data cannot be sent via the existing (HTTP) request.

    Sockets / long-lived connections. WebSockets (and other transports with socket semantics) improve on this further. The client connects once, and then a permanent TCP connection is maintained. Messages can be passed in both ways through this single request. As a conversation:

    Client: Are we there yet?
    Server: [Wait for until we're there]
    Server: Yes. Here is a message for you.
    

    If the client needs to send a message to the server, it can send it through the existing connection rather than through a separate request. This efficient and fast, but Websockets are only available in newer, better browsers.

    Socket.io

    As you can see above, there are several different ways to implement Comet.

    Socket.io offers several different transports:

    • Long polling: XHR-polling (using XMLHttpRequest), JSONP polling (using JSON with padding), HTMLFile (forever Iframe for IE)
    • Sockets / long-lived connections: Flash sockets (Websockets over plain TCP sockets using Flash) and Websockets

    Ideally, we would like to use the most efficient transport (Websockets) - but fall back to other transports on older browsers. This is what Socket.io does.

    Writing a basic application

    I almost left this part out, since I can't really do justice to Socket.io in one section of a full chapter. But here it is: a simple example using Socket.io. In this example, we will write simple echo server that receives messages from the browser and echoes them back.

    Let's start with a package.json:

    {
      "name": "siosample",
      "description": "Simple Socket.io app",
      "version": "0.0.1",
      "main": "server.js",
      "dependencies": {
        "socket.io": "0.8.x"
      },
      "private": "true"
    }

    This allows us to install the app with all the dependencies using npm install.

    In server.js:

    var fs = require('fs'),
        http = require('http'),
        sio = require('socket.io');
    
    var server = http.createServer(function(req, res) {
      res.writeHead(200, { 'Content-type': 'text/html'});
      res.end(fs.readFileSync('./index.html'));
    });
    server.listen(8000, function() {
      console.log('Server listening at http://localhost:8000/');
    });
    // Attach the socket.io server
    io = sio.listen(server);
    // store messages
    var messages = [];
    // Define a message handler
    io.sockets.on('connection', function (socket) {
      socket.on('message', function (msg) {
        console.log('Received: ', msg);
        messages.push(msg);
        socket.broadcast.emit('message', msg);
      });
      // send messages to new clients
      messages.forEach(function(msg) {
        socket.send(msg);
      })
    });

    First we start a regular HTTP server that always respondes with the content of "./index.html". Then the Socket.io server is attached to that server, allowing Socket.io to respond to requests directed towards it on port 8000.

    Socket.io follows the basic EventEmitter pattern: messages and connection state changes become events on socket. On "connection", we add a message handler that echoes the message back and broadcasts it to all other connected clients. Additionally, messages are stored in memory in an array, which is sent back to new clients so that the can see previous messages.

    Next, let's write the client page (index.html):

    
    
       type="text/css">
        #messages { padding: 0px; list-style-type: none;}
        #messages li { padding: 2px 0px; border-bottom: 1px solid #ccc; }
      
       src="http://code.jquery.com/jquery-1.7.1.min.js">
       src="/socket.io/socket.io.js">
      
    
    
      id="messages">
     
    type="text" id="chatmsg">

    BTW, "/socket.io/socket.io.js" is served by Socket.io, so you don't need to have a file placed there.

    To start the server, run node server.js and point your browser tohttp://localhost:8000/. To chat between two users, open a second tab to the same address.

    Additional features

    Check out the Socket.io website (and Github for server, client) for more information on using Socket.io.

    There are two more advanced examples on Github.

    I'm going to focus on deployment, which has not been covered in depth.

    Deploying Socket.io: avoiding the problems

    As you can see above, using Socket.io is fairly simple. However, there are several issues related to deploying an application using Socket.io which need to be addressed.

    Same origin policy, CORS and JSONP

    The same origin policy is a security measure built in to web browsers. It restricts access to the DOM, Javascript HTTP requests and cookies.

    In short, the policy is that the protocol (http vs https), host (www.example.com vs example.com) and port (default vs e.g. :8000) of the request must match exactly.

    Requests that are made from Javascript to a different host, port or protocol are not allowed, except via two mechanisms:

    Cross-Origin Resource Sharing is a way for the server to tell the browser that a request that violates the same origin policy is allowed. This is done by adding a HTTP header (Access-Control-Allow-Origin:) and applies to requests made from Javascript.

    JSONP, or JSON with padding, is an alternative technique, which relies on the fact that the

    你可能感兴趣的:(通过Socket.IO与nodeJs实现即时消息推送)