Zephyr提供一组connectivity API访问网络,和Socket类似可以通过Connectivity API可以create & close连接,接受和发送数据(包括TCP和UDP)。不一样的是Connectivity API使用的是 Fragment buffer,而Socket使用的是Linear buffer。
Connectivity API定义在include/net/net_context.h中
Fragment buffer定义在include/net/buf.h中
Connectivity API
只列了示例中api,更多参见头文件net_pkt.h,net_core.h,net_context.h或者文档
net_ipaddr_copy: ip地址复制
net_if_get_default:获取默认的iface,网卡控制接口
net_if_ipv4_addr_add:配置iface IPV4地址
net_context_get:获取tcp/ip context,作为网络控制句柄
net_context_bind: 绑定context通讯地址和端口
net_context_recv: 注册一个回调函数用于接收context上的网络封包
net_context_sendto:向指定的context发送网络封包
net_context_put:关闭一个context
net_pkt_get_tx: 获取一个pkt用于填装要发送的网络封包
net_pkt_appdatalen:获取指定pkt的封包应用层数据的长度
net_pkt_appdata:获取指定pkt的封包应用层数据指针
net_pkt_get_data:获取指定pkg的封包net_buf
net_pkt_family:获取pkt的family(ipv6 or v4)
net_pkt_unref: 释放一个pkg
net_buf_frags_len: 获取net_buf的data buf长度
net_buf_pull:从net_buf的最开始移除指定长度的数据
net_buf_add:向net_buf添加指定长度的数据(只移动指针,并返回需要添加数据的头指针)
net_buf_frag_add:将指定的net_buf加入到net_pkt中
net_buf_frag_del:从net_pkt中删除指定的net_buf
Sample
void main(void)
{
NET_INFO(“Run sample application”);
init_app();
create_context();
bind_address();
receive_data();
k_sem_take(&waiter, K_FOREVER);
close_context();
NET_INFO("Stopping sample application");
}
使用connectivity API进行网络通行,可以分为以下几个步骤
- 初始化
- 建立连接
- 接收&发送数据
- 关闭连接
初始化
初始化主要是完成ip地址的添加1
2
3
4
5
6
7
8
9
10
11#define MY_IPADDR {{ { 192, 0, 2, 1 } } }
static struct in_addr my_addr = MY_IPADDR;
static inline void init_app(void)
{
k_sem_init(&waiter, 0, 1);
/* Add our address to the network interface */
net_if_ipv4_addr_add(net_if_get_default(), &my_addr,
NET_ADDR_MANUAL, 0);
}
建立连接
使用net_context_get获取ip stack的context,再将要通信的ip地址和端口绑定上去,这里要接受所有ip地址的数据因此用INADDR_ANY,只接受端口5683的数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29static int create_context(void)
{
ret = net_context_get(AF_INET4, SOCK_DGRAM, IPPROTO_UDP, &context); //获取UDP的context
if (!ret) {
NET_ERR("Cannot get context (%d)", ret);
return ret;
}
return 0;
}
#define INADDR_ANY 0
#define INADDR_ANY_INIT { { { INADDR_ANY } } }
static int bind_address(void)
{
static struct sockaddr_in any_addr = {
.sin_family = AF_INET,
.sin_addr = INADDR_ANY_INIT,
.sin_port = htons(5683) };
ret = net_context_bind(context, (struct sockaddr *) &any_addr, sizeof(any_addr));
if (ret < 0) {
NET_ERR("Could not bind the context\n");
return ret;
}
return 0;
}
数据接收和发送
接收
数据接收是将接收回调函数注册到network stack,当network stack收到数据后就会调用回调函数,将数据送入回调函数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49static int receive_data(void)
{
ret = net_context_recv(context, udp_received, 0, NULL); //这里注册回调函数,用于接受udp数据(context是前面获取的udp context)
if (ret < 0) {
NET_ERR("Cannot receive IPv4 UDP packets");
quit();
return ret;
}
return 0;
}
//network stack收到udp后放到net_buf中调用udp_received处理
static void udp_received(struct net_context *context,
struct net_buf *buf,
int status,
void *user_data)
{
struct net_pkt *reply_pkt;
struct sockaddr dst_addr;
sa_family_t family = net_pkt_family(buf);
static char dbg[MAX_DBG_PRINT + 1];
int ret;
snprintf(dbg, MAX_DBG_PRINT, "UDP IPv%c",
family == AF_INET6 ? '6' : '4');
set_dst_addr(family, buf, &dst_addr);
//处理接收到的buf包,并组合成要发送的数据reply_pkt
reply_pkt = udp_recv(dbg, context, buf);
//当数据使用完后需要用net_pkt_unref将stack的数据包释放掉
net_pkt_unref(buf);
//将reply_pkt发送出去
ret = net_context_sendto(reply_pkt, &dst_addr, udp_sent, 0,
UINT_TO_POINTER(net_buf_frags_len(reply_pkt->frags)),
user_data);
if (ret < 0) {
NET_ERR("Cannot send data to peer (%d)", ret);
net_pkt_unref(reply_pkt);
quit();
}
}
发送
1 |
|
关闭连接
数据收发完毕后要将连接关闭1
2
3
4
5
6
7
8
9
10static int close_context(void)
{
ret = net_context_put(context);
if (ret < 0) {
NET_ERR("Cannot close IPv6 UDP context");
return ret;
}
return 0;
}
参考
http://docs.zephyrproject.org/subsystems/networking/networking-api-usage.html
http://docs.zephyrproject.org/api/networking.html