Published: 2015-09-01

Nodejs初探

Table of Contents

1 背景

出于好奇尝试了nodejs, 看了《Node:Up and Running》,被事件驱动程序和简单明了的方式吸引。

所以尝试跟着写了两个书上的demo感受下

1.1 简单聊天室

1.1.1 代码

Enviroment :node 0.10.25, ubuntu 14.04

一个基于TCP的聊天服务器,可使用Telnet连接,可同时连接多个客户端使用,如果其中一个客户端出问题不会影响其它客户端使用. 代码以及说明如下:

:::javascript

//加载'net'模块,包含了TCP模块
var net = require('net');

//创建一个TCP服务器
//创建一个数组存放连接的客户端
var chatServer = net.createServer(),
    clientList = [];

//添加服务器连接的监听事件
//将客户端对应的TCP socket对象'client' 传给callback函数
chatServer.on('connection', function(client){

    //client.remoteAddress获得客户端IP地址,
    //client.remotePort是客户端接收返回数据的TCP端口,作为client的唯一标识
    client.name = client.remoteAddress + ':' + client.remotePort

    //client.write方法用来写入发送给客户端的数据
    client.write('Hi ' + client.name + '!\n');

    //将此客户端放入所有客户端组成的数组
    clientList.push(client);

    //添加接收到客户端数据的监听事件
    client.on('data', function(data){
        //定义一个broadcast函数用来发送数据给所有有效的客户端
        broadcast(data, client)
    });

    //添加客户端断开连接的监听事件
    client.on('end', function(){
        //客户端断开连接后,将此客户端从客户端列表中清除
        clientList.splice(clientList.indexOf(client), 1);
    });

    //添加客户端错误的监听事件
    client.on('error', function(e){
        //打印出错误内容
        console.log(e);
    })
})

function broadcast(message, client){
    //定义一个存放需要清除的客户端的数组
    var cleanup = [];

    //遍历所有客户端
    for(var i=0;i<clientList.length;i++){

        //向除自己意外的客户端发送消息
        if(client != clientList[i]){

            //判断客户端socket是否能写入数据
            if(clientList[i].writable){

                //向该客户端写入内容
                clientList[i].write(client.name + " says> " + message);
            } else {

                //如果该客户端不可用则加它加入要清除的列表
                cleanup.push(clientList[i]);

                //通过Socket.destroy()方法关闭不可写的socket
                clientList[i].destroy();
            }
        }
    }

    //从客户端列表中移除所有不可写的客户端
    for(i=0;i<cleanup.length;i++){
        clientList.splice(clientList.indexOf(cleanup[i]), 1);
    }
}

//设置服务器监听8000端口
chatServer.listen(8000);

//服务器上打印初始信息
console.log('Server is now running at "127.0.0.1", port 8000');

1.1.2 运行结果如图:

  • 服务器端

node-simple-chat-server1.png

  • console1, 使用telnet连接服务器

node-simple-chat-server2.png

  • console2, 使用telnet连接服务器

node-simple-chat-server3.png

  • console3, 使用telnet连接服务器

node-simple-chat-server4.png

1.2 express

需要注意的是,版本变迁后,书上有些代码已经过时了 Enviroment :node 0.10.25, ubuntu 14.04

////app.js, , server side, simple twitter

//引入express模块,它express会在后台调用http模块
var express = require('express');

//创建服务器 书上的express.createServer()方法已经不再使用了
var app = express() ;

// 同样,新版本bodyparser也被分离出来了
var bodyParser = require('body-parser')
var urlencodedParser = bodyParser.urlencoded({ extended: false })

//指定监听端口
app.listen(8000);

//初始化数组用来存放twitter
var tweets = [];

//和使用http方式不同的是,不用为请求事件调用监听器,通过http匹配的方式来指定回掉函数
//而且可以根据请求的方式过滤(eg.get,post...)
app.get('/', function(req, res) {
  // 不需要像http那样先发送header然后再返回内容,直接用send()方法
  // send()方法会发送header,同时还会调用response.end()方法结束response
  res.send('Welcome to Node Twitter')
});

//  express.bodyParser()是一个中间件,用来将客户端post数据转化为javascript对象
//  如果不调用 express.bodyParser(),就需要手动处理请求的数据
// 新版本用上面指定对urlencodedParser
app.post('/send', urlencodedParser, function(req, res) {

  // req.body包含post数据对应的对象
  if (req.body && req.body.tweet) {
     tweets.push(req.body.tweet);

     // 不需要手动序列化,res.send()会自动进行,并添加http header
     res.send({status:"ok", message:"Tweet received"});

  } else {
    res.send({status:"nok", message:"No tweet received"});
  }
});

app.get('/tweets', function(req, res) {
  res.send(tweets);

})
// a simple Post test, 用来测试上述api

// assert模块来对返回值进行测试
var http = require('http'),
  assert = require('assert');

//配置http.request的属性
var opts = {
  host: 'localhost',
  port: 8000,
  path: '/send',
  method: 'POST',
  headers: {'content-type':'application/x-www-form-url-encodeed'}
};

//利用利用http模块来发送请求
var req = http.request(opts, function(res) {
  //指定接受数据的编码方式
  res.setEncoding('utf-8');

  //不同于express中的方式,这里手动处理返回的数据流
  var data = "";
  res.on('data', function(d) {
    data += d
  });

  //指定end回调函数
  res.on('end', function() {
    assert.notStrictEqual指定对数据进行“==”级别对检查
    assert.notStrictEqual(data, '{status:"ok", message:"Tweet received"}')
  });
})

//调用req.write来指定发送的数据
req.write('tweet=test');

//表示数据已经发送完毕
req.end();

Author: Nisen

Email: imnisenATgmailDOTcom

Emacs 25.2.1 (Org mode 8.2.10)