Как сделать нисходящее соединение в Contiki-NG с UDP
Я пытаюсь сделать простое сетевое соединение, используя 6LoWPAN с Contiki.
Для простоты я делаю это в Cooja, поэтому я думаю, что аппаратное обеспечение не является ограничением в этой проблеме.
Моя цель - иметь один корень (UDP-сервер) и много узлов (UDP-клиент). С примерами, предоставленными Contiki, я могу начать общение с Мотами и поговорить с Сервером, но возможно ли сделать это наоборот?
Я хочу, чтобы 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();
}
На стороне клиента код основан просто на прослушивании UDP-сокета и ответе в случае получения пакета.
#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, который является ip, который будет назначен моту в cooja, когда он это число 7 в моделировании.
Результаты, которые я получил, заключаются в том, что когда корень (A) и клиент (B) находятся в прямом соединении, они отлично разговаривают друг с другом, но когда я разделяю их и пытаюсь установить соединение из корня (A) клиенту (B) через другого клиента (C), сообщение не дойдет от A до B.
1 ответ
Да, это возможно. Протокол маршрутизации RPL позволяет отправлять пакеты в обоих направлениях от корня и к нему. Просто используйте IP-адрес узла в качестве пункта назначения.
Одна проблема заключается в том, что узел обычно имеет два адреса IPv6:
- Адреса, начинающиеся с
0xfe80
являются локальными ссылками. - Адреса, начинающиеся с префикса сети, определяются в конфигурации ОС как
UIP_DS6_DEFAULT_PREFIX
, равно0xfd00
по умолчанию. Этот адрес присутствует только после того, как узел присоединился к сети RPL.
Пакеты на локальные адреса должны быть односкачковыми, они не пересылаются узлами. Чтобы правильно использовать переадресацию многосегментной сетки, используйте другой адрес в качестве пункта назначения.