Nodejs学习笔记之NET模块


Posted in NodeJs onJanuary 13, 2015

一,开篇分析

从今天开始,我们来深入具体的模块学习,这篇文章是这个系列文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中,

对NodeJS也有一个基本的认识,没事!!!趁热打铁,让我们继续将NodeJS进行到底,好了废话不多说,直接进入今天的主题 “Net模块” ,那么”Net“应该如何理解那?

它是做什么用的那?(Net模块可用于创建Socket服务器或Socket客户端。NodeJS 的数据通信,最基础的两个模块是 Net 和 Http,前者是基于 Tcp 的封装,后者本质还是 Tcp 层,只不过做了比较多的数据封装,我们视为表现层)。

这里参考一下NodeJS “http.js” 中的源码:

Nodejs学习笔记之NET模块

从图中不难看出 HttpServer继承了Net类,具有了相关的通信能力,做了比较多的数据封装,我们视为更高级的表现层。

扩展知识(以下是“inherits”的源码):

exports.inherits = function(ctor, superCtor) {

  ctor.super_ = superCtor;

  ctor.prototype = Object.create(superCtor.prototype, {

    constructor: {

      value: ctor,

      enumerable: false,

      writable: true,

      configurable: true

    }

  });

};

功能是实现继承复用。

刚才做了一个简要的概述,里面有一些常用的概念,这里做个简短的概念普及介绍:

(1),TCP/IP------TPC/IP协议是传输层协议,主要解决数据如何在网络中传输。

(2),Socket------socket则是对TCP/IP协议的封装和应用(程序层面)。

(3),Http------HTTP是应用层协议,主要解决如何包装数据。

(4),网络七层模型------物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

总结一下:Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API)。

从而形成了我们知道的一些最基本的函数接口,比如Create、Listen、Connect、Accept、Send、Read和Write等等。

TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口

实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。

二,体验一把

好了,概念我们也有了,来个例子:

1,建立server.js

var net = require('net') ;

var server = net.createServer(function(c) { // Connection监听器

  console.log("服务器已连接") ;

  c.on("end", function() {

    console.log("服务器已断开") ;

  }) ;

  c.write("Hello,Bigbear !\r\n") ;

  c.pipe(c) ;

}) ;

server.listen(8124, function() { // Listening监听器

  console.log("服务器已绑定") ;

}) ;

2,建立client.js

var net = require('net') ;

var client = net.connect({

    port: 8124

},function(){ // connect监听器

  console.log("客户端已连接") ;

  client.write('Hello,Baby !\r\n') ;

});

client.on("data", function(data) {

  console.log(data.toString()) ;

  client.end() ;

});

client.on("end", function(){

  console.log("客户端断开连接") ;

}) ;

分析一下:

服务端------net.createServer创建一个 TCP 服务,这个服务绑定(server.listen)在 8124 这个端口上,创建 Server 后我们看到有一个回调函数,

在调用上面函数的时候传入一个参数,这个参数也是函数,并且接受了 socket ,这个由其他方法构造的一个管道(pipe),他的作用就是用来数据交互的。

pipe 是需要 Client 跟 Server 打招呼才能建立的,如果此刻没有客户端访问 Server,这个 socket 就不会存在了。

客户端------net.connect顾名思义,就是连接到服务端,第一个参数是对象,设置端口(port)为 8124,也就是我们服务器监听的端口,由于没有设置 host 参数,那默认就是 localhost (本地)。

在 Server 中,socket 是管道的一端,而在 client 中,client 本身就是管道的一端,如果是多个客户端连接 Server,Server 会新建多个 socket,每个 socket 对应一个 client。

运行结果:

Nodejs学习笔记之NET模块

三,案例引入

(1),下面代码仅仅是服务器向客户端输出一段文本,完成服务端到客户端的单向通讯。

//  Sever --> Client 的单向通讯

var net = require('net');

var chatServer = net.createServer();

chatServer.on('connection', function(client) {

  client.write('Hi!\n'); // 服务端向客户端输出信息,使用 write() 方法

  client.write('Bye!\n');

  client.end(); // 服务端结束该次会话

});

chatServer.listen(9000);

Telnet测试一下:telnet127.0.0.1:9000

执行 telnet后,与服务点连接,反馈 Hi! Bye! 的字符,并立刻结束服务端程序终止连接。

如果我们要服务端接到到客户端的信息?

可以监听 server.data 事件并且不要中止连接(否则会立刻结束无法接受来自客户端的消息)。

(2),监听 server.data 事件并且不要中止连接(否则会立刻结束无法接受来自客户端的消息)。

// 在前者的基础上,实现 Client --> Sever 的通讯,如此一来便是双向通讯

var net = require('net');

var chatServer = net.createServer(),    

    clientList = [];

chatServer.on('connection', function(client) {

  // JS 可以为对象自由添加属性。这里我们添加一个 name 的自定义属性,用于表示哪个客户端(客户端的地址+端口为依据)

  client.name = client.remoteAddress + ':' + client.remotePort;  

  client.write('Hi ' + client.name + '!\n');  

  clientList.push(client);  

  client.on('data', function(data) {    

     broadcast(data, client);// 接受来自客户端的信息  

  });

});

function broadcast(message, client) {  

    for(var i=0;i<clientList.length;i+=1) {    

      if(client !== clientList[i]) {      

        clientList[i].write(client.name + " says " + message);    

      }  

    }

}

chatServer.listen(9000);

上面是不是一个完整功能的代码呢?我们说还有一个问题没有考虑进去:那就是一旦某个客户端退出,却仍保留在 clientList里面,这明显是一个空指针。

(3),处理clientList

