contiki-rime-单跳单播

rucb是单跳单播的最顶层,将数据以块为单位进行传输(Bulk transfer)。
ruc,Reliable communication,保证可靠通信,主要实现确认和序列功能。
suc,Stubborn transmission,可靠通信的另一层。suc这一层在给定的时间间隔不断地重复发送数据包,直到上层让其停止。为防止无限重发,需要指定最大重发次数。
uc,unicast abstraction,将上层的数据包添加一个接收者头部。
ibc,identified sender best-effort broadcast,将上层的数据包添加一个发送者身份头部
abc,anonymous broadcast,匿名广播。即将数据包通过无线射频驱动(radio driver)发出去,接收来自无线射频驱动所有的包并交给上层。
建立连接
建立连接的实质是保存该连接一些信息(如发送者、接收者),Rime协议栈用一系列结构体保存这些连接状态信息。Rime每一层都有相应的连接结构体(以_conn结尾),上层嵌套下层,如下:
rucb_conn --> runicast_conn --> stunicast_conn --> unicast_conn --> broadcast_conn --> abc_conn
每个连接结构体都有相应的回调结构体(以_callbacks后缀结尾),该结构体的成员变量实为发送、接收函数指针。当接收到一个数据报,会调用该结构体相应的函数。回调结构体层次如下:
rucb_callbacks --> runicast_callbacks --> stunicast_callbacks --> unicast_callbacks --> broadcast_callbacks --> abc_callbacks
综上,连接建立_open、连接结构体_conn、回调结构体_callbacks间的关系如下图:

1>连接结构体
建立连接,实质是初始化结构体rucb_conn各个成员变量,结构体rucb_conn定义如下:
struct rucb_conn {
struct runicast_conn c;
const struct rucb_callbacks *u;
rimeaddr_t receiver, sender;
uint16_t chunk;
uint8_t last_seqno;
int last_size;
};
c
下一层连接结构体
u
结构体rucb_callbacks有3个函数指针成员变量,写数据块write_chunk、读数据块read_chunk、超时timeout,需要用户自己实现。
receiver、sender
用于标识接收者和发送者。receiver是指目的节点的接收地址
chunk
数据块数目
last_seqno
一次数据发送多个片段的最后一个序列号,当接收端接收到数据时,判断其序列号是否等于最后一个序列号,若等于则不接收(即,接收到最后一个数据块,停止接收)
数据发送
Rime协议栈建立连接后,就可以通信了(发送、接收数据),下面介绍单跳单播的发送数据情形。
Rime是层次型协议栈,整个发送数据过程是通过上层调用下层服务来完成的,具体如下:
rucb_send --> runicast_send --> stunicast_send_stubborn --> unicast_send --> broadcast_send --> abc_send -->rime_output -->NETSTACK_MAC.send
rucb是块传输层,可以理解成传输层,数据发送函数rucb_send的源代码如下:
int rucb_send(struct rucb_conn *c, const rimeaddr_t *receiver)
{
c->chunk = ;
read_data(c);
rimeaddr_copy(&c->receiver, receiver);
rimeaddr_copy(&c->sender, &rimeaddr_node_addr);
runicast_send(&c->c, receiver, MAX_TRANSMISSIONS);
return ;
}
c->chunk将数据块数目初始化为0,read_data进行一些Rime缓冲区初始化相关工作。rimeaddr_copy函数设置接收者receiver和发送者sender的Rime地址,rimeaddr_node_addr用于标识本节点的Rime地址。接下来调用下一层的发送函数runicast_send完成发送。
数据接收
Rime协议栈建立连接后,就可以调用数据接收函数recv来接收数据,整个接收数据过程是通过上层调用下层服务来完成的,具体如下:
recv --> recv_from_stunicast --> recv_from_uc --> recv_from_broadcast -->recv_from_abc
函数recv首先判断该数据包是不是最后一个序列(数据包被拆分的情况下),若不是,将收到的数据写入物理存储介质。recv函数流程图如下:

