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

首頁 > 編程 > JavaScript > 正文

深入Node TCP模塊的理解

2019-11-19 11:59:57
字體:
供稿:網(wǎng)友

1. TCP

在Node.js中,提供了net模塊用來實(shí)現(xiàn)TCP服務(wù)器和客戶端的通信。

1.1 TCP服務(wù)器

net.createServer([options][, connectionListener])

  • options.allowHalfOpen 是否允許單方面連接,默認(rèn)值為false
  • connectionListener參數(shù)用于指定當(dāng)客戶端與服務(wù)器建立連接時所要調(diào)用的回調(diào)函數(shù),回調(diào)中有一個參數(shù)socket,指的是TCP服務(wù)器監(jiān)聽的socket端口對象

也可以通過監(jiān)聽connection事件的方式來指定監(jiān)聽函數(shù)

server.on('connection',function(socket){});

1.1.1 啟動TCP服務(wù)器

可以使用listen方法通知服務(wù)器開始監(jiān)聽客戶端的連接

server.listen(port,[host],[backlog],[callback])

  • port 必須指定的端口號
  • host 指定需要監(jiān)聽的IP地址或主機(jī)名,如果省略的話服務(wù)器將監(jiān)聽來自于任何客戶端的連接
  • backlog指定位于等待隊(duì)列中的客戶端連接的最大數(shù)量,默認(rèn)值為511
server.on('listening',function(){});

1.1.2 使用TCP服務(wù)器

let net = require('net');let server = net.createServer(function(socket){ console.log('客戶端已連接');});server.listen(8080,'localhost',function(){  console.log('服務(wù)器開始監(jiān)聽');});

1.1.3 address

server.address()
  • port 端口號
  • address TCP服務(wù)器監(jiān)聽的地址
  • family 協(xié)議的版本

1.1.4 getConnections

查看當(dāng)前與TCP服務(wù)器建立連接的客戶端的連接數(shù)量以及設(shè)置最大連接數(shù)量

server.getConnections(callback); server.maxConnections = 2;

1.1.5 close

使用close方法可以顯式拒絕所有的客戶端的連接請求,當(dāng)所有已連接的客戶端關(guān)閉后服務(wù)器會自動關(guān)閉,并觸發(fā)服務(wù)器的close事件。

server.close();server.on('close',callback);

1.2 socket

1.2.1 address

net.Socket代表一個socket端口對象,它是一個可讀可寫流。

let net = require('net');let util = require('util');let server = net.createServer(function(socket){ server.getConnections((err,count)=>{   server.maxConnections = 1;   console.log('最大連接數(shù)量%d,當(dāng)前連接數(shù)量%d',server.maxConnections,count);  });  let address = socket.address(); console.log('客戶端地址 %s',util.inspect(address));});

1.2.2 讀取數(shù)據(jù)

let server = net.createServer(function (socket) {  socket.setEncoding('utf8');  socket.on('data', function (data) {    console.log('本次收到的內(nèi)容為%s,累計(jì)收到的字節(jié)數(shù)是%d', data, socket.bytesRead);  });});

1.2.3 監(jiān)聽關(guān)閉事件

let server = net.createServer(function (socket) {  socket.on('end', function () {    console.log('客戶端已經(jīng)關(guān)閉');  });});

1.2.4 pipe

pipe方法可以將客戶端發(fā)送的數(shù)據(jù)寫到文件或其它目標(biāo)中。

socket.pipe(destinatin,[options]);

options.end 設(shè)置為false時當(dāng)客戶端結(jié)束寫操作或關(guān)閉后并不會關(guān)閉目標(biāo)對象,還可以繼續(xù)寫入數(shù)據(jù)

let net = require('net');let path = require('path');let ws = require('fs').createWriteStream(path.resolve(__dirname, 'msg.txt'));let server = net.createServer(function (socket) {  socket.on('data', function (data) {    console.log(data);  });  socket.pipe(ws, { end: false });  socket.on('end', function () {    ws.end('over', function () {      socket.unpipe(ws);    });  });});

1.2.5 unpipe

