国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Nodejs學(xué)習(xí)筆記之NET模塊

2019-11-20 13:25:19
字體:
供稿:網(wǎng)友

一,開篇分析

從今天開始,我們來深入具體的模塊學(xué)習(xí),這篇文章是這個(gè)系列文章的第三篇,前兩篇主要是以理論為主,相信大家在前兩篇的學(xué)習(xí)中,

對(duì)NodeJS也有一個(gè)基本的認(rèn)識(shí),沒事?。?!趁熱打鐵,讓我們繼續(xù)將NodeJS進(jìn)行到底,好了廢話不多說,直接進(jìn)入今天的主題 “Net模塊” ,那么”Net“應(yīng)該如何理解那?

它是做什么用的那?(Net模塊可用于創(chuàng)建Socket服務(wù)器或Socket客戶端。NodeJS 的數(shù)據(jù)通信,最基礎(chǔ)的兩個(gè)模塊是 Net 和 Http,前者是基于 Tcp 的封裝,后者本質(zhì)還是 Tcp 層,只不過做了比較多的數(shù)據(jù)封裝,我們視為表現(xiàn)層)。

這里參考一下NodeJS “http.js” 中的源碼:

從圖中不難看出 HttpServer繼承了Net類,具有了相關(guān)的通信能力,做了比較多的數(shù)據(jù)封裝,我們視為更高級(jí)的表現(xiàn)層。

擴(kuò)展知識(shí)(以下是“inherits”的源碼):

復(fù)制代碼 代碼如下:

exports.inherits = function(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
};

功能是實(shí)現(xiàn)繼承復(fù)用。

剛才做了一個(gè)簡(jiǎn)要的概述,里面有一些常用的概念,這里做個(gè)簡(jiǎn)短的概念普及介紹:

 ?。?),TCP/IP------TPC/IP協(xié)議是傳輸層協(xié)議,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸。

 ?。?),Socket------socket則是對(duì)TCP/IP協(xié)議的封裝和應(yīng)用(程序?qū)用?。

 ?。?),Http------HTTP是應(yīng)用層協(xié)議,主要解決如何包裝數(shù)據(jù)。

  (4),網(wǎng)絡(luò)七層模型------物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會(huì)話層、表示層和應(yīng)用層。

  總結(jié)一下:Socket是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API)。

  從而形成了我們知道的一些最基本的函數(shù)接口,比如Create、Listen、Connect、Accept、Send、Read和Write等等。

  TCP/IP只是一個(gè)協(xié)議棧,就像操作系統(tǒng)的運(yùn)行機(jī)制一樣,必須要具體實(shí)現(xiàn),同時(shí)還要提供對(duì)外的操作接口

  實(shí)際上,傳輸層的TCP是基于網(wǎng)絡(luò)層的IP協(xié)議的,而應(yīng)用層的HTTP協(xié)議又是基于傳輸層的TCP協(xié)議的,而Socket本身不算是協(xié)議,就像上面所說,它只是提供了一個(gè)針對(duì)TCP或者UDP編程的接口。

二,體驗(yàn)一把

好了,概念我們也有了,來個(gè)例子:

1,建立server.js

復(fù)制代碼 代碼如下:

var net = require('net') ;
var server = net.createServer(function(c) { // Connection監(jiān)聽器
  console.log("服務(wù)器已連接") ;
  c.on("end", function() {
    console.log("服務(wù)器已斷開") ;
  }) ;
  c.write("Hello,Bigbear !/r/n") ;
  c.pipe(c) ;
}) ;
server.listen(8124, function() { // Listening監(jiān)聽器
  console.log("服務(wù)器已綁定") ;
}) ;

2,建立client.js

復(fù)制代碼 代碼如下:

var net = require('net') ;
var client = net.connect({
    port: 8124
},function(){ // connect監(jiān)聽器
  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("客戶端斷開連接") ;
}) ;

分析一下:

服務(wù)端------net.createServer創(chuàng)建一個(gè) TCP 服務(wù),這個(gè)服務(wù)綁定(server.listen)在 8124 這個(gè)端口上,創(chuàng)建 Server 后我們看到有一個(gè)回調(diào)函數(shù),

在調(diào)用上面函數(shù)的時(shí)候傳入一個(gè)參數(shù),這個(gè)參數(shù)也是函數(shù),并且接受了 socket ,這個(gè)由其他方法構(gòu)造的一個(gè)管道(pipe),他的作用就是用來數(shù)據(jù)交互的。

