1. 程式人生 > >通過Socket.IO與nodeJs實現即時訊息推送

通過Socket.IO與nodeJs實現即時訊息推送

很早開始就想用WebSocket完成即時訊息推送功能。之前本打算用WebSocket + C#實現的,結果人上了年紀變笨了,弄了一天也沒弄好 ⊙﹏⊙
今天參考了幾篇資料,終於搞定了一個Socket.IO結合nodeJs的Demo。
用Socket.IO有個很大的好處就是開發者不需要去關心瀏覽器差異。Chrome下會用WebSocket,如果是用的IE它就會輪詢。
nodeJs的環境搭建之類的知識這裡就不提了,暫提供一個入門的文章Node入門 ,Socket.IO的官網

後臺程式碼 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($('<li></li>').text(message));
              });
              socket.on('disconnect', function() {
                  $('#messages').append('<li>Disconnected</li>');
              });
          });

          var el = $('#chatmsg');
          $('#chatmsg').keypress(function(e) {
              if (e.which == 13) {
                  e.preventDefault();
                  socket.send(el.val());
                  $('#messages').append($('<li></li>').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 messagesvar 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):

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

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 serverclient) for more information on using Socket.io.

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 <script> tag is not subject to the same origin policy to receive fragments of information (as JSON in Javascript).

Socket.io supports these techniques, but you should consider try to set up you application in such a way that the HTML page using Socket.io is served from the same host, port and protocol. Socket.io can work even when the pages are different, but it is subject to more browser restrictions, because dealing with the same origin policy requires additional steps in each browser.

There are two important things to know:

First, you cannot perform requests from a local file to external resources in most browsers. You have to serve the page you use Socket.io on via HTTP.

Second, IE 8 will not work with requests that 1) violate the same origin policy (host/port) and 2) also use a different protocol. If you serve your page via HTTP (http://example.com/index.html) and attempt to connect to HTTPS (https://example.com:8000), you will see an error and it will not work.

My recommendation would be to only use HTTPS or HTTP everywhere, and to try to make it so that all the requests (serving the page and making requests to the Socket.io backend) appear to the browser as coming from the same host, port and protocol. I will discuss some example setups further below.

Flashsockets support requires TCP mode support

Flash sockets have their own authorization mechanism, which requires that the server first sends a fragment of XML (a policy file) before allowing normal TCP access.

This means that from the perspective of a load balancer, flash sockets do not look like HTTP and thus require that your load balancer can operate in tcp mode.

I would seriously consider not supporting flashsockets because they introduce yet another hurdle into the deployment setup by requiring TCP mode operation.

Websockets support requires HTTP 1.1 support

It's fairly common for people to run nginx in order to serve static files, and add a proxy rule from nginx to Node.

However, if you put nginx in front of Node, then the only connections that will work are long polling -based. You cannot use Websockets with nginx, because Websockets require HTTP 1.1 support throughout your stack to work and current versions of nginx do not support this.

I heard from the nginx team on my blog that they are working on HTTP 1.1 support (and you may be able to find a development branch of nginx that supports this), but as of now the versions of nginx that are included in most Linuxdistributions do not support this.

This means that you have to use something else. A common option is to use HAProxy in front, which supports HTTP 1.1 and can thus be used to route some requests (e.g. /socket.io/) to Node while serving other requests (static files) from nginx.

Another option is to just use Node either to serve all requests, or to use a Node proxy module in conjuction with Socket.io, such as node-http-proxy.

I will show example setups next.

Sample deployments: scaling

Single machine, single stack

This is the simplest deployment. You have a single machine, and you don't want to run any other technologies, like Ruby/Python/PHP alongside your application.

[Socket.io server at :80]

The benefit is simplicity, but of course you are now tasking your Node server with a lot of work that it wouldn't need to do, such as serving static files and (optionally) SSL termination.

The first step in scaling this setup up is to use more CPU cores on the same machine. There are two ways to do this: use a load balancer, or use node cluster.

Single machine, dual stack, node proxies to second stack

In this case, we add another technology - like Ruby - to the stack. For example, the majority of the web app is written in Ruby, and real-time operations are handled by Node.

For simplicity, we will use Node to perform the routing.

[Socket.io server at :80]
  --> [Ruby at :3000 (not accessible directly)]

To implement the route, we will simply add a proxy from the Socket.io server to the Ruby server, e.g. using node-http-proxy or bouncy. Since this mostly app-specific coding, I'm not going to cover it here.

Alternatively, we can use HAProxy:

[HAProxy at :80]
  --> [Ruby at :3000]
  --> [Socket.io server at :8000]

Requests starting with /socket.io are routed to Socket.io listening on port 8000, and the rest to Ruby at port 3000.

To start HAProxy, run sudo haproxy -f path/to/haproxy.cfg

I've also included a simple test server that listens on ports :3000 (http) and :8000 (websockets). It uses the same ws module that Socket.io uses internally, but with a much simpler setup.

Start the test server using node server.js, then run the tests using node client.js. If HAProxy works correctly, you will get a "It worked" message from the client:

            
           

相關推薦

通過Socket.IOnodeJs實現即時訊息

很早開始就想用WebSocket完成即時訊息推送功能。之前本打算用WebSocket + C#實現的,結果人上了年紀變笨了,弄了一天也沒弄好 ⊙﹏⊙ 今天參考了幾篇資料,終於搞定了一個Socket.IO結合nodeJs的Demo。 用Socket.IO有個很大的好處就是開

使用EventSource實現頁面訊息 websocket 的區別

      HTML5有一個Server-Sent Events(SSE)功能,允許服務端推送資料到客戶端。(通常叫資料推送)。我們來看下,傳統的WEB應用程式通訊時的簡單時序圖: 現在Web App中,大都有Ajax,是這樣子: 基於資料推送是這樣的,當資料來源有新資料,它馬上傳送到客戶端,不需要等待

Web Socket 多個使用者之間實現時時訊息

1個月不寫部落格了,最近挺忙的,剛用了2天寫了個預約的小程式和大家分享下~首先大家看下介面:1.祕書端 - 專門新增預約的內容,新增以後立馬在 “市長端” 彈出有一個新的預約2.市長端 - 專門看最新的預約 ,看看要不要接待,接待或不接待點選按鈕以後以後立馬 回覆祕書其實挺簡

一種通過xmpp實現離線訊息的方法及系統

[0039] 此外,本發明單獨設定的功能模組-1OS訊息模組,本質上既是XMPP伺服器的客戶端,又是APNS伺服器的訊息源,當訊息處理的瓶頸位於1S訊息模組時,如當前的1S訊息模組效能待改善或者同一時間內眾多離線訊息到達1S訊息模組時,則只需增加1S訊息模組伺服器的數量即可以解決此訊息處理瓶頸,因此本發明極易

android 實現mqtt訊息,以及不停斷線重連的問題解決

前段時間專案用到mqtt的訊息推送,整理一下程式碼,程式碼的原型是網上找的,具體哪個地址已經忘記了。 程式碼的實現是新建了一個MyMqttService,全部功能都在裡面實現,包括連伺服器,斷線重連,訂閱訊息,處理訊息,釋出訊息等基本操作。 首先新增依賴: dependencies { &

JAVA前後端實現WebSocket訊息(針對性

1、需要新增依賴包,在pom.xml檔案中新增 javax javaee-api 7.0 provided 2、客戶端程式碼 在這裡我為了做成httpsession登入後是同一個,所以我做成兩個頁面,一個登入跳轉頁面,一個用於連結Web

SpringBoot+Stomp實現WebSocket訊息

一、Stomp概念 STOMP是在WebSocket之上提供了一個基於幀的線路格式層,用於定義訊息的語義。 比起原生WebSocket,穩定性和功能性都好得多。 SEND destination:/app/sendTest content-length:23 {"n

Android 基於Socket的長連線實現一個實時的功能

實現此功能需要考慮的幾點: 1)如何保證Socket長連線一直存在並有效執行 2)通過Service執行Socket,當服務端有資料時,通過廣播或者handler來更新UI 具體效果,來上程式碼: @Override public void run() { try

Android WebSocket實現即時通訊/

使用java-websocket實現即時通訊/推送模組; 支援即時發訊息和收訊息,訊息型別有開發者自定義;; 該開源專案支援客戶端client和服務端server的配置使用,並提供示例test;   1,Android 客戶端使用需要配置網路許可權; 2,需要寫一個自

SignalR SelfHost實時訊息,整合到web中,實現伺服器訊息

先前用過兩次SignalR,但是中途有段時間沒弄了,今天重新弄,發現已經忘得差不多了,做個筆記! 首先建立一個控制檯專案Nuget新增引用聯機搜尋:Microsoft.AspNet.SignalR.SelfHostMicrosoft.Owin.Cors 在Program.cs新增程式碼新增一個

IOS8開發之實現App訊息

第一部分 首先第一步當然是介紹一下蘋果的推送機制(APNS)咯(ps:其實每一篇教程都有),先來看一張蘋果官方對其推送做出解釋的概要圖。 Provider是給你手機應用發出推送訊息的伺服器,而APNS(Apple Push Notification Service)則是蘋果訊息推送伺服器。你本地的

iOS經典講解之實現App訊息功能(二)

作者:Loving_iOS 上一篇部落格iOS經典講解之實現App訊息推送功能(一)講解了實現訊息推送的的準備工作,接下來我們來講解第二部分的內容,實現具體的推送及程式碼示例。 訊息推送的第三方平臺有很多,這裡我們使用極光推送平臺,註冊極光推送平臺的賬號。 登陸後進入控

Oracle資料庫觸發器如何呼叫Java程式實現Openfire訊息

寫在前面,要想實現整個過程的成功執行請先準備以下檔案: 1. 登陸Openfire服務端以及Spark客戶端相關程式(openfire_4_0_1.exe、spark_2_7_6.exe) 2. 連線Openfire和Oracle相關的jar包(presence.jar、s

springboot整合websocket實現一對一訊息和廣播訊息

springboot基礎環境 請參考springboot文件 maven依賴    

nodejs訊息socket.io ws對比

node.js的websocket庫目前比較熱門的是ws和socket.io。我們對比一下這兩個庫。 一、筆者寫這篇文章時,ws的周下載量是4百多萬,最近一次更新是11天前,總共98個版本。 socket.io周下載量接近2百萬,最近一次更新是三個月前。總共110個版本 從n

VueNode.js通過socket.io通訊的示例

#一、Node中socket.io基礎 1、是什麼 Socket.IO類庫,是在伺服器和瀏覽器之間提供一個共享介面,其可以用於實現以下幾種通訊方式: HTML5中的WebSocket通訊 Flash中使用的WebSocket通訊 XHR輪詢 JSONP

Android之通過socket.io實現長連線

在專案開發中,時常有服務端向客戶端主動發起交流的需求,可以整合極光推送,但是如果網路不好的情況下,推送可能會遲遲收不到,這樣就導致了使用者體驗得不到保證。 若改用socket實現長連線的話,速度就快很

c++ 網絡編程(六)TCP/IP LINUX下 socket編程 多播廣播 實現一次發所有組客戶端都能接收到

send all users 代碼示例 proto 次數 不可 的人 ssa 原文作者:aircraft 原文鏈接:https://www.cnblogs.com/DOMLX/p/9614288.html 一.多播 鍥子:有這麽一種情況,網絡電臺可能需要同時向成

基於Netty實現的Android 訊息(即時通訊)的解決方案

根據Netty框架實現訊息推送(即時聊天)功能. Netty框架,TCP長連線,心跳,阻塞訊息佇列,執行緒池處理訊息傳送, 基於Google ProtoBuf自定義的訊息協議, TCP粘包/拆包.... 客戶端通過TCP連線到伺服器,並建立TCP長連線;當伺服器端收到新訊息後通過TCP連線推送給

NodeJs 實現IOS APNS 訊息服務

公司的專案要求接入伺服器自己接入原生的ISO 推送服務,不再接第三方的SDK,網上也有很多例子講解什麼是APNS ,如何獲取證書,怎麼接入,剛開始還是聽順利的,就是在獲取pem證書上面有些小問題,不過後來ios開發還是解決了,最後他自己做了一個獲取證書的總結。 我做的就是nodejs 服