您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息
免费发信息
三六零分类信息网 > 黄南分类信息网,免费分类信息发布

Nodejs学习笔记之NET模块_node.js

2024/3/27 10:57:48发布30次查看
一,开篇分析
从今天开始,我们来深入具体的模块学习,这篇文章是这个系列文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中,
对nodejs也有一个基本的认识,没事!!!趁热打铁,让我们继续将nodejs进行到底,好了废话不多说,直接进入今天的主题 “net模块” ,那么”net“应该如何理解那?
它是做什么用的那?(net模块可用于创建socket服务器或socket客户端。nodejs 的数据通信,最基础的两个模块是 net 和 http,前者是基于 tcp 的封装,后者本质还是 tcp 层,只不过做了比较多的数据封装,我们视为表现层)。
这里参考一下nodejs “http.js” 中的源码:
从图中不难看出 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。
运行结果:
三,案例引入
(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      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    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    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,有兴趣可以完善一下那个聊天室的例子
黄南分类信息网,免费分类信息发布

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录