本文介绍了Rime协议栈单跳单播连接建立过程的连接结构体,包括rucb_conn --> runicast_conn --> stunicast_conn --> unicast_conn --> broadcast_conn --> abc_conn。 PS:为了叙述方便,将连接建立过程的连接结构体单独成文,阅读时,请结合以下博文:
1. 概述
1.1 讨论范围
Rime协议栈提供单跳单播、单跳广播、多跳三种功能,本文仅介绍单跳单播(Single-hop unicast)连接相关的结构体,如下图红色箭头所示:
图1 Rime协议栈系统框图
图1蓝色下划线suc
、stuc
是两篇不同论文的名称,事实上是同一个意思。因源代码用的也是stuc
,故在以后讨论使用stuc
。关于图1各名词解释,详见博文《概述及学习资料》。
1.2 连接结构体概述
使用Rime协议栈进行通信之前,需要建立连接,也就需要保存该连接一些信息(如发送者、接收者),Rime协议栈用一系列结构体保存这些链接状态信息。而建立连接过程说白了就是设置这些结构体相应的成员变量,所以有必要了解下连接结构体各成员变量的含义。Rime是层次型协议栈,上层的连接结构体嵌套着下层的结构体,自顶向下的连接结构体如下:
rucb_conn-->runicast_conn-->stunicast_conn-->unicast_conn-->broadcast_conn-->abc_conn
连接结构体与连接建立、回调结构体间对应关系如下图:
open、coon、callbacks对应关系源文件:open、coon、callbacks对应关系.vsd
图1 open、coon、callbacks对应关系二、rucb_conn
2. rucb_conn
rucb
是块传输(Bulk transfer)层[1],可以理解成传输层。结构体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;
};
结构体rucb_conn
各成员变量含义如下:
c
详情见第三部分。
u
结构体rucb_callbacks
有3个函数指针成员变量写数据块write_chunk
、读数据块read_chunk
、超时timedout
,由用户自己实现,详情见博文《Rime协议栈单跳单播建立连接之callbacks》。
receiver、sender
用于标识接收者和发送者。这里的receiver是指目的节点的接收地址。
chunk
数据块数目。
last_seqno
一次数据发送多个片段的最后一个序列号,当接收端接收到数据时,判断其序列号是否等于最后一个序列号,若等于则不接收(即接收到最后一个数据块,停止接收)。
3. runicast_conn
ruc
是可靠通信的另一层,该层主要实现确认和序列功能(acknowledgments and sequencing)[1]。结构体runicast_conn
源代码如下:
struct runicast_conn
{
struct stunicast_conn c;
const struct runicast_callbacks *u;
uint8_t sndnxt;
uint8_t is_tx;
uint8_t rxmit;
uint8_t max_rxmit;
};
结构体runicast_conn
各成员变量含义如下:
c
详情见第四部分。
u
结构体runicast_callbacks
有3个函数指针成员变量接收recv
、发送sent
、超时timedout
,分别映射到接收recv
、确认acked
、超时timedout
函数(在contiki/core/net/rime/rucb.c
实现),详情见博文《Rime协议栈单跳单播建立连接之callbacks》。
sndnxt
sndnxt
表示Send Next,想想报文分片的时候,sndnxt
为下一个待发送数据片在整个报文的偏移量,即下一个待发送数据片的序列号。(这点需阅读源代码加以验证)
is_tx
is_tx
表示is transmitting,用来标记连接线路上是否有数据在传输(0表示无数据传输,1表示有数据在传输)。
rxmit
rxmit
表示retransmissions,记录重传次数。
max_rxmit
max_rxmit
表示maximum retransmissions,最大重传次数。当重传次数大于等于最大重传次数时,取消传输。
4. stunicast_conn
stuc
是可靠通信的另一层,该层在给定的时间间隔不断地重发数据包,直到上层让其停止。为了防止无限重发,需要指定最大重发次数(maximum retransmission number)[1],结构体stunicast_conn
源代码如下:
struct stunicast_conn
{
struct unicast_conn c;
struct ctimer t;
struct queuebuf *buf;
const struct stunicast_callbacks *u;
rimeaddr_t receiver;
};
结构体stunicast_conn
各成员变量含义如下:
c
详情见第五部分。
u
结构体stunicast_callbacks
有2个函数指针成员变量接收recv
、发送sent
,分别映射到接收recv_from_stunicast
、发送sent_by_stunicast
函数(在contiki/core/net/rime/runicast.c
实现),详情见博文《Rime协议栈单跳单播建立连接之callbacks》。
t
Contiki提供5个定时器模型,即timer
、stimer
、ctimer
、etimer
、rtimer
。ctimer
由Rime使用,计时器到期调用某函数(Active timer, calls a function when it expires, Used by Rime)。正如上面所说,stuc
层在给定的时间间隔不断地重发数据包,t表示该时间间隔(待读源码验证)。
buf
queuebuf
表示queue buffer,队列缓冲区。所有发出和收到的数据包都被存储在一个缓冲区Rime buffer,Rime缓冲区包含应用程序数据和数据包属性(packet attributes)。一些需要数据包队列(queue packets)协议能够从队列缓冲池(a pool of Queue buffers)动态分配队列缓冲区(queue buffer),被分配后,Rime缓冲区的内容被拷贝到队列缓冲区[2]。
receiver
这里的receiver
不同于rucb_conn->receiver
,数据包从源到目的地传输,需要经过若干节点,rucb_conn->receiver
指的是目的节点的地址,而stunicast_conn->receiver
指的是直接接收者地址(从源到目的路径上中间节点地址)。(待读源码验证)
4.1 queuebuf
queuebuf
结构体定义如下:
struct queuebuf {
#if QUEUEBUF_DEBUG
struct queuebuf *next;
const char *file;
int line;
clock_time_t time;
#endif
uint16_t len;
uint8_t data[PACKETBUF_SIZE];
struct packetbuf_attr attrs[PACKETBUF_NUM_ATTRS];
struct packetbuf_addr addrs[PACKETBUF_NUM_ADDRS];
};
#ifdef PACKETBUF_CONF_SIZE
#define PACKETBUF_SIZE PACKETBUF_CONF_SIZE
#else
#define PACKETBUF_SIZE 128
#endif
#define PACKETBUF_NUM_ATTRS (PACKETBUF_ATTR_MAX - PACKETBUF_NUM_ADDRS)
#define PACKETBUF_NUM_ADDRS 4
PACKETBUF_ATTR_MAX
包含在一个枚举enum
类型中,如 :
enum {
PACKETBUF_ATTR_NONE,
/* Scope 0 attributes: used only on the local node. */
PACKETBUF_ATTR_CHANNEL,
PACKETBUF_ATTR_NETWORK_ID,
PACKETBUF_ATTR_LINK_QUALITY,
PACKETBUF_ATTR_RSSI,
PACKETBUF_ATTR_TIMESTAMP,
PACKETBUF_ATTR_RADIO_TXPOWER,
PACKETBUF_ATTR_LISTEN_TIME,
PACKETBUF_ATTR_TRANSMIT_TIME,
PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS,
PACKETBUF_ATTR_MAC_SEQNO,
PACKETBUF_ATTR_MAC_ACK,
/* Scope 1 attributes: used between two neighbors only. */
PACKETBUF_ATTR_RELIABLE,
PACKETBUF_ATTR_PACKET_ID,
PACKETBUF_ATTR_PACKET_TYPE,
PACKETBUF_ATTR_REXMIT,
PACKETBUF_ATTR_MAX_REXMIT,
PACKETBUF_ATTR_NUM_REXMIT,
PACKETBUF_ATTR_PENDING,
/* Scope 2 attributes: used between end-to-end nodes. */
PACKETBUF_ATTR_HOPS,
PACKETBUF_ATTR_TTL,
PACKETBUF_ATTR_EPACKET_ID,
PACKETBUF_ATTR_EPACKET_TYPE,
PACKETBUF_ATTR_ERELIABLE,
/* These must be last */
PACKETBUF_ADDR_SENDER,
PACKETBUF_ADDR_RECEIVER,
PACKETBUF_ADDR_ESENDER,
PACKETBUF_ADDR_ERECEIVER,
PACKETBUF_ATTR_MAX
};
5. unicast_conn
uc
(unicast abstraction)将上层的数据包添加一个接收者头部(adds a receiver header field)[1],结构体unicast_conn
源代码如下:
struct unicast_conn
{
struct broadcast_conn c;
const struct unicast_callbacks *u;
};
结构体unicast_conn
各成员变量含义如下:
c
详情见第六部分。
u
结构体unicast_callbacks
有2个函数指针成员变量接收recv
、发送sent
,分别映射到接收recv_from_uc
、发送sent_by_uc
函数(在contiki/core/net/rime/stunicast.c
实现),详情见博文《Rime协议栈单跳单播建立连接之callbacks》。
6. broadcast_conn
ibc
(identified sender best-effort broadcast)将上层的数据包添加一个发送者身份(sender identity)头部[1],结构体broadcast_conn
源代码如下:
struct broadcast_conn
{
struct abc_conn c;
const struct broadcast_callbacks *u;
};
结构体broadcast_conn
各成员变量含义如下:
c
详情见第七部分。
u
结构体broadcast_callbacks
有2个函数指针成员变量接收recv
、发送sent
,分别映射到接收recv_from_broadcast
、发送sent_by_broadcast
函数(在contiki/core/net/rime/unicast.c
实现),详情见博文《Rime协议栈单跳单播建立连接之callbacks》。
7. abc_conn
abc
(anonymous broadcast,匿名广播)将数据包通过无线射频驱动(radio driver)发出去,接收来自无线射频驱动所有的包并交给上层[1]。结构体abc_conn
源代码如下:
struct abc_conn
{
struct channel channel;
const struct abc_callbacks *u;
};
结构体abc_conn
各成员变量含义如下:
channel
Rime协议栈所有通信都是通过通道channel标识的,即两个应用进程通信需要相同的channel,关于channel介绍见博文《通道channel》。
u
结构体abc_callbacks
有2个函数指针成员变量接收recv
、发送sent
,分别映射到接收recv_from_abc
、发送sent_by_abc
函数(在contiki/core/net/rime/broadcast.c
实现),详情见博文《Rime协议栈单跳单播建立连接之callbacks》。
参考资料:
[1] 博文《概述及学习资料》
[2] Adam Dunkels,Fredrik Osterlind,Zhitao He. An Adaptive Communication Architecture for Wireless Sensor Networks[J]