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" ...
随机推荐
- [转]一个用户SQL慢查询分析,原因及优化
来源:http://blog.rds.aliyun.com/2014/05/23/%E4%B8%80%E4%B8%AA%E7%94%A8%E6%88%B7sql%E6%85%A2%E6%9F%A5%E ...
- Entity Framework7 入门之全功能.NET版本下使用EF7(含源码)另附数据迁移常见错误处理
Entity Framework7 入门之全功能.NET(Console, WinForms, WPF等)使用EF7 昨天,我们介绍了EF的新特性和开发计划,如果你还不了解,请移步 Entity Fr ...
- django静态文件配置
开发环境配置 需要下面几个步骤 1. 在app目录下创建static目录,将静态文件和相关文件夹放到此目录下,如your_app/static/img等 2. 确保settings.py中的INSTA ...
- Swift_UI_UIButton
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 1. 自定义 ...
- If you only do what you can do you'll never be more than you are now.
If you only do what you can do you'll never be more than you are now. 如果你只是做你力所能及的事,你将不会有所进步:
- 分页sql优化
如果分页sql里包含排序: select * from (...order by id) where rownum <=20 因为要排序,所以即使是分页只取20条,执行计划还是要把所有满足条件的 ...
- ImportError: cannot import name 'check_arrays'
from sklearn.utils.validation import check_arrays 执行 from sklearn.utils.validation import check_arra ...
- Oracle数据库的表结构 简单表的建立
- Android多媒体--MediaCodec 中文API文档
*由于工作需要,需要利用MediaCodec实现Playback及Transcode等功能,故在学习过程中翻译了Google官方的MediaCodec API文档,由于作者水平限制,文中难免有错误和不 ...
- webdriver杀死浏览器和Chromedriver进程
/** * 执行dos命令 * @param command */ public static void command(String command) { ...