[Nodejs]初探nodejs学习笔记- 如何使用nodejs搭建简单的UDP聊天功能
2019獨角獸企業重金招聘Python工程師標準>>>
何為UDP(User Datagram Protocol)?
從baidu摘過來一段:UDP,用戶數據報協議,與所熟知的TCP(傳輸控制協議)協議一樣,UDP協議直接位于IP(網際協議)協議的頂層。根據OSI(開放系統互連)參考模型,UDP和TCP都屬于傳輸層協議。UDP協議的主要作用是將網絡數據流量壓縮成數據包的形式。一個典型的數據包就是一個二進制數據的傳輸單位。每一個數據包的前8個字節用來包含報頭信息,剩余字節則用來包含具體的傳輸數據。
UDP報文沒有可靠性保證、順序保證和流量控制字段等,可靠性較差。但是正因為UDP協議的控制選項較少,在數據傳輸過程中延遲小、數據傳輸效率高,適合對可靠性要求不高的應用程序,或者可以保障可靠性的應用程序,如DNS、TFTP、SNMP等。
好了,接下來簡要說明一下我實現的效果:
????????? ????? 防工具盜鏈抓取【如果顯示此文字,代表來自第三方轉發】 freddon所有? ??? ???????????
有Fred、Lenka、Nick三個人,均處于同一聊天室中:
即:Nick發的消息,Fred、Lenka均能收到;
????? ?Fred、Lenka只能互相發消息。
OK,就這么簡單。為了說明問題,就不過度封裝代碼,以說明為主。
????????? ????? 防工具盜鏈抓取【如果顯示此文字,代表來自第三方轉發】 freddon所有? ??? ???????????
Server端:
server.js
var?udp?=?require('dgram');var?server?=?udp.createSocket('udp4');/***?用于存儲人員之間的離線消息任務*?@type?{{tasks:?Array}}*/ var?msgTask?=?{//config:?{},tasks:?[] };/***?存醋當前在線的用戶*?@type?{{online:?Array,?pool:?Array}}*/ var?userPool?=?{online:?[],pool:?[] };/***?加入某個用戶的在線狀態*?@param?name*?@param?rinfo*/ var?pushIntoPool?=?function?(name,?rinfo)?{var?index?=?userPool.online.indexOf(name);if?(index?>=?0)?{userPool.online.splice(index,?1);userPool.pool.splice(index,?1);}userPool.online.push(name);userPool.pool.push({name:?name,?ip:?rinfo.address,?port:?rinfo.port}); };/***?移除在線狀態*?@param?name*/ var?pullFromPool?=?function?(name)?{var?index?=?userPool.online.indexOf(name);if?(index?>=?0)?{userPool.online.splice(index,?1);userPool.pool.splice(index,?1);return;} };/***?加入離線消息任務*?@param?msg*/ var?addInTask?=?function?(msg)?{msgTask.tasks.push({msg:?msg,?expireTime:?7?*?24?*?3600?+?new?Date().getTime()}); };/***?發送消息*?@param?m*?@param?rinfo*/ var?sendMsg?=?function?(m,?rinfo)?{process.nextTick(function?()?{if?(m.to){//獲取對方的服務地址\端口var?index?=?userPool.online.indexOf(m.to.name);if?(index?>=?0)?{//在線var?config?=?userPool.pool[index];var?msg?=?JSON.stringify(m);server.send(msg,?0,?Buffer.byteLength(msg,?encoding?=?'utf8'),?config.port,?config.ip,?function?(err,?bytes)?{if?(err)?{//發送失敗//緩存數據addInTask(m);}});}?else?{if?(rinfo)?{//離線var?content?=?JSON.stringify({content:?m.to.name?+?'不在線'});server.send(content,?0,?Buffer.byteLength(content,?encoding?=?'utf8'),?rinfo.port,?rinfo.address,?function?(err,?bytes)?{if?(err)?{//發送失敗}});}//不在線pullFromPool(m.to.name);//緩存數據addInTask(m);}}?else?{//群聊for?(var?i?=?0;?i?<?userPool.pool.length;?i++)?{var?to_cfg?=?userPool.pool[i];if?(to_cfg.name?==?m.from.name)?{continue;}?else?{var?msg?=?JSON.stringify(m);server.send(msg,?0,?Buffer.byteLength(msg,?encoding?=?'utf8'),?to_cfg.port,?to_cfg.ip,?function?(err,?bytes)?{if?(err)?{//發送失敗}});}}}}); };/***?后臺輪詢任務*/ var?backgroundTask?=?function?()?{for?(var?i?=?0;?i?<?msgTask.tasks.length;?i++)?{var?m?=?msgTask.tasks.splice(i,?1)[0];sendMsg(m.msg);}beginTask(); };var?tid;var?beginTask?=?function?()?{clearTimeout(tid);tid?=?setTimeout(backgroundTask,?1000); };server.on('message',?function?(msg,?rinfo)?{//注意msg為Buffer對象var?m?=?JSON.parse(msg.toString());pushIntoPool(m.from.name,?rinfo);if?(m.action?==?'online')?{console.log('當前聊天室在線人數%d::%s',?userPool.online.length,userPool.online.join(","));return;}//發送消息sendMsg(m,?rinfo); }).bind(8124,?function?()?{console.log('服務端啟動成功');//當服務啟動后,開啟后臺消息輪詢服務beginTask(); });Client端:
Fred.js 用戶fred
var?udp=require('dgram'); var?mm=require('./msgmodel'); var?client=udp.createSocket('udp4'); var?from={name:'Fred',host:client.address,port:client.remotePort,content:'' }; var?msg=new?mm.FMsg(from); process.stdin.resume(); process.stdin.on('data',function(data){msg.setAction('chat');msg.setContent(data.toString('utf8'));//設置只能發送給Lenkamsg.setTo({name:'Lenka'});msg.udpSendMsg(client,function(err,bytes){if(err){//發送失敗}});}); client.on('message',function(data){var?data=JSON.parse(data.toString());if(!data.from){console.log(data.content);}else{if(!data.to){console.log("[%s]:%s",data.from.name,data.content);}else{console.log("[%s@%s]:%s",data.from.name,data.to.name,data.content);}} }); //默認連接后上線操作 msg.udpSendMsg(client,function(err,bytes){if(err==0){console.log("Fred上線!");} });Lenka.js 用戶Lenka
var?udp=require('dgram'); var?mm=require('./msgmodel'); var?client=udp.createSocket('udp4'); var?from={name:'Lenka',host:client.address,port:client.remotePort,content:'' }; var?msg=new?mm.FMsg(from); process.stdin.resume(); process.stdin.on('data',function(data){msg.setAction('chat');msg.setContent(data.toString('utf8'));//設置只能發送給Fredmsg.setTo({name:'Fred'});msg.udpSendMsg(client,function(err,bytes){if(err){//發送失敗}});}); client.on('message',function(data){var?data=JSON.parse(data.toString());if(!data.from){console.log(data.content);}else{if(!data.to){console.log("[%s]:%s",data.from.name,data.content);}else{console.log("[%s@%s]:%s",data.from.name,data.to.name,data.content);}} }); //默認連接后上線操作 msg.udpSendMsg(client,function(err,bytes){if(err==0){console.log("Lenka上線!");} });Nick.js 用戶Nick
var?udp=require('dgram'); var?mm=require('./msgmodel'); var?client=udp.createSocket('udp4'); var?from={name:'Nick',host:client.address,port:client.remotePort,content:'' }; var?msg=new?mm.FMsg(from); process.stdin.resume(); process.stdin.on('data',function(data){msg.setAction('chat');msg.setContent(data.toString('utf8'));//不設置發送給誰,默認發送給所有人msg.udpSendMsg(client,function(err,bytes){if(err){//發送失敗}});}); client.on('message',function(datas){var?data=JSON.parse(data.toString());if(!data.from){console.log(data.content);}else{if(!data.to){console.log("[%s]:%s",data.from.name,data.content);}else{console.log("[%s@%s]:%s",data.from.name,data.to.name,data.content);}} }); //默認連接后上線操作 msg.udpSendMsg(client,function(err,bytes){if(err==0){console.log("Nick上線!");} });消息類msgmodel.js??
var?host?=?'127.0.0.1';//需要連接到服務器提供udp連接的ip var?port?=?8124;//需要連接到服務器提供udp連接的端口 var?ACTIONS=['online','chat','request','stranger','del','offline']; function?FMsg(from,?to,?content)?{this.from?=?from;this.to?=?to;this.content?=?content;this.action?=?'online';this.setAction?=?function?(action)?{this.action?=?action;};this.setTo?=?function?(to)?{this.to?=?to;};this.setContent?=?function?(content)?{this.content?=?content;};this.getMsg?=?function?()?{var?msg?=?{from:?this.from,to:?this.to,content:?this.content,action:this.action};return?JSON.stringify(msg);};this.udpSendMsg?=?function?(client,?callback)?{var?data?=?this.getMsg();client.send(data,?0,?Buffer.byteLength(data,encoding='utf8'),?port,?host,?callback);}; } exports.FMsg?=?FMsg;接下來分別使用nodejs啟動服務端和客戶端。
啟動服務端后,只啟動Fred、Lenka中的一個(比如說啟動了Fred):
在Fred控制臺進行如下輸入:(Lenka不在線,所以該消息未發送成功)
然后啟動Lenka,(Lenka收到了離線消息)Lenka的控制臺為:
啟動Nick,Nick說話,然后觀察其他兩個客戶端,
server:
nick:
fred:
lenka:
Lenka、Fred說話,觀察Nick控制臺:
Lenka:
fred:
nick:
好啦,相當簡單的一個點對點和聊天室的功能就這樣搭好了。
????????? ????? 防工具盜鏈抓取【如果顯示此文字,代表來自第三方轉發】 freddon所有? ??? ???????????
轉載請注明:http://my.oschina.net/freddon/blog/518328
轉載于:https://my.oschina.net/freddon/blog/518328
總結
以上是生活随笔為你收集整理的[Nodejs]初探nodejs学习笔记- 如何使用nodejs搭建简单的UDP聊天功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 荣耀平板8连不上无线网怎么办 荣耀平板8
- 下一篇: 荣耀平板8如何隐藏指定软件应用 荣耀平板