const net = require('net');const path = require('path');let file = require('fs').createWriteStream(path.join(__dirname, 'msg.txt'));let server = net.createServer(function (socket) {  socket.pipe(file, {    end: false  });  setTimeout(function () {    file.end('bye bye');    socket.unpipe(file);  }, 5000);  // socket.on('end', function () {  //   file.end('bye bye');  // });});server.listen(8080);

1.2.5 pause&resume

pause 可以暫停 data 事件觸發(fā),服務(wù)器會把客戶端發(fā)送的數(shù)據(jù)暫存在緩存區(qū)里

const net = require('net');const net = require('net');const path = require('path');let file = require('fs').createWriteStream(path.join(__dirname, 'msg.txt'));let server = net.createServer(function (socket) {  socket.pause();  setTimeout(function () {    socket.resume();    socket.pipe(file);  }, 10 * 1000);});server.listen(8080);

1.2.6 setTimeout

let net = require('net');let path = require('path');let ws = require('fs').createWriteStream(path.resolve(__dirname, 'msg.txt'));let server = net.createServer(function (socket) {  socket.setTimeout(5 * 1000);  socket.pause();  socket.on('timeout', function () {    socket.pipe(ws);  });  //socket.setTimeout(0);取消超時時間的設(shè)置});server.listen(8080);

1.2 TCP客戶端

1.2.1 創(chuàng)建TCP客戶端

let socket = new net.Socket([options])
  • fd socket文件描述符
  • type 客戶端所有協(xié)議
  • allowHalfOpen 是否允許半連接,服務(wù)器收到FIN包時不回發(fā)FIN包,可以使服務(wù)器可以繼續(xù)向客戶端發(fā)數(shù)據(jù)
socket.connect(port, host, callback);socket.on('connect', callback);

1.2.2 向服務(wù)器端寫入數(shù)據(jù)、end 、error、destroy,close

  • write表示向服務(wù)器寫入數(shù)據(jù)
  • end 用于結(jié)束連接
  • error 連接發(fā)生錯誤
  • destroy 銷毀流
  • close 表示連接關(guān)閉成功,hasError=true代表有可能有錯誤
socket.write(data,[encoding],[callback]);
let net = require('net');let server = net.createServer(function (socket) {  console.log("客戶端已經(jīng)連接");  socket.setEncoding('utf8');  socket.on('data', function (data) {    console.log("已接收客戶端發(fā)送的數(shù)據(jù):%s", data);    socket.write('服務(wù)器:' + data);  })  socket.on('error', function (err) {    console.log('與客戶端通信過程中發(fā)生了錯誤,錯誤編碼為%s', err.code);    socket.destroy();  });  socket.on('end', function (err) {    console.log('客戶端已經(jīng)關(guān)閉連接');    socket.destroy();  });  socket.on('close', function (hasError) {    console.log(hasError ? '異常關(guān)閉' : '正常關(guān)閉');  });});server.listen(808, function () {  let client = new net.Socket();  client.setEncoding('utf8');  client.connect(808, '127.0.0.1', function () {    console.log('客戶端已連接');    client.write('hello');    setTimeout(function () {      client.end('byebye');    }, 5000);  });  client.on('data', function (data) {    console.log('已經(jīng)接收到客戶端發(fā)過來的數(shù)據(jù):%s', data);  });  client.on('error', function (err) {    console.log('與服務(wù)器通信過程中發(fā)生了錯誤,錯誤編碼為%s', err.code);    client.destroy();  });});

1.2.3 close

停止server接受建立新的connections并保持已經(jīng)存在的connections

server.getConnections((err, count) => {   if (count == 2) server.close(); });

1.2.4 unref&ref

unref方法指定發(fā)客戶端連接被全部關(guān)閉時退出應(yīng)用程序 如果將allowHalfOpen方法,必須使用與客戶端連接的socket端口對象的end 方法主動關(guān)閉服務(wù)器端連接

let net = require('net');let server = net.createServer({ allowHalfOpen: true }, function (socket) {  console.log("客戶端已經(jīng)連接");  socket.setEncoding('utf8');  socket.on('data', function (data) {    console.log("已接收客戶端發(fā)送的數(shù)據(jù):%s", data);    socket.write('服務(wù)器確認(rèn)數(shù)據(jù):' + data);  })  socket.on('error', function (err) {    console.log('與客戶端通信過程中發(fā)生了錯誤,錯誤編碼為%s', err.code);    socket.destroy();  });  socket.on('end', function (err) {    console.log('客戶端已經(jīng)關(guān)閉連接');    socket.end();    server.unref();  });  socket.on('close', function (hasError) {    if (hasError) {      console.log('由于錯誤導(dǎo)致socket關(guān)閉');      server.unref();    } else {      console.log('端口正常關(guān)閉');    }  });  server.getConnections((err, count) => {    if (count == 2) server.close();  });});server.listen(808, function () { });server.on('close', function () {  console.log('服務(wù)器關(guān)閉');});

1.2.5 bufferSize

write的返回值和bufferSize屬性值

let server = net.createServer({ allowHalfOpen: true }, function (socket) {  console.log("客戶端已經(jīng)連接");  socket.setEncoding('utf8');  let rs = fs.createReadStream(path.resolve(__dirname, 'a.txt'), { highWaterMark: 2 });  rs.on('data', function (data) {    let flag = socket.write(data);    console.log("flag:", flag);    console.log('緩存字節(jié):' + socket.bufferSize);    console.log('已發(fā)送字節(jié):' + socket.bytesWritten);  })  socket.on('data', function (data) {    console.log('data', data);  });  socket.on('drain', function (err) {    "緩存區(qū)已全部發(fā)送"  });});

1.2.6 keepAlive

當(dāng)服務(wù)器和客戶端建立連接后,當(dāng)一方主機(jī)突然斷電、重啟、系統(tǒng)崩潰等意外情況時,將來不及向另一方發(fā)送FIN包,這樣另一方將永遠(yuǎn)處于連接狀態(tài)。 可以使用setKeepAlive方法來解決這一個問題

socket.setKeepAlive([enaable],[initialDelay]);
  • enable 是否啟用嗅探,為true時會不但向?qū)Ψ桨l(fā)送探測包,沒有響應(yīng)則認(rèn)為對方已經(jīng)關(guān)閉連接,自己則關(guān)閉連接
  • initialDelay 多久發(fā)送一次探測包,單位是毫秒

1.2.7 聊天室1.0

/** * 1.創(chuàng)建一個服務(wù)器 * 2. 客戶端可以連接服務(wù)器 * 3.客戶端可以發(fā)言,然后廣播給大家 * 4.客戶端連接和退出后都要通知大家。 * 5.顯示當(dāng)前的在線人數(shù) */let net = require('net');let util = require('util');let clients = {};let server = net.createServer(function (socket) {  server.getConnections(function (err, count) {    socket.write(`weclome,there is ${count} users now,please input your username/r/n`);  });  let nickname;  socket.setEncoding('utf8');  socket.on('data', function (data) {    data = data.replace(//r/n/, '');    if (data == 'byebye') {      socket.end();    } else {      if (nickname) {        broadcast(nickname, `${nickname}:${data}`);      } else {        nickname = data;        clients[nickname] = socket;        broadcast(nickname, `welcome ${nickname} joined us!`);      }    }  });  socket.on('close', function () {    socket.destroy();  });}).listen(8088);function broadcast(nickname, msg) {  for (let key in clients) {    if (key != nickname) {      clients[key].write(msg + '/r/n');      clients[nickname].destroy();      delete clients[nickname];    }  }}

1.2.8 聊天室2.0

var key = scoket.remoteAddress+':'+socket.remotePort;users[key] = {name:'匿名',socket};socket.on('data',function(){  parse(data);});function parse(msg){ swtich(msg.type){  case 'secret':   secret(msg.user,msg.text);   break; } case 'boardcast':   boardcast(message.text);   break; case 'cname':   cname(messsage.text);   break; case 'list':   list();   break;   default:   socket.write('不能識別命令');   break;}function secret(user,text){}function boardcast(text){}function cname(text){}function list(){}
b:text 廣播c:nickname:text 私聊n:nickname 改名l 列出在線用戶列表 on('data',function(data){  if(data == 'quit){  }else if(data == 'help'){  }else(){   write(data);  }});function convert(){}

1.3 類方法

  • isIP 判斷字符串是否是IP
  • isIPv4 判斷字符串是否是IPv4地址
  • isIPv6 判斷字符串是否是IPv6地址

2. UDP

2.1 創(chuàng)建socket

let socket = dgram.createSocket(type,[callback]);socket.on('messsage',function(msg,rinfo){});
  • type 必須輸入,制定時udp4還是udp6
  • callback 從該接口接收到數(shù)據(jù)時調(diào)用的回調(diào)函數(shù)
    • msg 接收到的數(shù)據(jù)
    • rinfo 信息對象
      • address 發(fā)送著的地址
      • family ipv4還是ipv6
      • port 發(fā)送者的socket端口號
      • size 發(fā)送者所發(fā)送的數(shù)據(jù)字節(jié)數(shù)
socket.bind(port,[address],[callback]);socket.on('listening',callabck;
  • port 綁定的端口號
  • address 監(jiān)聽的地址
  • callback 監(jiān)聽成功后的回調(diào)函數(shù)

2.2 向外發(fā)送數(shù)據(jù)

如果發(fā)送數(shù)據(jù)前還沒有綁定過地址和端口號,操作系統(tǒng)將為其分配一個隨機(jī)端口并可以接收任何地址的數(shù)據(jù)

socket.send(buf,offset,length,port,address,[callback]);
  • buffer 代表緩存區(qū)
  • offset 從緩存區(qū)第幾個字節(jié)開始發(fā)
  • length 要發(fā)送的字節(jié)數(shù)
  • port 對方的端口號
  • address 接收數(shù)據(jù)的socket地址
  • callback 制定當(dāng)數(shù)據(jù)發(fā)送完畢時所需要的回調(diào)函數(shù)
    • err 錯誤對象
    • byets 實(shí)際發(fā)送的字節(jié)數(shù)

2.3 address

獲取此socket相關(guān)的地址信息

let address = socket.address();
  • port
  • address
  • family

2.4 UDP服務(wù)器

var dgram = require('dgram');var socket = dgram.createSocket('udp4');socket.on('message',function(msg,rinfo){ console.log(msg.toString()); console.log(rinfo);  socket.send(msg,0,msg.length,rinfo.port,rinfo.address);});socket.bind(41234,'localhost');

2.5 UDP客戶端

var dgram = require('dgram');var socket = dgram.createSocket('udp4');socket.on('message',function(msg,rinfo){  console.log(msg.toString());  console.log(rinfo);});socket.setTTL(128);socket.send(new Buffer('zz'),0,6,41234,'localhost',function(err,bytes){  console.log('發(fā)送了個%d字節(jié)',bytes);});socket.on('error',function(err){  console.error(err);});

2.6 廣播

創(chuàng)建一個UDP服務(wù)器并通過該服務(wù)器進(jìn)行數(shù)據(jù)的廣播

2.6.1 服務(wù)器

let dgram = require('dgram');let server = dgram.createSocket('udp4);server.on('message',function(msg){ let buf = new Bufffer('已經(jīng)接收客戶端發(fā)送的數(shù)據(jù)'+msg); server.setBroadcast(true); server.send(buf,0,buf.length,41235,"192.168.1.255");});server.bind(41234,'192.168.1.100');

2.6.2 客戶端

let dgram = require('dgram');let client = dgram.createSocket('udp4);client.bind(41235,'192.168.1.102);let buf = new Buffer('hello');client.send(buf,0,buf.length,41234,'192.168.1.100');client.on('message',function(msg,rinfo){ console.log('received : ',msg);});

2.7 組播

所謂的組播,就是將網(wǎng)絡(luò)中同一業(yè)務(wù)類型進(jìn)行邏輯上的分組,從某個socket端口上發(fā)送的數(shù)據(jù)只能被該組中的其他主機(jī)所接收,不被組外的任何主機(jī)接收。

實(shí)現(xiàn)組播時,并不直接把數(shù)據(jù)發(fā)送給目標(biāo)地址,而是將數(shù)據(jù)發(fā)送到組播主機(jī),操作系統(tǒng)將把該數(shù)據(jù)組播給組內(nèi)的其他所有成員。

在網(wǎng)絡(luò)中,使用D類地址作為組播地址。范圍是指 224.0.0.0 ~ 239.255.255.255,分為三類

  • 局部組播地址: 224.0.0.0 ~ 224.0.0.255 為路由協(xié)議和其他用途保留
  • 預(yù)留組播地址: 224.0.1.0 ~ 238.255.255.255 可用于全球范圍或網(wǎng)絡(luò)協(xié)議
  • 管理權(quán)限組播地址 : 239.0.0.0 ~ 239.255.255.255 組織內(nèi)部使用,不可用于Internet

把該socket端口對象添加到組播組中。

socket.addMembership(multicastAddress,[multicastInterface]);
  • multicastAddress 必須指定,需要加入的組播組地址
  • multicastInterface 可選參數(shù),需要加入的組播組地址
socket.dropMembership(multicastAddress,[multicastInterface]);socket.setMulticastTTL(ttl);socket.setMulticastLoopback(flag);

2.7.1 服務(wù)器

let dgram = require('dgram');let server = dgram.createSocket('udp4');server.on('listening',function(){ server.MulticastTTL(128); server.setMulticastLoopback(true); server.addMembership('230.185.192.108');});setInterval(broadcast,1000);function broadcast(){ let buffer = Buffer.from(new Date().toLocaleString()); server.send(buffer,0,buffer.length,8080,"230.185.192.108");}

2.7.2 客戶端

let dgram = require('dgram');let client = dgram.createSocket('udp4');client.on('listening',function(){  client.addMembership('230.185.192.108');});client.on('message',function(message,remote){ console.log(message.toString());});client.bind(8080,'192.168.1.103');

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 龙州县| 灌云县| 林口县| 天峻县| 绥中县| 连云港市| 甘谷县| 德保县| 磐石市| 宝鸡市| 柳州市| 尤溪县| 甘孜| 沁阳市| 和林格尔县| 句容市| 彰化市| 梨树县| 梅河口市| 阿克苏市| 连平县| 会同县| 平武县| 屯昌县| 新宁县| 瑞金市| 普兰店市| 奈曼旗| 丰台区| 丹凤县| 南溪县| 景东| 武穴市| 诏安县| 荆州市| 商水县| 胶南市| 阳江市| 金寨县| 通辽市| 曲水县|