Node.js UDP编程

本文会演示如何构建一个简单的UDP客户端与服务端应用,该应用是一个改进的股票监控器。服务端会发送有关幻想世界股票数据给客户端,客户端负责跟踪到达的消息是否为最近的。如果客户端检测到到达消息出现故障,仅仅丢弃消息(不对过期股票价格感兴趣)。

从服务端开始:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');
 
const host = '0.0.0.0';
const port = 41100;
 
server.on('error', (err) => {
  console.log(err.stack);
  server.close();
});
 
server.on('message', (msg, rinfo) => {
  console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
 
  const reply = new Buffer('Got [' + msg + ']');
  server.send(reply, 0, reply.length, rinfo.port, rinfo.address, (err, bytes) => {
    if (err){
      console.log(err.stack);
    }
  });
});
 
server.on('listening', () => {
  const address = server.address();
  console.log(`server listening ${address.address}:${address.port}`);
});
 
server.bind(port, host);
该代码片段说明了任何一个网络服务端应用所有重要的特征:绑定端口、接收消息、应答、应错。


既然已经有了服务端,为其构建一个客户端。

const dgram = require('dgram');
const client = dgram.createSocket('udp4');
 
const host = '0.0.0.0';
const port = 41100;
 
const message = new Buffer('Hello Server');
 
client.on('message', (message, remote) => {
  console.log('Server: ' + message);
});
 
client.send(message, 0, message.length, port, host, (err, bytes) => {
  if (err) {
    throw err;
  }
 
  console.log('Message sent');
});
如果运行服务端与客户端,可以看到相互交换消息。现在将这段代码与典型TCP/IP服务端进行比较。注意到的第一件事情会是没有连接或者套接字的概念,从某个远程套接字接收消息,但是不能分辨出来该套接字是否仍然存活并处于监听之中。即使发送消息,也不能检查,除非客户端发送回应答或者心跳。

现在来做一个小实验:改变客户端端口号地址,尝试再次发送消息。会发现即使没有UDP服务端监听那个端口,也不会得到任何错误。底线是“如果想要得到任何额外的保证,比如:消息传送通知或者连接客户端列表,必须自己实现。

那是我们会在代码下一部分中所做的事情。为了给所有连接客户端发送股票数据,需要在服务端保存主机与端口号列表。不会进行检查它们是否仍然存活并处于监听之中,只是保存注册。

更新的服务端代码:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');
 
const host = '0.0.0.0';
const port = 41100;
 
const clients = [];
 
server.on('error', (err) => {
  console.log(err.stack);
  server.close();
});
 
server.on('message', (msg, rinfo) => {
  console.log(`Connected client at ${rinfo.address}:${rinfo.port}`);
  clients.push(rinfo);
});
 
server.on('listening', () => {
  const address = server.address();
  console.log(`server listening ${address.address}:${address.port}`);
});
 
setInterval(() => {
  const price = Math.floor(1000+ Math.random()*100);
  const time = Date.now();
  const data = new Buffer(price + ',' + time);
 
  clients.forEach((rinfo) => {
    server.send(data, 0, data.length, rinfo.port, rinfo.address, (err, bytes) => {
      if (err){
        console.log(err.stack);
      }
    });
  })
}, 1000);
 
server.bind(port, host);

增加setInterval()方法每一秒发送随机股票价格数据,针对这个例子,设计了一个简单基于文本的协议。发送消息以逗号分割字段列表,第一个字段是股票价格,第二个字段是发送该价格时的服务端时间。

再次运行这个客户端与服务端,会发现客户端现在展示来自服务端的消息。通过使得客户端更智能一些完成这个简单的示例。客户端现在会解析数据,如果看到更接近的消息则会丢弃之前的价格。

const dgram = require('dgram');
const client = dgram.createSocket('udp4');
 
const host = '0.0.0.0';
const port = 41100;
 
const message = new Buffer('Hello Server');
 
const parseTick = (message) => {
  const parts = message.toString().split(',').map((part) => +part);
  return {
    price: parts[0],
    time: parts[1]
  }
};
 
let latestTickTime = -1;
 
client.on('message', (message, remote) => {
  const tick = parseTick(message);
 
  if (tick.time > latestTickTime) {
    console.log('Price is', tick.price);
    latestTickTime = tick.time
  } else {
    console.log('Price is outdated, discard');
  }
});
 
client.send(message, 0, message.length, port, host, (err, bytes) => {
  if (err) {
    throw err;
  }
 
  console.log('Message sent');
});
现在客户端解析消息,也会检查消息是否应该忽略,既然已经得到一个更接近的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值