chatServer.on('connection', function(client) {

  client.name = client.remoteAddress + ':' + client.remotePort

  client.write('Hi ' + client.name + '!\n');

  clientList.push(client)

  client.on('data', function(data) {

    broadcast(data, client)

  })

  client.on('end', function() {

    clientList.splice(clientList.indexOf(client), 1); // 删除数组中的制定元素。

  })

})

NodeTCPAPI已经为我们提供了 end 事件,即客户端中止与服务端连接的时候发生。

(4),优化broadcast

function broadcast(message, client) {

  var cleanup = []

  for(var i=0;i<clientList.length;i+=1) {

    if(client !== clientList[i]) {

      if(clientList[i].writable) { // 先检查 sockets 是否可写

        clientList[i].write(client.name + " says " + message)

      } else {

        cleanup.push(clientList[i]) // 如果不可写,收集起来销毁。销毁之前要 Socket.destroy() 用 API 的方法销毁。

        clientList[i].destroy()

      }

    }

  }  //Remove dead Nodes out of write loop to avoid trashing loop index 

  for(i=0;i<cleanup.length;i+=1) {

    clientList.splice(clientList.indexOf(cleanup[i]), 1)

  }

}

注意的是一旦 “end” 没有被触发,会出现异常,所以才做优化工作。

(5),NetAPI中还提供一个 error 事件,用于捕捉客户端的异常

client.on('error', function(e) {

  console.log(e);

});

四,总结一下

1,理解开篇的相关概念

2,认识Http与Net模块之间的关系

3,结合本文的例子,查阅相关api去实践

4,socket客户端与服务器端之间的通信思想

5,有兴趣可以完善一下那个聊天室的例子

NodeJs 相关文章推荐
跟我学Nodejs(二)--- Node.js事件模块
May 21 NodeJs
轻松创建nodejs服务器(5):事件处理程序
Dec 18 NodeJs
nodejs URL模块操作URL相关方法介绍
Mar 03 NodeJs
nodejs加密Crypto的实例代码
Jul 07 NodeJs
Nodejs抓取html页面内容(推荐)
Aug 11 NodeJs
NodeJS远程代码执行
Aug 28 NodeJs
nodejs redis 发布订阅机制封装实现方法及实例代码
Dec 15 NodeJs
图片上传之FileAPI与NodeJs
Jan 24 NodeJs
nodejs使用express创建一个简单web应用
Mar 31 NodeJs
nodejs 日志模块winston的使用方法
May 02 NodeJs
webstorm中配置nodejs环境及npm的实例
May 15 NodeJs
nodejs使用socket5进行代理请求的实现
Feb 21 NodeJs
Nodejs学习笔记之Global Objects全局对象
Jan 13 #NodeJs
Nodejs为什么选择javascript为载体语言
Jan 13 #NodeJs
NodeJS中Buffer模块详解
Jan 07 #NodeJs
Nodejs中读取中文文件编码问题、发送邮件和定时任务实例
Jan 01 #NodeJs
Nodejs中调用系统命令、Shell脚本和Python脚本的方法和实例
Jan 01 #NodeJs
nodejs中实现路由功能
Dec 29 #NodeJs
NodeJS制作爬虫全过程(续)
Dec 22 #NodeJs
You might like
FleaPHP的安全设置方法
2008/09/15 PHP
据说是雅虎的一份PHP面试题附答案
2009/01/07 PHP
PHP中数组的三种排序方法分享
2012/05/07 PHP
sql注入与转义的php函数代码
2013/06/17 PHP
php程序员应具有的7种能力小结
2014/11/27 PHP
php连接mysql数据库
2017/03/21 PHP
Js 时间间隔计算的函数(间隔天数)
2011/11/15 Javascript
extjs实现选择多表自定义查询功能 前台部分(ext源码)
2011/12/20 Javascript
jQuery实现单击和鼠标感应事件
2015/02/01 Javascript
jQuery实现网站添加高亮突出显示效果的方法
2015/06/26 Javascript
jquery.cookie实现的客户端购物车操作实例
2015/12/24 Javascript
基于JavaScript实现随机颜色输入框
2016/12/10 Javascript
关于微信jssdk实现多图片上传的一点心得分享
2016/12/13 Javascript
Vue.js学习示例分享
2017/02/05 Javascript
Spring Boot+AngularJS+BootStrap实现进度条示例代码
2017/03/02 Javascript
bootstrap timepicker在angular中取值并转化为时间戳
2017/06/13 Javascript
详解React Native网络请求fetch简单封装
2017/08/10 Javascript
详解微信小程序canvas圆角矩形的绘制的方法
2018/08/22 Javascript
微信小程序webview实现长按点击识别二维码功能示例
2019/01/24 Javascript
基于layui实现高级搜索(筛选)功能
2019/07/26 Javascript
JS数组方法join()用法实例分析
2020/01/18 Javascript
vue fetch中的.then()的正确使用方法
2020/04/17 Javascript
Vue watch响应数据实现方法解析
2020/07/10 Javascript
PyTorch的深度学习入门教程之构建神经网络
2019/06/27 Python
tensorflow 固定部分参数训练,只训练部分参数的实例
2020/01/20 Python
Python3如何使用range函数替代xrange函数
2020/10/05 Python
Python抓包并解析json爬虫的完整实例代码
2020/11/03 Python
是否有自动比较结构的方法
2015/06/03 面试题
大学生职业生涯规划范文
2014/01/08 职场文书
市场营销个人求职信范文
2014/02/02 职场文书
三分钟演讲稿范文
2014/04/24 职场文书
实验心得体会
2014/09/05 职场文书
冰峪沟导游词
2015/02/09 职场文书
会计专业自荐信范文
2019/05/22 职场文书
CSS3实现的文字弹出特效
2021/04/16 HTML / CSS
mysql中关键词exists的用法实例详解
2022/06/10 MySQL