Nodejs进阶:核心模块net入门学习与实例讲解


Posted in NodeJs onNovember 21, 2016

模块概览

net模块是同样是nodejs的核心模块。在http模块概览里提到,http.Server继承了net.Server,此外,http客户端与http服务端的通信均依赖于socket(net.Socket)。也就是说,做node服务端编程,net基本是绕不开的一个模块。

从组成来看,net模块主要包含两部分,了解socket编程的同学应该比较熟悉了:

  • net.Server:TCP server,内部通过socket来实现与客户端的通信。
  • net.Socket:tcp/本地 socket的node版实现,它实现了全双工的stream接口。

本文从一个简单的 tcp服务端/客户端 的例子开始讲解,好让读者有个概要的认识。接着再分别介绍 net.Server、net.Socket 比较重要的API、属性、事件。

对于初学者,建议把文中的例子本地跑一遍加深理解。

简单的 server+client 例子

tcp服务端程序如下:

var net = require('net');

var PORT = 3000;
var HOST = '127.0.0.1';

// tcp服务端
var server = net.createServer(function(socket){
  console.log('服务端:收到来自客户端的请求');

  socket.on('data', function(data){
    console.log('服务端:收到客户端数据,内容为{'+ data +'}');

    // 给客户端返回数据
    socket.write('你好,我是服务端');
  });

  socket.on('close', function(){
     console.log('服务端:客户端连接断开');
  });
});
server.listen(PORT, HOST, function(){
  console.log('服务端:开始监听来自客户端的请求');
});

tcp客户端如下:

var net = require('net');

var PORT = 3000;
var HOST = '127.0.0.1';

// tcp客户端
var client = net.createConnection(PORT, HOST);

client.on('connect', function(){
  console.log('客户端:已经与服务端建立连接');
});

client.on('data', function(data){
  console.log('客户端:收到服务端数据,内容为{'+ data +'}');
});

client.on('close', function(data){
  console.log('客户端:连接断开');
});

client.end('你好,我是客户端');

运行服务端、客户端代码,控制台分别输出如下:

服务端:

服务端:开始监听来自客户端的请求
服务端:收到来自客户端的请求
服务端:收到客户端数据,内容为{你好,我是客户端}
服务端:客户端连接断开

客户端:

客户端:已经与服务端建立连接
客户端:收到服务端数据,内容为{你好,我是服务端}
客户端:连接断开

服务端 net.Server

server.address()
返回服务端的地址信息,比如绑定的ip地址、端口等。

console.log( server.address() );
// 输出如下 { port: 3000, family: 'IPv4', address: '127.0.0.1' }

server.close(callback])

关闭服务器,停止接收新的客户端请求。有几点注意事项:

  • 对正在处理中的客户端请求,服务器会等待它们处理完(或超时),然后再正式关闭。
  • 正常关闭的同时,callback 会被执行,同时会触发 close 事件。
  • 异常关闭的同时,callback 也会执行,同时将对应的 error 作为参数传入。(比如还没调用 server.listen(port) 之前,就调用了server.close())

下面会通过两个具体的例子进行对比,先把结论列出来

  • 已调用server.listen():正常关闭,close事件触发,然后callback执行,error参数为undefined
  • 未调用server.listen():异常关闭,close事件触发,然后callback执行,error为具体的错误信息。(注意,error 事件没有触发)

例子1:服务端正常关闭

var net = require('net');
var PORT = 3000;
var HOST = '127.0.0.1';
var noop = function(){};

// tcp服务端
var server = net.createServer(noop);

server.listen(PORT, HOST, function(){

  server.close(function(error){
    if(error){
      console.log( 'close回调:服务端异常:' + error.message );
    }else{
      console.log( 'close回调:服务端正常关闭' );
    }      
  }); 
});

server.on('close', function(){
  console.log( 'close事件:服务端关闭' );
});

server.on('error', function(error){
  console.log( 'error事件:服务端异常:' + error.message );
});

输出为:

close事件:服务端关闭
close回调:服务端正常关闭

例子2:服务端异常关闭

代码如下

var net = require('net');
var PORT = 3000;
var HOST = '127.0.0.1';
var noop = function(){};

// tcp服务端
var server = net.createServer(noop);

// 没有正式启动请求监听
// server.listen(PORT, HOST);

server.on('close', function(){
  console.log( 'close事件:服务端关闭' );
});

server.on('error', function(error){
  console.log( 'error事件:服务端异常:' + error.message );
});

