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" ...
随机推荐
- 夺命雷公狗-----React---19--表单的值的修改
少了1个e,在代码部分补回,否则会报错 <!DOCTYPE> <html> <head> <meta charset="utf-8"> ...
- 【KeyCode 键码】
Key codes returned by Event.keyCode. These map directly to a physical key on the keyboard. KeyCode是由 ...
- Linux下make与makefile
make 用来解析 makefile 文件 make 的选项:-d 显示调试信息-f 文件 默认是从 makefile 或 Makefile 中读取依赖信息,用该选项可更改文件-h 显示所有 ...
- 分布式入门之1:Lease机制
引子: 分布式系统中,如何确认一个节点是否工作正常? 如果有3副本A.B.C,并通过中心结点M来管理.其中A为主副本. 未接触过分布式的直观的处理方法是在每个副本与中心节点M中维护一个心跳,期 ...
- YbSoftwareFactory 代码生成插件【十九】:实体类配合数据库表字段进行属性扩展的小技巧
实体类通常需要和数据库表进行了ORM映射,当你需要添加新的属性时,往往同时也需要在数据库中添加相应的字段并配置好映射关系,同时可能还需对数据访问组件进行重新编译和部署才能有效.而当你开始设计一个通用数 ...
- Mono.Ceil 无法保存Silverlight 程序集
一句话: 处理Silverlight程序集之前, 须先移除强名称(StrongNameRemoveHelper), 之后Reflexil 即可一如预期的正常工作.
- 读书笔记 --TCP :传输控制协议(二)
TCP建立连接 请求端(客户端)发送一个SYN指明客户端打算连接的服务器端口号,以及初始序列号. 服务端发回包含服务器的初始序号的SYN报文段作为应答.同时,将确认序号设置为客户的ISN加1以对客户的 ...
- C#调用RAR压缩与解压
public void RARsave(string rarPatch, string rarFiles,string patch,string rarName) { ...
- 小结一下前段时间做的rpgdemo
虽然说已经是彻底放弃继续做那个demo了(代码结构混乱,想增加新功能非常的不方便),不过还是花了一点心血在里面的,毕竟这是我开始学习unity游戏制作的初衷,不过果然是学的越多越发现自己的不足... ...
- android HAL 教程(含实例)
http://www.cnblogs.com/armlinux/archive/2012/01/14/2396768.html Android Hal 分析 ...