如何在 Node.js 中的同一进程内监听同一地址上的不同 UDP 端口

How to listen to different UDP ports on the same address within the same process in Node.js

我正在编写一个 Node.js 应用程序来控制一架小型无人机。以下是来自 SDK 的说明:


使用 Wi-Fi 在 Tello 和 PC、Mac 或移动设备之间建立连接。

发送命令并接收响应

特洛 IP:192.168.10.1 UDP 端口:8889 <<-->> PC/Mac/Mobile

第 1 步:在 PC、Mac 或移动设备上设置 UDP 客户端,以通过同一端口从 Tello 发送和接收消息。

第 2 步:在发送任何其他命令之前,通过 UDP 端口 8889 发送 'command' 到 Tello 以启动 SDK 模式。

接收 Tello 状态

Tello IP: 192.168.10.1 -->> PC/Mac/Mobile UDP 服务器: 0.0.0.0 UDP 端口: 8890

第3步:在PC、Mac或移动设备上设置UDP服务器,并通过UDP PORT 8890查看来自IP 0.0.0.0的消息。必须先完成第1和2步,然后才能尝试执行此步骤3.

接收 Tello 视频流

Tello IP: 192.168.10.1 -->> PC/Mac/Mobile UDP 服务器: 0.0.0.0 UDP 端口: 11111

第4步:在PC、Mac或移动设备上设置UDP服务器,通过UDP PORT 11111查看来自IP 0.0.0.0的消息。

第 5 步:通过 UDP 端口 8889 发送 'streamon' 到 Tello 以开始流式传输。必须先完成第 1 步和第 2 步,然后才能尝试第 5 步。


命令和接收部分非常有效,我正在发送和接收数据报 to/from 端口 8889 上的无人机。我的问题是我似乎没有收到任何状态或视频流消息在其他端口上,我很确定这不是无人机的问题,而是我没有正确设置 Node.js 的问题。任何人都可以看到我的实现中的问题所在。这是我的代码:

tello.ts

import dgram from 'dgram';

export class Tello {
  private LOCAL_IP_ = '0.0.0.0';
  private TELLO_IP_ = '192.168.10.1';

  private COMMAND_PORT_ = 8889;
  private commandSocket_ = dgram.createSocket('udp4');

  private STATE_PORT_ = 8890;
  private stateSocket_ = dgram.createSocket('udp4');

  private VIDEO_PORT_ = 11111;
  private videoSocket_ = dgram.createSocket('udp4');

  constructor() {}

  startCommandSocket() {
    this.commandSocket_.addListener('message', (msg, rinfo) => {
      const message = msg.toString();
      console.log(`from ${rinfo.address}: ${message}`);
    });
    this.commandSocket_.bind(this.COMMAND_PORT_, this.LOCAL_IP_, () => {
      console.log('Started listening on the command socket');
    });
  }

  startStateSocket() {
    this.stateSocket_.addListener('message', (msg, rinfo) => {
      const message = msg.toString();
      console.log(`from ${rinfo.address}: ${message}`);
    });
    this.stateSocket_.bind(this.STATE_PORT_, this.LOCAL_IP_, () => {
      console.log('Started listening on the state socket');
    });
  }

  startVideoSocket() {
    this.videoSocket_.addListener('message', (msg, rinfo) => {
      console.log('receiving video');      
      const message = msg.toString();
      console.log(`from ${rinfo.address}: ${message}`);
    });
    this.videoSocket_.bind(this.VIDEO_PORT_, this.LOCAL_IP_, () => {
      console.log('Started listening on the video socket');
    });
  }

  private sendCommand_(command: string) {
    // As this is sent over UDP and we have no guarantee that the packet is received or a response given
    // we are sending the command 5 times in a row to add robustess and resiliency.
    //for (let i = 0; i < 5; i++) {
    this.commandSocket_.send(command, this.COMMAND_PORT_, this.TELLO_IP_);
    //}
    console.log(`sending command: ${command} to ${this.TELLO_IP_}`);
  }

  /**
   * Enter SDK mode.
   */
  command() {
    this.sendCommand_('command');
  }

  /**
   * Auto takeoff.
   */
  takeoff() {
    this.sendCommand_('takeoff');
  }

  /**
   * Auto landing.
   */
  land() {
    this.sendCommand_('land');
  }

  streamVideoOn() {
    this.sendCommand_('streamon');
  }

  streamVideoOff() {
    this.sendCommand_('streamoff');
  }

  ...

}

index.ts

import { waitForSeconds } from './utils';
import { Tello } from './tello'

const main = async () => {
  const tello = new Tello();

  tello.startCommandSocket();
  await waitForSeconds(1);
  tello.command();
  await waitForSeconds(1);  
  tello.startStateSocket();
  await waitForSeconds(1);
  tello.startVideoSocket();
  await waitForSeconds(1);
  tello.streamVideoOn();
  await waitForSeconds(1);
    
  tello.takeoff();
  await waitForSeconds(10);
  tello.land(); 
};

main();

这里是使用"streamon"命令接收和解码Tello SDK团队提供的h264视频流的示例代码。 https://github.com/dji-sdk/Tello-Python. 接收到的视频流数据的具体处理方法请参考doc/reademe.pdf和h264解码器路径下的源码

在 运行 示例代码之前,您应该使用安装脚本安装一些依赖项。

您是否打开防火墙以接受 UDP 端口 8890 / 11111?

在笔记本电脑防火墙中打开端口 8890/udp 和 11111/udp 以接收 Tello 遥测数据。

在 Linux

$ sudo firewall-cmd --permanent --add-port=8890/udp

$ sudo firewall-cmd --permanent --add-port=11111/udp

在 Mac 上,使用系统偏好设置打开端口。

Open System Preferences > Security & Privacy > Firewall > Firewall Options
Click the + / Add button
Choose 'node' application from the Applications folder and click Add.
Ensure that the option next to the application is set to Allow incoming connections.
Click OK.