Node.js之网络通讯模块实现浅析


Posted in Javascript onApril 01, 2017

前言

想必我们在用Node.js用的最多的应该是创建http服务,所以对于每个Web开发工程师而言,Node.js的网络相关模块学习是必不可少。

Node.js的网络模块架构

在Node.js的模块里面,与网络相关的模块有Net、DNS、HTTP、TLS/SSL、HTTPS、UDP/Datagram,除此之外,还有v8底层相关的网络模块有tcp_wrap.ccudp_wrap.ccpipe_wrap.ccstream_wrap.cc等等,在Javascript层以及C++层之间通过process.binding进行桥接相互通信。

Node.js之网络通讯模块实现浅析

Net模块

Net模块提供了一些用于底层的网络通信接口,包括创建服务器以及客户端,其中HTTP模块也是基于Net模型的上层封装,在Net模块里面主要提供net.Server以及net.Socket

创建TCP服务端

创建一个TCP服务器,可以通过使用构造函数new net.Server或者使用工厂方法net.createServer,这两个方法都会返回一个net.Server类,可接收两个可选参数。

var net = require('net');

var server = net.createServer(function(socket){

  socket
    .on('data',function(data){
      console.log('socket data',data.toString());
      socket.write( data.toString() );
    })
    .on('end',function(){
      console.log('socket end')
    })
    .on('error',function(error){
      console.log('socket error',error);
    });
});

server.listen(56200,function(){
  console.log('server run at ',server.address());
});

server.on('error',function(err){
  throw err;
});
// 执行后:server run at { address: '::', family: 'IPv6', port: 56200 }

在listen监听的时候没有指定端口的话会自动随意监听一个端口,创建完成一个TCP服务器后,使用tenlent 0.0.0.0 56200,链接后可与服务器进行数据通信。通过createServer实例化一个服务后,服务会去监听客户端请求,与客户端建立了链接之后会在回调里面抛出建链的net.Socket对象。

创建TCP客户端

创建一个TCP客户端链接可以使用构造函数new net.Socket或者其工厂方法net.createConnection,创建成功后都会返回一个net.Socket实例。

var net = require('net');

var client = net.createConnection({port:56200,host:'localhost'});

client.on('connect',function(){
  console.log('client connect');
});

client.on('data',function(data){
  console.log('client data',toString());
});

client.on('error',function(error){
  throw error;
});

client.on('close',function(){
  console.log('client close');
});

Socket

socket是啥这里就不做详细的阐述了,下面主要了解下net.Socket这个构造体主要有提供一些什么方法、监听事件的使用。

相关事件

  1. connect : 当客户端与服务端成功建立链接之后触发,如果链接不上服务器直接抛出error事件错误然后退出node进程。
  2. data : 当客户端收到服务器传送过来的数据或者是客户端传送给服务器的数据的时候触发回调。
  3. end : 当另外一侧发送FIN包断开的时候触发,默认情况下面 (allowHalfOpen == false)socket会自我销毁(如果写入待处理队列里面还没正式响应回包),但是我们可以设置allowHalfOpen参数为true,这样可以继续往该socket里面写数据,但是我们需要自己去调用 end 方法去消耗这个socket,不然可能会造成句柄泄漏。
  4. close : 链接断开的时候触发,但是如果在传输的过程中有错误的话这里会在回调函数里面抛出 error。
  5. timeout : 当socket超时空闲的时候触发,如果要在队列里面销毁需要手动去调close方法。
  6. lookup : 域名解析完成的时候触发。
  7. drain : 写完缓存的时候触发,可使用在上传大小限制中。

相关方法

  1. write() : 服务端给客户端发送数据或者是客户端给服务端发送数据。
  2. address() : 获取服务绑定的socket的IP地址,返回对象有三个属性,分别为端口、host以
  3. 及IPvX版本。
  4. end() : 半关闭socket,会发送一个FIN包,服务器仍然可能发送一些数据,也可以这样调用socket.end(data,encoding)。
  5. pause() : 暂停读取数据,可以用作对数据上传限制。
  6. resume() : 继续数据读取。
  7. setEncoding() : 设置数据流的获取格式。
  8. setKeepAlive() : 允许/禁止keep-alive功能。
  9. setNoDelay() : 禁止Nagele算法,TCP链接默认使用Nagle算法,它们在发送之前数据会被缓存。这是为true的话在每次socket.write()的时候会立即发送数据,默认为true。
  10. setTimeout() : 当一个空闲的socket在多少秒后不活跃会被接受到timeout事件,但是该socket不会停止销毁,需要手动调用end()或者destroy()。表示禁止空闲超时。

相关属性

  1. bufferSize : 当前缓存的等待被发送的字符串的数量。
  2. bytesRead : 收到的字节的数量。
  3. bytesWritten : 发送的字节的数量
  4. destroyed : 标识链接是否已经被破坏,一旦被破环,就不用使用该链接来传输数据。
  5. localAddress : 远程客户端链接本地地址的host。如果我们监听服务的host是0.0.0.0,而客户端链接的是'192.168.1.1',最后的值是后者。
  6. localPort : 本地的端口。
  7. remoteAddress : 客户端IP,如果socket已经是destryed的话,该值为undefined
  8. remoteFamily : 客户端是IPvX

回包异常处理

服务器从客户端接受到需要处理的数据后进入处理环节,再业务逻辑处理完成之前如果socket以外断开的话,待服务器再给客户端回报的时候会直接响应error事件并报错Error : This socket has benn ended by the other part,所以在回报之前服务端需要先判断该socket是否被销毁,如果没有被销毁则回包,如果已经断开则销毁:

