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聊天功能相关推荐

  1. PyTorch学习笔记(10)--搭建简单的神经网络以及Sequential的使用

    PyTorch学习笔记(10)–搭建简单的神经网络以及Sequential的使用     本博文是PyTorch的学习笔记,第10次内容记录,主要搭建一个简单的神经网络,并介绍Sequential的使 ...

  2. Ionic 学习笔记之-痛彻心扉的环境搭建

    Ionic 学习笔记之-痛彻心扉的环境搭建 最近在学习Ionic 做多平台的应用.跨平台应用.就是用html写的界面.js实现逻辑. 在学ionic之前选了各种跨平台APP开发框架.最后选择了ioni ...

  3. JavaScript学习笔记(三)——从简单模仿到创作

    JavaScript学习笔记(三)--从简单模仿到创作 目前我先列好提纲,利用每晚和周末的闲暇时间,将逐步写完 ^_^ 转载于:https://www.cnblogs.com/mixer/archiv ...

  4. 【数据库学习笔记】Day03 - SQL语言基础及数据库定义功能

    [数据库学习笔记]Day03 - SQL语言基础及数据库定义功能 〇.本文所用数据库表格: 一.关系运算: 关系运算,数学名词,基本运算有两类:一类是传统的集合运算(并.差.交等),另一类是专门的关系 ...

  5. ESP32学习笔记(1)——搭建环境、编译烧写(Windows+VS Code)

    Espressif-IDE 环境搭建参看 ESP32学习笔记(50)--搭建环境.编译烧写(Windows+Espressif-IDE) 一.搭建环境 1.1 官方资料 ESP-IDF 编程指南 1. ...

  6. OpenGL学习笔记(一):环境搭建、三维空间坐标系理解以及OpenGL的基本使用

    原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7866 ...

  7. ESP8266学习笔记(1)——搭建环境、编译烧写(NONOS SDK)

    RTOS SDK环境搭建参看 ESP8266学习笔记(17)--搭建环境.编译烧写(RTOS SDK) 一.搭建环境 1.1 ESP8266 SDK 入门指南 官网下载:https://www.esp ...

  8. P4学习笔记(二)一个简单P4交换机实现

    P4学习笔记(一)初始P4 P4学习笔记(二)一个简单P4交换机实现 文章目录 1. 架构模型 2.预定义模块详细描述 2.1 Arbiter 模块 2.2 Parser runtime 模块 2.3 ...

  9. adg oracle,【学习笔记】Oracle ADG搭建与配置 windows平台11G ADG搭建与测试

    [学习笔记]Oracle ADG搭建与配置 windows平台11G ADG搭建与测试 时间:2016-10-26 20:09   来源:Oracle研究中心   作者:HTZ   点击: 次 天萃荷 ...

最新文章

  1. 由“递归遍历二叉树”引发的思考
  2. 分销与供应链海外采购电子元器件,你需要了解哪些报关知识?
  3. 【收藏】keepalived nginx服务检测脚本
  4. 计算机组成原理试卷五套,山东理工计算机组成原理五套题之题5
  5. InfluxDB学习之InfluxDB数据保留策略(Retention Policies)
  6. centos8 默认nginx路径_CentOS 8系统安装Nginx Web服务器及常见配置过程
  7. ip转换器是否可以被检测出来_一氧化碳报警器是否可以检测煤气泄漏
  8. Filter的基本配置
  9. java通字乱码_Java解决通信过程的中文乱码的问题
  10. CloudStack 4.4学习总结之注册ISO
  11. 卷积操作改进之Involution: Inverting the Inherence of Convolution for Visual Recognition
  12. apple watch 微信连接不上手机
  13. 保持健康和快乐的20种方法
  14. 什么是OSINT?以及如何使用开源网络情报工具?
  15. Ubuntu14.04 Firefox无法播放视频
  16. Graphics View框架
  17. 075 定积分积分法之换元积分法
  18. 海思方案技术研发交流群/海思方案供需交流群
  19. Virtualization——虚拟化技术
  20. 关于WAP的常见问答

热门文章

  1. php编译参数注解--不明白许多参数的作用 慎用 –with-curlwrappers参数
  2. 我的Go语言学习之旅六:做一个WIN的简单弹窗
  3. Win8离线安装.net framework组件
  4. C++ 预编译头文件
  5. keycloak 调研资料
  6. Ambari 2.6.0 HDP 2.6.3集群搭建
  7. 结对-贪吃蛇游戏-开发过程
  8. 当重复调用addsubview时出现显示重叠问题
  9. 20155235 2016-2017-2《Java程序设计》课程总结
  10. Android开发7:简单的数据存储(使用SharedPreferences)和文件操作