static void recv(struct runicast_conn *ruc, const rimeaddr_t *from, uint8_t seqno)
{
struct rucb_conn *c = (struct rucb_conn *)ruc; PRINTF("%d.%d: rucb: recv from %d.%d len %d\n",
rimeaddr_node_addr.u8[],rimeaddr_node_addr.u8[],
from->u8[], from->u8[], packetbuf_totlen()); if(seqno == c->last_seqno) {
return;
}
c->last_seqno = seqno; if(rimeaddr_cmp(&c->sender, &rimeaddr_null)) {
rimeaddr_copy(&c->sender, from);
c->u->write_chunk(c, , RUCB_FLAG_NEWFILE, packetbuf_dataptr(), );
c->chunk = ;
} if(rimeaddr_cmp(&c->sender, from)) {
int datalen = packetbuf_datalen(); if(datalen < RUCB_DATASIZE) {
PRINTF("%d.%d: get %d bytes, file complete\n",
rimeaddr_node_addr.u8[], rimeaddr_node_addr.u8[],
datalen);
c->u->write_chunk(c, c->chunk * RUCB_DATASIZE,
RUCB_FLAG_LASTCHUNK, packetbuf_dataptr(), datalen);
} else {
c->u->write_chunk(c, c->chunk * RUCB_DATASIZE,
RUCB_FLAG_NONE, packetbuf_dataptr(), datalen);
}
c->chunk++;
} if(packetbuf_datalen() < RUCB_DATASIZE) {
rimeaddr_copy(&c->sender, &rimeaddr_null);
}
}
函数recv首先判断接收到的包是不是最后一个序列(数据包太大时,需要拆分),如果是最后一个就返回(用最后序列号标识包传递完毕)。若不是最后一个序列,意味着还有数据要接收。接着判断发送者地址是否为空,若是,说明节点未曾接收到该包的任何序列,则建立文件以存放数据。确保发送地址无误之后,若块小于块的最大值(RUCB_DATASIZE),即这是数据包的最后的一块,写入最后一块,否则正常写入这块的数据。把块的数目累加,接着判断这块是否是最后一块(最后一块意味着数据包传输完毕),若是则将发送者地址设为空,否则返回。
释放连接
数据通信完毕之后,需要释放连接,以供其他进程是哟个。关闭连接实质上是将相应的连接结构体从连接表中删除。整个调用过程如下:
rucb_close --> runicast_close --> stunicast_close --> unicast_close --> broadcast_close --> abc_close --> channel_close -->list_remove
contiki-rime-单跳单播的更多相关文章
- 表单跳转到Struts2
在使用表单跳转到Struts2时,路径一直不正确. login.html如下: <form action="login.do" method=post> 账号:< ...
- 原生js阻止表单跳转
/* W3C浏览器下的 */ var forms = document.getElementById("from") forms.addEventListener('submit' ...
- H3C 路由器单跳操作
- [Contiki系列论文之2]WSN的自适应通信架构
说明:本系列文章翻译自Contiki之父Adam Dunkels经典论文,版权归原作者全部. Contiki是由Adam Dunkels及其团队开发的系统.研读其论文是对深入理解Contiki系统的最 ...
- Djangoform表单Ajax控制跳转
需求: 1:在登陆页面输入账号密码后,ajax异步提交数据给后端验证. 2:验证通过后,后端指定跳转页面,并把页面封装进返回的Json数据中,由ajax控制from表单跳转到目标页面 一:登陆页面HT ...
- AutoIt 脚本小试——刷网易云音乐歌单
AutoIt 确实是个很强大的脚本工具. 如果早知道有这个,当初是怎么都不会去学易语言的 (๑•̀ω•́๑) 这是个简单脚本 = ๛ก(ー̀ωー́ก) 用来增加歌单播放次数和个人的听歌量. 原理不过 ...
- Servlet3.0 jsp跳转到Servlet 出现404错误的路径设置方法
最近又遇到了这种问题,百度了好久,发现有人说要在action的路径里面写Servlet文件的绝对路径,比如说,单独打开servlet的地址为http://localhost:8080/TomcatTe ...
- ajax跳转到新的jsp页面
ajax可以实现局部刷新页面,即在不刷新整个页面的情况下更新页面的局部信息. 项目中遇到一个问题:在用户列表也,当点击某个按钮时需要去查询用户的信息,查询成功跳转到用户详情界面:查询失败,则在原页面弹 ...
- layui---表单验证
使用layui,使用它的表单验证也是比不可少的,下面就来总结下: <!-- 不用form 用div也可以 --> <form class="layui-form" ...
随机推荐
- Java 之 List<T> 接口的实现:ArrayList
Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHashMap ArrayLis ...
- 【003:jsoncpp的简单使用】
#include <json/json.h> #include <iostream> #include <string> using namespace std; ...
- Maximo7自定义实现WebService
最近很多人在群里聊这个话题,我就也一个hello world来实现一下. 1.自定义一个类,继承于AppService 代码如下:
- ADB简单基础命令
1.查看设备 adb devices 这个命令是查看当前连接的设备, 连接到计算机的android设备或者模拟器将会列出显示 2.安装软件 adb install adb install :这个命令将 ...
- 闲鱼demo
编程是一种美德,是促使一个人不断向上发展的一种原动力 -----–以下是正文------- 最近好多app的底部标签导航使用以下形式了,所以我们就来学习一下它是如何实现的. 先看效果: 中间的&quo ...
- Hello Spring Framework——源(Resources)
本文介绍Spring框架如何解析外部资源文件,仅参考官方文档<第7章 Resources>. ***************************以下是正文的部分************ ...
- 8. apache服务实验笔记
Apache服务器 一 简介 1 www:world wide web 万维网 http 协议: 超文本传输协议 HTML语言: 超文本标识语言 2 URL:统一资源定位 协议+域名:端口+网页文 ...
- USB 设备的PID-Product ID,VID-Vendor ID
根据USB规范的规定,所有的USB设备都有供应商ID(VID)和产品识别码(PID),主机通过不同的VID和PID来区别不同的设备,VID 和PID都是两个字节长,其中,供应商ID(VID)由供应商向 ...
- Manthan, Codefest 16 -C. Spy Syndrome 2
time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...
- Javascript > Eclipse > problems encountered during text search
Reproduce: Ctrl + H, Select "File Search", will encounter eclipse kinds of bug/error alert ...