Linux 用于在 Linux board 和每个节点之间进行通信的用户空间代码 运行 contiki udp 发送器示例代码

Linux userspace code to communicate between Linux board and each node running contiki udp sender example code

我正在使用 Contiki 创建一个涉及多个基于 STM32L152 的节点和一个 Linux 板的物联网产品。我有一个嵌入式 Linux 板(基于 iMX6),它从节点接收数据,使用蜂窝和 10 个感知不同环境参数并传送到 Linux 板的节点发送到互联网。 Linux板子有一个协处理器,运行border/edge路由器代码,协处理器的UART2线连接到Linux板子。我使用 Contiki 工具 tunslip6 创建 tun0 接口,我能够 ping 每个节点。 为了让问题更容易理解,我将解释我执行的硬件设置和步骤。

  1. 我是 运行 UDP 发送器示例代码 (STM32CubeExpansion_SUBG1_V3.0.0/Projects/Multi/Applications/Contiki/Udp-sender) 在具有 x-nucleo-ids01a5 (SPSGRF) 的 STM32L152RE-NUCLEO 板上-915 模块)电路板位于顶部。

  2. 第二个类似的硬件设置,我是运行边界路由器示例代码。 USB 数据线连接到我的 Linux 盒子。

这样做之后; sudo ./tunslip6 –s /dev/ttyACM0 aaaa::1/64,我可以在网页上看到所有邻居节点,我也可以ping6每个节点。 我想在Linux上编写应用程序代码来接收和发送数据到每个节点,我卡在了这一点。

sudo ./tunslip6 -s /dev/ttyACM0 aaaa::1/64
********SLIP started on ``/dev/ttyACM0''
opened tun device ``/dev/tun0''
ifconfig tun0 inet `hostname` mtu 1500 up
ifconfig tun0 add aaaa::1/64
ifconfig tun0 add fe80::0:0:0:1/64
ifconfig tun0

tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00- 
00-00-00-00-00  
          inet addr:127.0.1.1  P-t-P:127.0.1.1  Mask:255.255.255.255
          inet6 addr: fe80::1/64 Scope:Link
          inet6 addr: aaaa::1/64 Scope:Global
          inet6 addr: fe80::8fad:d1a:c8d0:b76f/64 Scope:Link
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

*** Address:aaaa::1 => aaaa:0000:0000:0000
Got configuration message of type P
Setting prefix aaaa::
Server IPv6 addresses:
 aaaa::900:f4ff:c3a:f3c5
 fe80::900:f4ff:c3a:f3c5

ifconfig
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:127.0.1.1  P-t-P:127.0.1.1  Mask:255.255.255.255
          inet6 addr: fe80::1/64 Scope:Link
          inet6 addr: aaaa::1/64 Scope:Global
          inet6 addr: fe80::8fad:d1a:c8d0:b76f/64 Scope:Link
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:37 errors:0 dropped:0 overruns:0 frame:0
          TX packets:67 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500 
          RX bytes:3422 (3.4 KB)  TX bytes:5653 (5.6 KB)

ip addr show tun0
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 500
    link/none 
    inet 127.0.1.1/32 scope host tun0
       valid_lft forever preferred_lft forever
    inet6 aaaa::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::1/64 scope link 
       valid_lft forever preferred_lft forever
    inet6 fe80::8fad:d1a:c8d0:b76f/64 scope link flags 800 
       valid_lft forever preferred_lft forever

sudo ip -6 route
aaaa::/64 dev tun0  proto kernel  metric 256  pref medium
fe80::/64 dev tun0  proto kernel  metric 256  pref medium

This is what I am seeing on the webpage, I have one neighbor node 我可以 ping 这个。

ping6 aaaa::fdff:d2fa:2d05
PING aaaa::fdff:d2fa:2d05(aaaa::fdff:d2fa:2d05) 56 data bytes
64 bytes from aaaa::fdff:d2fa:2d05: icmp_seq=1 ttl=63 time=130 ms
64 bytes from aaaa::fdff:d2fa:2d05: icmp_seq=2 ttl=63 time=131 ms
64 bytes from aaaa::fdff:d2fa:2d05: icmp_seq=3 ttl=63 time=130 ms
64 bytes from aaaa::fdff:d2fa:2d05: icmp_seq=4 ttl=63 time=130 ms
64 bytes from aaaa::fdff:d2fa:2d05: icmp_seq=6 ttl=63 time=130 ms
64 bytes from aaaa::fdff:d2fa:2d05: icmp_seq=7 ttl=63 time=130 ms
64 bytes from aaaa::fdff:d2fa:2d05: icmp_seq=8 ttl=63 time=131 ms
^C
--- aaaa::fdff:d2fa:2d05 ping statistics ---
8 packets transmitted, 7 received, 12% packet loss, time 7040ms
rtt min/avg/max/mdev = 130.681/131.068/131.863/0.555 ms

