websocket + node.js

websocket的原理和应用

在继续本文之前,让我们了解下websocket的原理:

websocket通信协议实现的是基于浏览器的原生socket,这样原先只有在c/s模式下的大量开发模式都可以搬到web上来了,基本就是通过浏览器的支持在web上实现了与服务器端的socket通信。

WebSocket没有试图在HTTP之上模拟server推送,而是直接在TCP之上定义了帧协议,因此WebSocket能够支持双向的通信。

首先来介绍下websocket客户端与服务端建立连接的过程:

先用js创建一个WebSocket实例,使用ws协议建立服务器连接,ws://www.cnodejs.org:8088

ws开头是普通的websocket连接,wss是安全的websocket连接,类似于https。

客户端与服务端建立握手,发送如下信息:

GET /echo HTTP/1.1

Upgrade: WebSocket

Connection: Upgrade

Host:http://www.cnodejs.org:8088

Origin:http://www.cnodejs.com

服务端会发回如下:

HTTP/1.1 101 Web Socket Protocol Handshake

Upgrade: WebSocket

Connection: Upgrade

WebSocket-Origin:http://www.cnodejs.org

WebSocket-Location: ws://www.cnodejs.org:8088/echo

具体的ws协议,可以参考:http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76

我们在开发过程中不需要考虑协议的细节,因为websocket API已经帮我们封装好了。

需要注意的是所有的通信数据都是以”\x00″开头以”\xFF”结尾的,并且都是UTF-8编码的。

这个过程类似于http的建立连接过程,不同的是,建立连接之后,接下来客户端和服务端的任何交互都需要再有这个动作。客户端通过websocket API提供的如下4个事件进行编程:

onopen 建立连接后触发

onmessage 收到消息后触发

onerror 发生错误时触发

onclose 关闭连接时触发

让我们全面了解一下websocket API,他其实非常简单,下面是所有的API:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23[Constructor(in DOMString url, in optional DOMString protocols)]

[Constructor(in DOMString url, in optional DOMString[] protocols)]

interface WebSocket {

readonly attribute DOMString url;

// ready state

const unsigned short CONNECTING = 0;

const unsigned short OPEN = 1;

const unsigned short CLOSING = 2;

const unsigned short CLOSED = 3;

readonly attribute unsigned short readyState;

readonly attribute unsigned long bufferedAmount;

// networking

attribute Function onopen;

attribute Function onmessage;

attribute Function onerror;

attribute Function onclose;

readonly attribute DOMString protocol;

void send(in DOMString data);

void close();

};

WebSocket implements EventTarget;

详细的websocket API,可以参考此文:http://dev.w3.org/html5/websockets/

node.js与websocket的结合

终于讲到了正题了,node.js如何与websocket结合,websocket API是基于事件的,他是对于客户端而言,而对于服务端来说,如何来处理呢?其实可以简单的理解为实现websocket协议的socket server开发。

node.js天生就是一个高效的服务端语言,可以直接使用 javascript直接来处理来自客户端的请求,这样如果服务端这边需要大量的业务逻辑开发,则可以直接使用node开发。通过node和 websocket的结合可以开发出很多实时性要求很高的web应用,如游戏、直播、股票、监控、IM等等。

而node.js如何实现websocket的支持,已经有一个比较成熟的开源系统node-websocket-server:https://github.com/miksago/node-websocket-server,让我们来探究一二:

其实原理也是很简单就是用node实现了websocket draft-76的协议,同时他对外提供了api,可以方便其他应用程序简化编程。

它继承了node的http.Server的事件和方法,这样它简化了服务端的编程,同时可以处理http的请求。

为了实现连接之间的通信和消息的广播,它实现了一个manager类,给每一个连接创建一个id,然后在内存中维护一个连接链表,并提供了上线和下线的自动管理。

它还提供对以下几个事件的接口:

listening 当服务器准备好接受客户端请求时

