如何使用 UDP 在 Contiki-NG 中建立向下连接

How to make downward connection in Contiki-NG with UDP

我正在尝试使用 6LoWPAN 和 Contiki 建立一个简单的网状连接。

为了简单起见,我在 Cooja 中制作了这个,所以我认为硬件不是这个问题的限制因素。

我的objective是一个root(UDP Server)和多个mote(UDP Client)。通过 Contiki 提供的示例,我能够开始与 Mote 的通信并与服务器对话,但是是否有可能以相反的方式进行?

我希望 Root 开始向任何客户端发送消息,如果有必要,通过网络中的其他客户端跳转消息。

你知道这是否可行吗?或实现此目标的任何途径?

更新:到目前为止我尝试过的内容:

到目前为止我已经尝试过,在服务器设备中,创建两个进程,一个用于启动root,另一个用于定期发送数据包:

#include "contiki.h"
#include <stdlib.h>
#include "net/routing/routing.h"
#include "random.h"
#include "net/netstack.h"
#include "net/ipv6/simple-udp.h"
#include "sys/log.h"

#define LOG_MODULE "App"
#define LOG_LEVEL LOG_LEVEL_DBG

#define UDP_CLIENT_PORT 8765
#define UDP_SERVER_PORT 5678

#define SEND_INTERVAL         (5 * CLOCK_SECOND)

static struct simple_udp_connection udp_conn;
static struct etimer periodic_timer;

PROCESS(udp_server_process, "UDP server");
PROCESS(send_msg_process, "UDP server");
AUTOSTART_PROCESSES(&udp_server_process, &send_msg_process);


static void
udp_rx_callback(struct simple_udp_connection *c,
         const uip_ipaddr_t *sender_addr,
         uint16_t sender_port,
         const uip_ipaddr_t *receiver_addr,
         uint16_t receiver_port,
         const uint8_t *data,
         uint16_t datalen)
{
  LOG_INFO("Received response '%.*s' from ", datalen, (char *) data);
  LOG_INFO_6ADDR(sender_addr);
  LOG_INFO_("\n");
}




PROCESS_THREAD(udp_server_process, ev, data)
{
  PROCESS_BEGIN();

  /* Initialize DAG root */
  NETSTACK_ROUTING.root_start();

  /* Initialize UDP connection */
  simple_udp_register(&udp_conn, UDP_SERVER_PORT, NULL,
                      UDP_CLIENT_PORT, udp_rx_callback);

  PROCESS_END();
}


PROCESS_THREAD(send_msg_process, ev, data)
{
  
  static unsigned count;
  static char str[32];
  uip_ipaddr_t dest_ipaddr;
  LOG_INFO("%u", count);
  PROCESS_BEGIN();

  while(1) {
      etimer_set(&periodic_timer, CLOCK_SECOND);
      PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer));
        uip_ip6addr(&dest_ipaddr,0xfe80,0,0,0,0x207,0x7,0x7,0x7);
        LOG_INFO("Sending request %u to ", count);
        LOG_INFO_6ADDR(&dest_ipaddr);
        LOG_INFO_("\n");
        snprintf(str, sizeof(str), "hello %d", count);
        simple_udp_sendto(&udp_conn, str, strlen(str), &dest_ipaddr);
        count++;
  }
  PROCESS_END();
}

在client端,代码只是简单的监听UDP socket,收到数据包就做出响应

#include "contiki.h"
#include "net/routing/routing.h"
#include "random.h"
#include "net/netstack.h"
#include "net/ipv6/simple-udp.h"

#include "sys/log.h"
#define LOG_MODULE "App"
#define LOG_LEVEL LOG_LEVEL_DBG

#define WITH_SERVER_REPLY  1
#define UDP_CLIENT_PORT 8765
#define UDP_SERVER_PORT 5678

#define SEND_INTERVAL         (5 * CLOCK_SECOND)

static struct simple_udp_connection udp_conn;

/*---------------------------------------------------------------------------*/
PROCESS(udp_client_process, "UDP client");
AUTOSTART_PROCESSES(&udp_client_process);
/*---------------------------------------------------------------------------*/
static void
udp_rx_callback(struct simple_udp_connection *c,
         const uip_ipaddr_t *sender_addr,
         uint16_t sender_port,
         const uip_ipaddr_t *receiver_addr,
         uint16_t receiver_port,
         const uint8_t *data,
         uint16_t datalen)
{

  LOG_INFO("Received request '%.*s' from ", datalen, (char *) data);
  LOG_INFO_6ADDR(sender_addr);

  LOG_INFO("Sending response.\n");
  simple_udp_sendto(&udp_conn, data, datalen, sender_addr);

  LOG_INFO_("\n");

}

PROCESS_THREAD(udp_client_process, ev, data)
{
  PROCESS_BEGIN();
  simple_udp_register(&udp_conn, UDP_CLIENT_PORT, NULL,
                      UDP_SERVER_PORT, udp_rx_callback);
  PROCESS_END();
}

如你所见,服务端的代码周期性的向ipv6方向发送一个数据包:0xfe80:0:0:0:0x207:0x7:0x7:0x7,这是cooja中7号mote分配的ip模拟。

我得到的结果是,当 root (A) 和 client (B) 处于直接连接时,它们可以完美地相互通信,但是当我将它们分开并尝试建立连接时根 (A) 通过另一个客户端 (C) 到客户端 (B),消息不会从 A 到 B。

是的,这是可能的。 RPL 路由协议允许在往返于根的两个方向上发送数据包。只需使用节点的 IP 地址作为目的地。

一个问题是一个节点通常有两个 IPv6 地址:

  • 0xfe80 开头的地址是 link 本地地址。
  • 以网络前缀开头的地址 - 在 OS 配置中定义为 UIP_DS6_DEFAULT_PREFIX,默认等于 0xfd00。该地址仅在节点加入 RPL 网络后出现。

到 link-local 地址的数据包必须是 single-hop,它们不会被节点转发。为了正确使用 multi-hop 网状转发,请使用其他地址作为目的地。