server.close(function(error){
  if(error){
    console.log( 'close回调:服务端异常:' + error.message );
  }else{
    console.log( 'close回调:服务端正常关闭' );
  }      
});

输出为:

close事件:服务端关闭
close回调:服务端异常:Not running

server.ref()/server.unref()

了解node事件循环的同学对这两个API应该不陌生,主要用于将server 加入事件循环/从事件循环里面剔除,影响就在于会不会影响进程的退出。

对出学习net的同学来说,并不需要特别关注,感兴趣的自己做下实验就好。

事件 listening/connection/close/error

  • listening:调用 server.listen(),正式开始监听请求的时候触发。
  • connection:当有新的请求进来时触发,参数为请求相关的 socket。
  • close:服务端关闭的时候触发。
  • error:服务出错的时候触发,比如监听了已经被占用的端口。

几个事件都比较简单,这里仅举个 connection 的例子。

从测试结果可以看出,有新的客户端连接产生时,net.createServer(callback) 中的callback回调 会被调用,同时 connection 事件注册的回调函数也会被调用。

事实上,net.createServer(callback) 中的 callback 在node内部实现中 也是加入了做为 connection事件 的监听函数。感兴趣的可以看下node的源码。

var net = require('net');
var PORT = 3000;
var HOST = '127.0.0.1';
var noop = function(){};

// tcp服务端
var server = net.createServer(function(socket){
  socket.write('1. connection 触发\n');
});

server.on('connection', function(socket){
  socket.end('2. connection 触发\n');
});

server.listen(PORT, HOST);

通过下面命令测试下效果

curl http://127.0.0.1:3000

输出:

1. connection 触发
2. connection 触发

客户端 net.Socket

在文章开头已经举过客户端的例子,这里再把例子贴一下。(备注:严格来说不应该把 net.Socket 叫做客户端,这里方便讲解而已)

单从node官方文档来看的话,感觉 net.Socket 比 net.Server 要复杂很多,有更多的API、事件、属性。但实际上,把 net.Socket 相关的API、事件、属性 进行归类下,会发现,其实也不是特别复杂。

具体请看下一小节内容。

var net = require('net');

var PORT = 3000;
var HOST = '127.0.0.1';

// tcp客户端
var client = net.createConnection(PORT, HOST);

client.on('connect', function(){
  console.log('客户端:已经与服务端建立连接');
});

client.on('data', function(data){
  console.log('客户端:收到服务端数据,内容为{'+ data +'}');
});

client.on('close', function(data){
  console.log('客户端:连接断开');
});

client.end('你好,我是客户端');

API、属性归类

以下对net.Socket的API跟属性,按照用途进行了大致的分类,方便读者更好的理解。大部分API跟属性都比较简单,看下文档就知道做什么的,这里就先不展开。

连接相关

  • socket.connect():有3种不同的参数,用于不同的场景;
  • socket.setTimeout():用来进行连接超时设置。
  • socket.setKeepAlive():用来设置长连接。
  • socket.destroy()、socket.destroyed:当错误发生时,用来销毁socket,确保这个socket上不会再有其他的IO操作。

数据读、写相关

socket.write()、socket.end()、socket.pause()、socket.resume()、socket.setEncoding()、socket.setNoDelay()

数据属性相关

socket.bufferSize、socket.bytesRead、socket.bytesWritten

事件循环相关

socket.ref()、socket.unref()

地址相关

  • socket.address()
  • socket.remoteAddress、socket.remoteFamily、socket.remotePort
  • socket.localAddress/socket.localPort

事件简介

  • data:当收到另一侧传来的数据时触发。
  • connect:当连接建立时触发。
  • close:连接断开时触发。如果是因为传输错误导致的连接断开,则参数为error。
  • end:当连接另一侧发送了 FIN 包的时候触发(读者可以回顾下HTTP如何断开连接的)。默认情况下(allowHalfOpen == false),socket会完成自我销毁操作。但你也可以把 allowHalfOpen 设置为 true,这样就可以继续往socket里写数据。当然,最后你需要手动调用 socket.end()
  • error:当有错误发生时,就会触发,参数为error。(官方文档基本一句话带过,不过考虑到出错的可能太多,也可以理解)
  • timeout:提示用户,socket 已经超时,需要手动关闭连接。
  • drain:当写缓存空了的时候触发。(不是很好描述,具体可以看下stream的介绍)
  • lookup:域名解析完成时触发。

相关链接