var net = require('net');
var biz = require('./biz');
var server = net.createServer(function(socket){

  socket
    .on('data',function(data){
      biz.do(data)
        .then(function(){
          if( !socket.destroyed ) {
            socket.write( data.toString() );
          } else {
            // do some report
            socket.destry();
          }
        })
        .catch(function(){
          !socket.destroyed && socket.end('server handler error');
        });
      
    })
    .on('end',function(){
      console.log('socket end')
    })
    .on('error',function(error){
      console.log('socket error',error);
    });
});

server.listen(56200,function(){
  console.log('server run at ',server.address());
});

server.on('error',function(err){
  throw err;
});

限制客户端数据大小

对请求大小限制是服务安全里面比不可少的一个环节,服务端不能无限大小的去接受客户端发送过来的所有数据,而限制大小就是第一道门槛。

var net = require('net');
var MAX_REQUEST_BYTES = 2 * 1024 * 1024; // 2M
var server = net.createServer(function(socket){

  socket
    .on('data',function(data){
      
      if(data.bytesRead > MAX_REQUEST_BYTES) {
        socket.pause();
        socket.end('data is too big, forbidden');
        // do some report
      }
    })
    .on('end',function(){
      console.log('socket end')
    })
    .on('error',function(error){
      console.log('socket error',error);
    });
});

server.listen(56200,function(){
  console.log('server run at ',server.address());
});

server.on('error',function(err){
  throw err;
});

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 5 新增 Array 方法实现介绍
Feb 06 Javascript
js类式继承的具体实现方法
Dec 31 Javascript
JavaScript的instanceof运算符学习教程
Jun 08 Javascript
jQuery实现的表格展开伸缩效果实例
Sep 07 Javascript
使用jquery给指定的table动态添加一行、删除一行
Oct 13 Javascript
AngularJS中transclude用法详解
Nov 03 Javascript
NPM 安装cordova时警告:npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to
Dec 20 Javascript
老生常谈ES6中的类
Jul 31 Javascript
React native ListView 增加顶部下拉刷新和底下点击刷新示例
Apr 27 Javascript
详解关于vue-area-linkage走过的坑
Jun 27 Javascript
vue微信分享到朋友圈 vue微信发送给好友
Nov 28 Javascript
浅析vue中的nextTick
Dec 28 Vue.js
vue-cli+webpack记事本项目创建
Apr 01 #Javascript
JS常见创建类的方法小结【工厂方式,构造器方式,原型方式,联合方式等】
Apr 01 #Javascript
Vue.js实战之Vuex的入门教程
Apr 01 #Javascript
AngularJS页面传参的5种方式
Apr 01 #Javascript
vue2.0构建单页应用最佳实战
Apr 01 #Javascript
vue货币过滤器的实现方法
Apr 01 #Javascript
javascript 中的try catch应用总结
Apr 01 #Javascript
You might like
德生S2000收音机更换“钕铁硼”全频扬声器
2021/03/02 无线电
如何修改和添加Apache的默认站点目录
2013/07/05 PHP
PHP变量的定义、可变变量、变量引用、销毁方法
2013/12/20 PHP
如何解决phpmyadmin导入数据库文件最大限制2048KB
2015/10/09 PHP
PHP将身份证正反面两张照片合成一张图片的代码
2017/04/08 PHP
用php+ajax新建流程(请假、进货、出货等)
2017/06/11 PHP
YII2框架中excel表格导出的方法详解
2017/07/21 PHP
javascript 火狐(firefox)不显示本地图片问题解决
2008/07/05 Javascript
简单的代码实现jquery定时器
2013/11/17 Javascript
Backbone.js 0.9.2 源码注释中文翻译版
2015/06/25 Javascript
jQuery实现默认是闭合的FAQ展开效果菜单
2015/09/14 Javascript
JQuery EasyUI Layout 在from布局自适应窗口大小的实现方法
2016/05/28 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
2016/06/06 Javascript
vue.js树形组件之删除双击增加分支实例代码
2017/02/28 Javascript
使用xampp将angular项目运行在web服务器的教程
2019/09/16 Javascript
解决layui批量传值到后台操作时出现传值为空的问题
2019/09/28 Javascript
vscode 配置vue+vetur+eslint+prettier自动格式化功能
2020/03/23 Javascript
javascript 易错知识点实例小结
2020/04/25 Javascript
使用Python脚本对Linux服务器进行监控的教程
2015/04/02 Python
Python实现Smtplib发送带有各种附件的邮件实例
2017/06/05 Python
利用Python如何制作好玩的GIF动图详解
2018/07/11 Python
基于python实现聊天室程序
2018/07/27 Python
详解用python计算阶乘的几种方法
2019/08/14 Python
Python 多线程搜索txt文件的内容,并写入搜到的内容(Lock)方法
2019/08/23 Python
Html5 webRTC简单实现视频调用的示例代码
2020/09/23 HTML / CSS
Marc Jacobs官方网站:美国奢侈品牌
2017/08/29 全球购物
北美领先的智能产品购物网站:Wellbots
2018/06/11 全球购物
用C语言实现文件读写操作
2013/10/27 面试题
什么是方法的重载
2013/06/24 面试题
创意活动策划书
2014/01/15 职场文书
核心价值观演讲稿
2014/05/13 职场文书
销售求职信范文
2014/05/26 职场文书
党员批评与自我批评思想汇报(集锦)
2014/09/14 职场文书
2015教师节师德演讲稿
2015/03/19 职场文书
立春观后感
2015/06/18 职场文书
2016年大学生党员承诺书
2016/03/24 职场文书