我不是网络和套接字编程方面的专家,我写了一些我在互联网上找到并尝试过的代码。我试过这样的事情;

import socket
UDP_IP = "aaaa::fdff:d2fa:2d05"  
UDP_PORT = 1234
print "UDP target IP:", UDP_IP
print "UDP target port:", UDP_PORT
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) # UDP
sock.connect((UDP_IP, UDP_PORT))
while True:
   data = sock.recv(1024)
   print 'Received', repr(data)

问题:在Linux用户space中,同事想写一个应用程序代码,可以读写每个节点(本例aaaa::fdff:d2fa:2d05),如何实现那?在微控制器板上,我可以用两个节点读写,但在 Linux space 中不行。请帮助我,如何从Linux用户space读取和写入数据到每个节点?如果可能,请分享一些示例代码。谢谢!

更新 - 我尝试使用不同的 Contiki 示例 contiki/examples/ipv6/rpl-udp/udp-client.c 在 Linux 主机和节点之间进行通信并取得了成功,我能够从节点接收数据。我的 python 代码是;

import socket, struct

UDP_LOCAL_IP = 'aaaa::1'
UDP_LOCAL_PORT = 5678


UDP_REMOTE_IP = 'fe80::fdff:d2fa:2d05'
UDP_REMOTE_PORT = 8765


try:
    socket_rx = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    socket_rx.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    socket_rx.bind((UDP_LOCAL_IP, UDP_LOCAL_PORT))
except Exception:
    print "ERROR: Server Port Binding Failed"

print 'UDP server ready: %s'% UDP_LOCAL_PORT
print

while True:
    data, addr = socket_rx.recvfrom(1024)
    print "address : ", addr
    print "received message: ", data
    print "\n"
    socket_rx.sendto("Hello from serevr\n", (UDP_REMOTE_IP, UDP_REMOTE_PORT))

以上 python 代码有效。

边界路由器有一个硬编码的 IPv6 地址,根据 https://anrg.usc.edu/contiki/index.php/RPL_Border_Router 这个地址是 fe80:0000:0000:0000:0212:7401:0001:0101(可能 运行 ip addr show tun0 -> 你的编辑显示分配的地址是 fe80:0000:0000:0000:8fad:d1a:c8d0:b76f )。您将应用程序的套接字绑定到该地址,python 中没有相关代码。因为你使用 tunslip 你也可以使用 准确的端口 和 ipv4 协议

绑定到 localhost

为了测试,您可以使用 netcat 将 UDP 数据包直接发送到节点 ( http://www.tutorialspoint.com/unix_commands/nc.htm )

要消除错误(评论),您必须应用 inet_pton 转换 IPv6 地址(http://man7.org/linux/man-pages/man3/inet_pton.3.html

以下是您可以转换为 python 的工作 C 代码。是为使用 Raven USB 记忆棒作为边界路由器而编写的(搜索 Contiki Jackdaw,未使用 tunslip

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <net/if.h>

 int fd = 0;   //socket file descriptor
 struct sockaddr_in6 server;


/* ipv6 address to in6_addr structure */

const char *ip6str = "fe80::8fad:d1a:c8d0:b76f";
struct in6_addr ravenipv6;

if (inet_pton(AF_INET6, ip6str, &ravenipv6) == 1) // successful
{
   printf("%s \n", "ipv6 address ...");
}


/* Create an empty IPv6 socket interface specification */
memset(&server, 0, sizeof(server));


server.sin6_family = AF_INET6;
server.sin6_flowinfo = 0;
server.sin6_port = htons(1234);  // port
server.sin6_addr = ravenipv6;  <- here the address converted with inet_ptons is inserted
server.sin6_scope_id = if_nametoindex("tun0");  // if your border router is on tun0

/*create socket*/
if ((fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1)
  {
    printf("%s \n", "failed to create socket");
  }

 /*bind to socket*/

if(bind(fd, (struct sockaddr_in6*)&server, sizeof(server)) == -1)

{
    printf("%s \n", "no binding ! ");
}