如何使用 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 网状转发,请使用其他地址作为目的地。
我正在尝试使用 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 网状转发,请使用其他地址作为目的地。