request 当一个http 请求发生时触发

stream

close

clientError

error

让我们看看一个node-websocket-server提供的一个server的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27var sys = require("sys")

, ws = require('../lib/ws/server');

var server = ws.createServer({debug: true});

// Handle WebSocket Requests

server.addListener("connection", function(conn){

conn.send("Connection: "+conn.id);

conn.addListener("message", function(message){

conn.broadcast("<"+conn.id+"> "+message);

if(message == "error"){

conn.emit("error", "test");

}

});

});

server.addListener("error", function(){

console.log(Array.prototype.join.call(arguments, ", "));

});

server.addListener("disconnected", function(conn){

server.broadcast("<"+conn.id+"> disconnected");

});

server.listen(8000);

这个例子非常的简单,可以看到对于websocket的server端开发,我们已经不需要考虑 websocket协议的实现,他几乎有着和客户端浏览器上websocket API一样的事件,只有对连接、断开连接、消息、错误等事件进行处理,这样应用的开发就非常的灵活了。

实例:用websocket和node.js搭建实时监控系统

通过websocket打通了浏览器和服务端之后,我们就可以尝试搭建一个实际的应用,这里以实时监控系统为例。

直接与linux自身监控工具的结合,将监控结果通过websocket直接更到网页上,由于建立了socket长连接,绑定iostat的标准输 出的事件,做到了真正的实时。同时可以支持对监控结果的讨论,增加了一个简单的chat,基于事件的通讯中,chat和监控同时发送完全不受影响,所以还 可以把更多的事件加入进来。

让我们来看看这个过程:

首先是用node.js捕获iostat的输出:

1

2

3

4

5

6var sys = require("sys")

, ws = require('../lib/ws/server');

var sys = require('sys');

var spawn = require('child_process').spawn;

var mon = spawn("iostat",["-I","5"]);

spawn可以根据参数启动一个进程,同时可以对stdout, stderr, exit code进行捕获,当这些事件触发时,可以绑定我们的函数,同时捕获其输出。

这里是iostat的标准输出:

disk0 cpu load average

KB/t tps MB/s us sy id 1m 5m 15m

14.64 4 0.06 7 5 88 0.76 0.95 0.90

我们捕获他的输出,将其发送到客户端去:

1

2

3

4

5mon.stdout.on('data',function(data) {

data = format_string(data);

sys.puts(data);

conn.send("#mon:"+data+"");

});

客户端也就是浏览器,在收到消息后,对其进行简单的字符串处理,然后就可以直接在网页中输出了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15w.onmessage = function(e) {

var msg = e.data;

if(msg.match(/#mon:/)) {

var monarr = msg.split(":")[1].split(" ");

var body = "";

for(var item in monarr) {

"+monarr[item]+"

}

$("#iobody").html(body);

//log(monarr[0]);

}

else

log(e.data);

}

这里自定义了一个#mon的简单协议,这样可以对更多类型的输出分开处理。

服务端和客户端总共100多行的代码,就已经实现了一个实时服务器性能监控系统。

全部代码下载地址:http://cnodejs.googlecode.com/svn/trunk/monsocket/examples/

(注:本程序仅在mac osx下测试通过)

如果加上RGraph(基于html5),则可以打造更加精美的实时展现:  http://www.rgraph.net/docs/dynamic.html

总结

这篇文章适合node.js的初学者或者对于websocket不够了解的人,总结起来,就是以下几个点:

使用websocket API可以开发web应用实时

websocket api和 node.js可以很完美的配合

node-websocket-server 封装了websocket协议,使服务端进行websocket的开发,非常的简单

node的易用性,使其在服务端略加编程,即可以打造一个完美的后台服务

node的事件驱动的机制保证了系统的高效,可以使用EventEmitter定义自己的事件触发

对于命令行输出可以使用spawn来捕获,通过在web应用中充分利用linux的各种系统工具

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容