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 相关文章推荐
JS request函数 用来获取url参数
May 17 Javascript
javascript开发随笔二 动态加载js和文件
Nov 25 Javascript
js滚动条回到顶部的代码
Dec 06 Javascript
javascript使用switch case实现动态改变超级链接文字及地址
Dec 16 Javascript
JavaScript移除数组内重复元素的方法
Mar 18 Javascript
js实现简单鼠标跟随效果的方法
Apr 10 Javascript
判断数组是否包含某个元素的js函数实现方法
May 19 Javascript
vue.js将unix时间戳转换为自定义时间格式
Jan 03 Javascript
JS设置时间无效问题的解决办法
Feb 18 Javascript
基于react组件之间的参数传递(详解)
Sep 05 Javascript
JavaScript+Canvas实现彩色图片转换成黑白图片的方法分析
Jul 31 Javascript
js构造函数constructor和原型prototype原理与用法实例分析
Mar 02 Javascript
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
php连接mssql的一些相关经验及注意事项
2013/02/05 PHP
Smarty高级应用之缓存操作技巧分析
2016/05/14 PHP
PHP通过curl获取接口URL的数据方法
2018/05/31 PHP
JQuery对id中含有特殊字符的转义处理示例
2013/09/06 Javascript
读取input:file的路径并显示本地图片的方法
2013/09/23 Javascript
设置checkbox为只读(readOnly)的两种方式
2013/10/11 Javascript
基于js实现微信发送好友如何分享到朋友圈、微博
2015/11/30 Javascript
JavaScript位移运算符(无符号) >>> 三个大于号 的使用方法详解
2016/03/31 Javascript
JavaScript与java语言有什么不同
2016/09/22 Javascript
Bootstrap分页插件之Bootstrap Paginator实例详解
2016/10/15 Javascript
浅谈mint-ui 填坑之路
2017/11/06 Javascript
vue 下列表侧滑操作实例代码详解
2018/07/24 Javascript
js中apply()和call()的区别与用法实例分析
2018/08/14 Javascript
微信小程序搭建(mpvue+mpvue-weui+fly.js)的详细步骤
2018/09/18 Javascript
JS实现根据数组对象的某一属性排序操作示例
2019/01/14 Javascript
vue权限管理系统的实现代码
2019/01/17 Javascript
微信小程序实现发微博功能的示例代码
2020/06/24 Javascript
JS绘图Flot如何实现可选显示曲线图功能
2020/10/16 Javascript
[01:17:12]职来职往完美电竞专场
2014/09/18 DOTA
python中map()与zip()操作方法
2016/02/27 Python
TensorFlow安装及jupyter notebook配置方法
2017/09/08 Python
python 中的列表生成式、生成器表达式、模块导入
2019/06/19 Python
Python 实现文件读写、坐标寻址、查找替换功能
2019/09/11 Python
Idea安装python显示无SDK问题解决方案
2020/08/12 Python
Lombok插件安装(IDEA)及配置jar包使用详解
2020/11/04 Python
美国迪克体育用品商店:DICK’S Sporting Goods
2018/07/24 全球购物
耐克亚太地区:Nike APAC
2019/12/07 全球购物
int和Integer有什么区别
2013/05/25 面试题
学校安全教育制度
2014/01/31 职场文书
好习惯伴我成长演讲稿
2014/05/21 职场文书
代领毕业证委托书
2014/08/02 职场文书
报效祖国演讲稿
2014/09/15 职场文书
公司股东出资证明书
2014/11/01 职场文书
院系推荐意见
2015/06/05 职场文书
基于python的matplotlib制作双Y轴图
2021/04/20 Python
Python中OpenCV实现简单车牌字符切割
2021/06/11 Python