xuos-web/docs/doc/framework/lian.md

314 lines
12 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 联 - 网络框架
多数嵌入式操作系统,应具备传输多种网络协议数据的能力,但是网络协议种类繁多,为每种协议都开放单独的接口,势必会增加操作系统使用者的开发负担,亦不利于嵌入式操作系统的普及与推广。
XiUOS网络框架采用以网络适配器为中心的抽象方式发送与接收数据时只需要像Linux socket网络通信一样仅关注发送与接收的数据而不用把重点放在所使用的具体协议上。这种抽象方式有效屏蔽了种类繁多的网络协议细节对外提供统一的网络接口简化了基于嵌入式操作系统的网络开发。网络框架对各类协议的网络设备进行了抽象
* 一个网络协议设备被抽象为一个Adapter
Adapter可以被设计为采用类似面向对象的方法针对不同的网络协议扩展其数据成员与接口从而为种类繁多的网络协议实现统一的管理架构。在网络应用开发的过程中只需要使用对应网络协议的Adapter实例而无需关心网络协议的硬件细节从而实现了网络数据收发功能与底层硬件的解耦。
<center>
![LIAN IMAGE](./imagesrc/lian.png)
</center>
## 1. XiUOS网络框架关键数据结构定义和解析
* struct Adapter结构
```c
struct Adapter
{
char name[NAME_NUM_MAX];
int fd;
int product_info_flag;
struct AdapterProductInfo *info;
ATAgentType agent;
struct Socket socket;
int net_role_id;
enum NetProtocolType net_protocol;
enum NetRoleType net_role;
enum AdapterStatus adapter_status;
char buffer[ADAPTER_BUFFSIZE];
void *done;
void *adapter_param;
struct DoublelistNode link;
};
```
name成员是一个可读的名字用于唯一标识一个Adapter结构。fd成员是一个标识符编号用于唯一标识此网络设备所用串口。product_info_flag用于根据型号给设备进行分类。AdapterProductInfo结构体包含该网络设备的一些信息如厂家名vendor与型号product_model。
```c
struct AdapterProductInfo
{
uint32_t functions;
char vendor_name[NAME_NUM_MAX];
char model_name[NAME_NUM_MAX];
uint32_t work_mode;
void *model_done;
};
```
其中model_done成员包含统一的API用于对特定网络适配器进行实际的数据读写。model_done成员有IpProtocolDone/PrivProtocolDone两套接口根据网络适配器种类而定两套接口都具有的基础API如下。在使用一个网络适配器前后需要打开open/关闭close该网络适配器打开适配器后需要配置(ioctl)其属性setup和setdown用于使能/关闭网络传输功能setaddr/setdns/setdhcp/ping/netstat为一些基础打网络调试接口send/recv分别用于从网络适配器接收数据与向网络适配器发送数据connect/disconnect用于建立/断开一个网络连接。
```c
struct IpProtocolDone/PrivProtocolDone
{
int (*open)(struct Adapter *adapter);
int (*close)(struct Adapter *adapter);
int (*ioctl)(struct Adapter *adapter, int cmd, void *args);
int (*setup)(struct Adapter *adapter);
int (*setdown)(struct Adapter *adapter);
int (*setaddr)(struct Adapter *adapter, const char *ip, const char *gateway, const char *netmask);
int (*setdns)(struct Adapter *adapter, const char *dns_addr, uint8 dns_count);
int (*setdhcp)(struct Adapter *adapter, int enable);
int (*ping)(struct Adapter *adapter, const char *destination);
int (*netstat)(struct Adapter *adapter);
int (*connect)(struct Adapter *adapter, enum NetRoleType net_role, const char *ip, const char *port, enum IpType ip_type);
int (*send)(struct Adapter *adapter, const void *buf, size_t len);
int (*recv)(struct Adapter *adapter, void *buf, size_t len);
int (*disconnect)(struct Adapter *adapter);
};
```
agent结构体是串口收发数据结构用于辅助串口通信。网络设备通过agent通信,具有两个缓冲区分别用于向CPU接收和发送信息。
```c
struct ATAgent
{
char agent_name[64];
int fd;
char *maintain_buffer;
uint32 maintain_len;
uint32 maintain_max;
int lock;
ATReplyType reply;
char reply_lr_end;
char reply_end_last_char;
char reply_end_char;
uint32 reply_char_num;
int rsp_sem;
pthread_t at_handler;
#define ENTM_RECV_MAX 256
char entm_recv_buf[ENTM_RECV_MAX];
uint32 entm_recv_len;
enum ReceiveMode receive_mode;
int entm_rx_notice;
};
typedef struct ATAgent *ATAgentType;
```
socket成员用于实现上层通信协议。建立多个安全稳定的tcp/udp套接字通信。
```c
struct Socket
{
uint8_t type; /* socket type:DGRAM->UDP,STREAM->TCP */
uint8_t protocal; /* udp or tcp */
unsigned short listen_port; /* 0-65535 */
uint8_t socket_id;
uint8_t recv_control;
uint8_t af_type; /* IPv4 or IPv6 */
char *src_ip_addr; /* source ip address */
char *dst_ip_addr; /* destination IP address */
};
```
net_protocol成员用于指示此网络设备支持的协议IP_PROTOCOL类型表示支持IP层相关协议PRIVATE_PROTOCOL表示此网络设备支持额外的协议。net_role_id用于辅助net_protocol,用于标识区分该协议下支持的多个设备。
```c
enum NetProtocolType
{
PRIVATE_PROTOCOL = 1,
IP_PROTOCOL,
PROTOCOL_NONE,
};
```
net_role成员用于设置此网络设备通信过程中的模式和角色,包括主、从、路由、终端等。
```c
enum NetRoleType
{
CLIENT = 1,
SERVER,
MASTER,
SLAVE,
COORDINATOR,
ROUTER,
END_DEVICE,
ROLE_NONE,
};
```
adapter_status成员用来指示网络设备注册状态。buffer/done/adapter_param成员均为预留给adapter使用的数据缓冲区和用户数据接口。
```c
enum AdapterStatus
{
REGISTERED = 1,
UNREGISTERED,
INSTALL,
UNINSTALL,
};
```
最后在系统中每种网络协议的Adapter被分别组织成不同双链表如Lora的Adapter链表、4G的Adapter链表等使用的链表节点即为link成员。
## 2. XiUOS网络框架驱动开发
以WiFi网络适配器为例。网络框架针对每个具体的网络适配器填充Adapter的数据成员项如协议类型、设备名称、厂商信息等。数据成员填充完后将其注册。
```c
int AdapterWifiRegister(struct Adapter *adapter);
#define ADAPTER_WIFI_NAME "wifi"
static int AdapterWifiRegister(struct Adapter *adapter)
{
int ret = 0;
strncpy(adapter->name, ADAPTER_WIFI_NAME, 32);
adapter->net_protocol = IP_PROTOCOL;
adapter->adapter_status = UNREGISTERED;
ret = AdapterDeviceRegister(adapter);
if (ret < 0) {
printf("AdapterWifi register error\n");
return -1;
}
return ret;
}
```
WiFi设备协议类型为IP_PROTOCOL故使用IpProtocolDone接口注册到model_done。实现model_done中的数据通信API具体实现细节取决于所使用网络协议无法实现的API可以置为NULL
```c
static const struct IpProtocolDone hfa21_done =
{
.open = Hfa21Open,
.close = Hfa21Close,
.ioctl = Hfa21Ioctl,
.setup = Hfa21SetUp,
.setdown = Hfa21SetDown,
.setaddr = Hfa21SetAddr,
.setdns = NULL,
.setdhcp = NULL,
.ping = Hfa21Ping,
.netstat = Hfa21Netstat,
.connect = Hfa21Connect,
.send = Hfa21Send,
.recv = Hfa21Receive,
.disconnect = NULL,
};
```
将hfa21_done接口注册到model_done
```c
AdapterProductInfoType Hfa21WifiAttach(struct Adapter *adapter)
{
struct AdapterProductInfo *product_info = PrivMalloc(sizeof(struct AdapterProductInfo));
if (!product_info) {
printf("Hfa21WifiAttach Attach malloc product_info error\n");
PrivFree(product_info);
return NULL;
}
strcpy(product_info->model_name, ADAPTER_WIFI_HFA21);
product_info->model_done = (void *)&hfa21_wifi_done;
return product_info;
}
```
## 3. XiUOS网络框架的使用实例
网络应用开发者根据自己的需求将网络框架提供的API加上一些逻辑封装为一套应用层API使用该套API操作网络适配器应用层API可以分为通用API与协议特有API。通用API用于网络适配器的打开、关闭、参数配置以及网络测试功能协议特有API用于特定协议的配置以及数据收发。以Wifi网络适配器为例
```c
/* generic API: open/close a adapter instance */
int AdapterDeviceOpen(struct Adapter *adapter);
int AdapterDeviceClose(struct Adapter *adapter);
/* generic API: configure a adapter instance */
int AdapterDeviceControl(struct Adapter *adapter, int cmd, void *args);
/* generic API: network interface */
int AdapterDeviceSetAddr(struct Adapter *adapter, const char *ip, const char *gateway, const char *netmask);
int AdapterDeviceSetDns(struct Adapter *adapter, const char *dns_addr, uint8 dns_count);
int AdapterDeviceSetDhcp(struct Adapter *adapter, int enable);
int AdapterDevicePing(struct Adapter *adapter, const char *destination);
int AdapterDeviceNetstat(struct Adapter *adapter);
/* Wifi API: get current Wifi adapter reading and receiving */
ssize_t AdapterDeviceSend(struct Adapter *adapter, const void *src, size_t len);
ssize_t AdapterDeviceRecv(struct Adapter *adapter, void *dst, size_t len);
```
在获取数据前,需要先打开要使用的网络适配器;网络适配器打开后对其进行相关参数如波特率等的配置,接着配置相关网络参数后,对网络适配器数据可以随时进行读取;使用完毕后,须关闭网络适配器。完整的使用过程示例如下:
```c
int AdapterWifiTest(void)
{
char cmd[64];
int baud_rate = BAUD_RATE_57600;
struct Adapter* adapter = AdapterDeviceFindByName(ADAPTER_WIFI_NAME);
AdapterDeviceOpen(adapter);
AdapterDeviceControl(adapter, OPE_INT, &baud_rate);
AdapterDeviceSetUp(adapter);
AdapterDeviceSetAddr(adapter, "192.168.66.253", "255.255.255.0", "192.168.66.1");
AdapterDevicePing(adapter, "36.152.44.95");
AdapterDeviceNetstat(adapter);
const char *ip = "192.168.66.211";
const char *port = "12345";
enum NetRoleType net_role = CLIENT;
enum IpType ip_type = IPV4;
AdapterDeviceConnect(adapter, net_role, ip, port, ip_type);
const char *wifi_msg = "LiuKai Test";
int len = strlen(wifi_msg);
for(int i = 0;i < 10; ++i) {
AdapterDeviceSend(adapter, wifi_msg, len);
PrivTaskDelay(4000);
}
char wifi_recv_msg[128];
while (1) {
AdapterDeviceRecv(adapter, wifi_recv_msg, 128);
}
}
```
## 4. XiUOS自组网功能简介
传统的数据收集与上报系统架构,一般采用星型拓扑的组织形式,以网关为中心,将数据收集设备(传感器)连接组织起来,传感器之间一般没有大规模的数据流动。而这种中心化的网络架构,有其自身的缺点,如中心节点的数据压力经常逼近极限,成为整个系统的性能瓶颈,或者一旦程序崩溃,即造成其承载的所有传感器发生掉线事故。
所以我们在提供中心化网络服务的同时,也提供了去中心化的自组网络服务,自组网结构一般具有以下优点:
1、动态接入
传统的中心节点型网络,需要网关手动配置想要连接的传感器,然后对区域进行轮询扫描,传感器则在被轮询到时,被动地上报自己的数据。而自组网新节点需接入时,可实现主动接入,无需对网关进行手动配置,节省运维成本。
2、去中心化
自组网内无中心节点,节点之间可进行自主路由协商,以此来实现跳转通信,相比传统中心化网络,有效分摊网络流量,进而分散节点运算压力。自组网具有良好的健壮性,任何一个节点发生崩溃,其所承载的传感器会自动寻找其他上传节点,不会造成大面积的掉线事故。
3、不依赖现有网络
节点之间通信,不依赖现有的网络基础设施,自组网内部实现网络自治,以此应对通信地点和时间的不确定性。