官方文档:https://nodejs.org/api/net.html#net_socket_destroy_exception

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

NodeJs 相关文章推荐
Nodejs使用mysql模块之获得更新和删除影响的行数的方法
Mar 18 NodeJs
Nodejs中的this详解
Mar 26 NodeJs
用NodeJS实现批量查询地理位置的经纬度接口
Aug 16 NodeJs
详解nodejs中的process进程
Mar 19 NodeJs
nodejs学习笔记之路由
Mar 27 NodeJs
nodejs实现邮件发送服务实例分享
Mar 29 NodeJs
nodejs服务搭建教程 nodejs访问本地站点文件
Apr 07 NodeJs
详解nodejs微信公众号开发——1.接入微信公众号
Apr 10 NodeJs
浅谈nodejs中的类定义和继承的套路
Jul 26 NodeJs
NodeJS爬虫实例之糗事百科
Dec 14 NodeJs
NodeJS父进程与子进程资源共享原理与实现方法
Mar 16 NodeJs
详解Nodejs内存治理
May 13 NodeJs
Nodejs进阶:基于express+multer的文件上传实例
Nov 21 #NodeJs
Nodejs进阶:如何将图片转成datauri嵌入到网页中去实例
Nov 21 #NodeJs
Nodejs下DNS缓存问题浅析
Nov 16 #NodeJs
NodeJS中的MongoDB快速入门详细教程
Nov 11 #NodeJs
Nodejs中解决cluster模块的多进程如何共享数据问题
Nov 10 #NodeJs
NodeJS整合银联网关支付(DEMO)
Nov 09 #NodeJs
nodejs的HTML分析利器node-jquery用法浅析
Nov 08 #NodeJs
You might like
让PHP开发者事半功倍的十大技巧小结
2010/04/20 PHP
php正则表达式学习笔记
2015/11/13 PHP
PHP绕过open_basedir限制操作文件的方法
2018/06/10 PHP
让JavaScript 轻松支持函数重载 (Part 1 - 设计)
2009/08/04 Javascript
关于IE、Firefox、Opera页面呈现异同 写脚本很痛苦
2009/08/28 Javascript
使用jQuery简化Ajax开发 Ajax开发入门
2009/10/14 Javascript
js控制div及网页相关属性的代码
2009/12/19 Javascript
JavaScript中创建类/对象的几种方法总结
2013/11/29 Javascript
浅谈Javascript 数组与字典
2015/01/29 Javascript
使用window.prompt()实现弹出用户输入的对话框
2015/04/13 Javascript
javascript伸缩菜单栏实现代码分享
2015/11/12 Javascript
Jqgrid之强大的表格插件应用
2015/12/02 Javascript
分享jQuery封装好的一些常用操作
2016/07/28 Javascript
深入理解bootstrap框架之入门准备
2016/10/09 Javascript
详解Jquery Easyui的验证扩展
2017/01/09 Javascript
Vue.use源码分析
2017/04/22 Javascript
angular.js指令中transclude选项及ng-transclude指令详解
2017/05/24 Javascript
layui表格checkbox选择全选样式及功能的实例
2018/03/07 Javascript
微信小程序如何自定义table组件
2019/06/29 Javascript
跟老齐学Python之用while来循环
2014/10/02 Python
python使用 HTMLTestRunner.py生成测试报告
2017/10/20 Python
python主线程捕获子线程的方法
2018/06/17 Python
python flask解析json数据不完整的解决方法
2019/05/26 Python
6行Python代码实现进度条效果(Progress、tqdm、alive-progress​​​​​​​和PySimpleGUI库)
2020/01/06 Python
Python实现动态给类和对象添加属性和方法操作示例
2020/02/29 Python
python/golang 删除链表中的元素
2020/09/14 Python
Python __slots__的使用方法
2020/11/15 Python
html5使用html2canvas实现浏览器截图的示例
2017/08/31 HTML / CSS
世界上最大的皮肤科医生拥有和经营的美容网站:LovelySkin
2021/01/03 全球购物
销售自我评价
2013/10/22 职场文书
外贸业务员的岗位职责
2013/11/23 职场文书
班主任工作经验材料
2014/02/02 职场文书
关心下一代工作先进事迹
2014/08/15 职场文书
2014年军人思想汇报范文
2014/10/12 职场文书
小学开学典礼新闻稿
2015/07/17 职场文书
如何用PHP实现分布算法之一致性哈希算法
2021/05/26 PHP