pipe 是需要 Client 跟 Server 打招呼才能建立的,如果此刻沒有客戶端訪問 Server,這個(gè) socket 就不會(huì)存在了。

客戶端------net.connect顧名思義,就是連接到服務(wù)端,第一個(gè)參數(shù)是對(duì)象,設(shè)置端口(port)為 8124,也就是我們服務(wù)器監(jiān)聽的端口,由于沒有設(shè)置 host 參數(shù),那默認(rèn)就是 localhost (本地)。

在 Server 中,socket 是管道的一端,而在 client 中,client 本身就是管道的一端,如果是多個(gè)客戶端連接 Server,Server 會(huì)新建多個(gè) socket,每個(gè) socket 對(duì)應(yīng)一個(gè) client。

運(yùn)行結(jié)果:

三,案例引入

(1),下面代碼僅僅是服務(wù)器向客戶端輸出一段文本,完成服務(wù)端到客戶端的單向通訊。

復(fù)制代碼 代碼如下:

//  Sever --> Client 的單向通訊
var net = require('net');
var chatServer = net.createServer();
chatServer.on('connection', function(client) {
  client.write('Hi!/n'); // 服務(wù)端向客戶端輸出信息,使用 write() 方法
  client.write('Bye!/n');
  client.end(); // 服務(wù)端結(jié)束該次會(huì)話
});
chatServer.listen(9000);

Telnet測(cè)試一下:telnet127.0.0.1:9000

執(zhí)行 telnet后,與服務(wù)點(diǎn)連接,反饋 Hi! Bye! 的字符,并立刻結(jié)束服務(wù)端程序終止連接。

如果我們要服務(wù)端接到到客戶端的信息?

可以監(jiān)聽 server.data 事件并且不要中止連接(否則會(huì)立刻結(jié)束無法接受來自客戶端的消息)。

(2),監(jiān)聽 server.data 事件并且不要中止連接(否則會(huì)立刻結(jié)束無法接受來自客戶端的消息)。

復(fù)制代碼 代碼如下:

// 在前者的基礎(chǔ)上,實(shí)現(xiàn) Client --> Sever 的通訊,如此一來便是雙向通訊
var net = require('net');
var chatServer = net.createServer(),   
    clientList = [];
chatServer.on('connection', function(client) {
  // JS 可以為對(duì)象自由添加屬性。這里我們添加一個(gè) name 的自定義屬性,用于表示哪個(gè)客戶端(客戶端的地址+端口為依據(jù))
  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);

上面是不是一個(gè)完整功能的代碼呢?我們說還有一個(gè)問題沒有考慮進(jìn)去:那就是一旦某個(gè)客戶端退出,卻仍保留在 clientList里面,這明顯是一個(gè)空指針。

(3),處理clientList

復(fù)制代碼 代碼如下:

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); // 刪除數(shù)組中的制定元素。
  })
})

NodeTCPAPI已經(jīng)為我們提供了 end 事件,即客戶端中止與服務(wù)端連接的時(shí)候發(fā)生。

(4),優(yōu)化broadcast

復(fù)制代碼 代碼如下:

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” 沒有被觸發(fā),會(huì)出現(xiàn)異常,所以才做優(yōu)化工作。

(5),NetAPI中還提供一個(gè) error 事件,用于捕捉客戶端的異常

復(fù)制代碼 代碼如下:

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

四,總結(jié)一下

1,理解開篇的相關(guān)概念

2,認(rèn)識(shí)Http與Net模塊之間的關(guān)系

3,結(jié)合本文的例子,查閱相關(guān)api去實(shí)踐

4,socket客戶端與服務(wù)器端之間的通信思想

5,有興趣可以完善一下那個(gè)聊天室的例子

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 阳西县| 离岛区| 黄平县| 旌德县| 凌云县| 柳河县| 建瓯市| 信阳市| 民县| 盐山县| 平塘县| 澎湖县| 德阳市| 浑源县| 赣榆县| 大英县| 鹤庆县| 藁城市| 陈巴尔虎旗| 宜兴市| 衡南县| 开远市| 靖远县| 平潭县| 信丰县| 镶黄旗| 鹿泉市| 蚌埠市| 炉霍县| 措美县| 盐亭县| 珠海市| 梓潼县| 栖霞市| 沈丘县| 清徐县| 平潭县| 靖安县| 长沙市| 兴文县| 扶绥县|