简介

        现实中多设备间通信方式多种多样(WIFI、蓝牙等),不同的通信方式使用差异大,导致通信问题多;同时还面临设备间通信链路的融合共享和冲突无法处理等挑战。分布式软总线实现近场设备间统一的分布式通信管理能力,提供不区分链路的设备间发现连接、组网和传输能力,主要功能如下:

  1. 发现连接:提供基于Wifi、蓝牙等通信方式的设备发现连接能力。
  2. 设备组网:提供统一的设备组网和拓扑管理能力,为数据传输提供已组网设备信息。
  3. 数据传输:提供数据传输通道,支持消息、字节、流、文件的数据传输能力。

        业务方通过使用分布式软总线提供的API实现设备间的高速通信,不用关心通信细节,进而实现业务平台的高效部署与运行能力。

 

系统架构

 

目录

        分布式软总线组件主要代码目录结构如下:

//foundation/communication/dsoftbus
├── adapter               # 适配层代码
├── components            # 依赖组件代码
├── core                  # 核心代码
│   ├── adapter           # 适配层代码
│   ├── authentication    # 认证代码
│   ├── bus_center        # 组网代码
│   ├── common            # 通用代码
│   ├── connection        # 连接代码
│   ├── discovery         # 发现代码
│   ├── frame             # 框架代码
│   └── transmission      # 传输代码
├── interfaces            # 对外接口代码
├── sdk                   # 运行业务进程代码
│   ├── bus_center        # 组网代码
│   ├── discovery         # 发现代码
│   ├── frame             # 框架代码
│   └── transmission      # 传输代码
├── tests                 # 测试代码
└── tools                 # 工具代码
  • SDK:为其他业务提供软总线的能力接口,如发现设备,发布服务,设备连接,远端设备信息获取,时间同步,注册回调接收设备上下线消息,设备信息变更消息;SDK 对外提供 softbus_client.so,头文件均在 interfaces/kits 目录里;
  • Tools:提供 SoftBusDumpDeviceInfo 工具,可以查看本地的设备信息和所有发现的设备信息;
  • Core:软总线的核心实现部分,提供 softbus_server 库,实现 system ability 框架提供系统能力;
    • discovery:提供对网络设备和蓝牙设备的发布,发现,连接的能力,
    • authentication:设备认证模块,对不同类型的连接方式提供不同的认证实现和统一的认证能力,并为分布式设备业务提供 DeviceAuthCallback;设备认证模块依赖//base/security/device_auth/services:deviceauth_sdk 库。认证模块提供认证连接对应的处理,如连接处理(OnConnectResult),数据处理(OnDataReceived),断开处理(OnDisconnected)三个基础入口,提供设备的连接认证能力;
    • connection:提供 ble,br,tcp,p2p 连接方式。连接模块会启动一个后台连接服务,此连接服务提供默认的 tcp,ble,br,p2p 的连接处理接口,服务内部通过一个线程池处理连接的任务;认证模块通过连接模块进行认证连接,同时连接模块也提供回调接口,为业务模块提供数据返回。连接模块就是通过具体的连接业务实现代码为业务模块提供设备连接和信息传输通道;目前主要提供的连接方式为 socket 或者蓝牙两种;其中接口声明在 interface 目录下;
    • transmission:提供消息发送接口,可以发送加密信息或者不加密信息,加密方式根据认证的信息确认,使用认证会话的 key 作为 key 值,加密方式为 aes 加密。
    • bus_center:提供核心的 LNN 本地网络服务接口,包括网络服务发现,连接,服务发布等核心能力,以及设备管理能力。bus_center 作为软总线的管理节点提供本地网络拓扑账本(NetLedger),消息处理回环(BusLooper),事件处理对象(Netlink,Product,Lwip,Wifi,BtState,Driver,ScreenState,DeviceName),网络发现服务(Coap),网络接口(Netif, softbus_feature_config.c 里写死),消息网络构造(NetBuilder),本地网络路由管理(LaneHub),节点地址分配(NodeAddrAllocator)。软总线设计目标为无感的设备互联互通,所以每个标准设备都可以作为一个网络节点也可以作为一个网关,而 bus_center 就是作为网关实现的部分。软总线服务通过收听系统的事件,包括设备事件,网络事件以感知本设备的每一处变化,然后根据变化来决定是否可以感知到周围新的节点设备加入网络,并提供设备认证,连接,传输数据的服务;
    • common:核心部分的基础代码,如 bitmap(位图),dfx(DesignForX,未来设计),json,messagehandler(软总线信令),network(网络频率参数),queue(队列),security(权限认证),property(软总线配置),utils(工具集,timeout,hextobytes,random,等等)
    • frame:框架层,不同类型的系统(小型系统 L0,轻量系统 L1,标准系统 L2)提供不同的对外接口实现;
    • adapter:适配层,目前适配不同的设备类型,如 WiFi,蓝牙等;
  • Adapter:软总线适配层,对不同系统进行裁剪和能力配置,对外部依赖进行包装和调用;
  • Component:组件,mbedtls(SSL 算法库),nstackx(网络协议库,为 coap 提供网络协议服务)

约束

  1. 组网设备需在同一局域网中 或者 距离相近的近场设备间。
  2. 组网之前,需先完成设备绑定。
  3. 传输完成数据收发之后,业务要主动关闭会话,释放资源。

 

说明

使用说明

        须知: 使用跨设备通信时,必须添加权限ohos.permission.DISTRIBUTED_DATASYNC和ohos.permission.DISTRIBUTED_SOFTBUS_CENTER,该权限类型为 dangerous 。

1、发现

  • 发布流程
  1. 上层应用需要对外发布自身能力时,调用服务发布接口发布自身能力。

// 发布回调
typedef struct {
    /** Callback for publish result */
    void (*OnPublishResult)(int publishId, PublishResult reason);
} IPublishCb;

// 发布信息
typedef struct {
    int publishId;                  // 发布消息Id
    DiscoverMode mode;              // 发布模式
    ExchangeMedium medium;          // 发布媒介
    ExchangeFreq freq;              // 发布频率
    const char *capability;         // 被发现设备需要具备的能力
    unsigned char *capabilityData;  // 业务发布的自定义数据
    unsigned int dataLen;           // 数据长度
    bool ranging;                   // 是否测距
} PublishInfo;

// 发布服务
int32_t PublishLNN(const char *pkgName, const PublishInfo *info, const IPublishCb *cb);

    2.上层应用不再需要对外发布自身能力时,调用StopPublishLNN接口注销服务。

 

// 注销服务
int32_t StopPublishLNN(const char *pkgName, int32_t publishId);
  • 发现流程

    1.上层应用需要发现特定能力设备时,调用发现接口启动发现。

// 发现回调
typedef struct {
    /** Callback that is invoked when a device is found */
    void (*OnDeviceFound)(const DeviceInfo *device);
    /** Callback for a subscription result */
    void (*OnDiscoverResult)(int32_t refreshId, RefreshResult reason);
} IRefreshCallback;

// 发现服务
int32_t RefreshLNN(const char *pkgName, const SubscribeInfo *info, const IRefreshCallback *cb);

    2.当软总线发现到设备时,通过回调接口通知业务所发现的设备信息。

    3.上层应用不再需要发现时,调用StopRefreshLNN接口停止设备发现。

// 停止发现
int32_t StopRefreshLNN(const char *pkgName, int32_t refreshId);

 

2、组网

    1.发起组网请求,携带组网连接地址信息,并且提供组网执行结果回调函数。

// 组网连接地址
typedef struct {
    ConnectionAddrType type;
    union {
        struct BrAddr {
            char brMac[BT_MAC_LEN];
        } br;
        struct BleAddr {
            char bleMac[BT_MAC_LEN];
            uint8_t udidHash[UDID_HASH_LEN];
        } ble;
        struct IpAddr {
            char ip[IP_STR_MAX_LEN];
            uint16_t port; 
        } ip;
    } info;
    char peerUid[MAX_ACCOUNT_HASH_LEN];
} ConnectionAddr;

// 组网连接地址类型
typedef enum {
    CONNECTION_ADDR_WLAN = 0,
    CONNECTION_ADDR_BR,
    CONNECTION_ADDR_BLE,
    CONNECTION_ADDR_ETH,
    CONNECTION_ADDR_MAX
} ConnectionAddrType;

// 组网请求执行结果回调
typedef void (*OnJoinLNNResult)(ConnectionAddr *addr, const char *networkId, int32_t retCode);

// 发起组网请求
int32_t JoinLNN(const char *pkgName, ConnectionAddr *target, OnJoinLNNResult cb);

    2.等待组网结果,JoinLNN()返回成功表示软总线接受了组网请求,组网结果通过回调函数通知业务;组网回调函数中addr参数内容和JoinLNN()的入参互相匹配;retCode如果为0,表示组网成功,此时networkId为有效值,后续传输、退网等接口均需使用该参数;retCode如果不为0,表示组网失败,此时networkId为无效值。

    3.使用传输相关接口进行数据传输。

    4.发送退网请求,携带组网成功后返回的networkId,并且提供退网执行结果回调。

// 退网执行结果回调
typedef void (*OnLeaveLNNResult)(const char *networkId, int32_t retCode);

// 退网请求
int32_t LeaveLNN(const char *pkgName, const char *networkId, OnLeaveLNNResult cb);

    5.等待退网完成,OnLeaveLNNResult()的networkId和退网请求接口中的networkId互相匹配;retCode为0表示退网成功,否则退网失败。退网成功后,networkId变为无效值,后续不应该被继续使用。

    6.使用节点(即设备)注册和注销接口,监听网络中节点状态变化等事件。

// 事件掩码
#define EVENT_NODE_STATE_ONLINE 0x1
#define EVENT_NODE_STATE_OFFLINE 0x02
#define EVENT_NODE_STATE_INFO_CHANGED 0x04
#define EVENT_NODE_STATUS_CHANGED 0x08
#define EVENT_NODE_STATE_MASK 0xF

// 节点信息
typedef struct {
    char networkId[NETWORK_ID_BUF_LEN];
    char deviceName[DEVICE_NAME_BUF_LEN];
    uint16_t deviceTypeId;
} NodeBasicInfo;

// 节点状态事件回调
typedef struct {
    uint32_t events; // 组网事件掩码
    void (*onNodeOnline)(NodeBasicInfo *info);   // 节点上线事件回调
    void (*onNodeOffline)(NodeBasicInfo *info);  // 节点下线事件回调
    void (*onNodeBasicInfoChanged)(NodeBasicInfoType type, NodeBasicInfo *info); // 节点信息变化事件回调
    void (*onNodeStatusChanged)(NodeStatusType type, NodeStatus *status); // 设备运行状态变化事件回调
} INodeStateCb;

//  注册节点状态事件回调
int32_t RegNodeDeviceStateCb(const char *pkgName, INodeStateCb *callback);

// 注销节点状态事件回调
int32_t UnregNodeDeviceStateCb(INodeStateCb *callback);

 

3、传输

    1.创建Socket。

typedef struct {
    char *name;                 // 本端Socket名称
    char *peerName;             // 对端Socket名称
    char *peerNetworkId;        // 对端Socket的网络ID
    char *pkgName;              // 调用者包名
    TransDataType dataType;     // 传输的数据类型,需要与发送方法一致
} SocketInfo;

// 创建Socket
int32_t Socket(SocketInfo info);

2.服务端启动监听,客户端进行绑定。

// Socket回调函数
typedef struct {
    void (*OnBind)(int32_t socket, PeerSocketInfo info);
    void (*OnShutdown)(int32_t socket, ShutdownReason reason);
    void (*OnBytes)(int32_t socket, const void *data, uint32_t dataLen);
    void (*OnMessage)(int32_t socket, const void *data, uint32_t dataLen);
    void (*OnStream)(int32_t socket, const StreamData *data, const StreamData *ext, const StreamFrameInfo *param);
    void (*OnFile)(int32_t socket, FileEvent *event);
    void (*OnQos)(int32_t socket, QoSEvent eventId, const QosTV *qos, uint32_t qosCount);
    void (*OnError)(int32_t socket, int32_t errCode);
    void (*OnBytesSent)(int32_t socket, uint32_t dataSeq, int32_t errCode);
} ISocketListener;

typedef enum {
    QOS_TYPE_MIN_BW,            // 最小带宽
    QOS_TYPE_MAX_WAIT_TIMEOUT,  // Bind超时时间
    QOS_TYPE_MIN_LATENCY,       // 最小建链时延
    QOS_TYPE_RTT_LEVEL,         // 往返时间级别
    QOS_TYPE_MAX_BUFFER,        // 最大缓存(预留)
    QOS_TYPE_FIRST_PACKAGE,     // 首包大小(预留)
    QOS_TYPE_MAX_IDLE_TIMEOUT,  // 最大空闲时间
    QOS_TYPE_TRANS_RELIABILITY, // 传输可靠性(预留)
    QOS_TYPE_BUTT,
} QosType;

typedef struct {
    QosType qos;
    int32_t value;
} QosTV;

// 监听Socket,由服务端开启。
int32_t Listen(int32_t socket, const QosTV qos[], uint32_t qosCount, const ISocketListener *listener);

// 绑定Socket,由客户端开启。
int32_t Bind(int32_t socket, const QosTV qos[], uint32_t qosCount, const ISocketListener *listener);

    3.通过Socket向对端设备发送数据。

// 发送字节数据
int32_t SendBytes(int32_t socket, const void *data, uint32_t len);
// 异步发送字节数据, dataSeq是无符号的不为0值的整数
int32_t SendBytesAsync(int32_t socket, uint32_t dataSeq, const void *data, uint32_t len);
// 发送消息数据
int32_t SendMessage(int32_t socket, const void *data, uint32_t len);
// 发送流数据
int32_t SendStream(int32_t socket, const StreamData *data, const StreamData *ext, const StreamFrameInfo *param);
// 发送文件
int32_t SendFile(int32_t socket, const char *sFileList[], const char *dFileList[], uint32_t fileCnt);

    4.关闭Socket。

// 关闭Socket
void Shutdown(int32_t socket);

 

4、设备管理相关

  • 选择Wi-Fi保活模式

    1.业务在软总线客户端调用ShiftLNNGear,通过IPC接口调用到服务端ShiftLNNGear,策略管理模块按照策略对TCP长连接的keepalive属性进行调整。

typedef struct {
    ModeCycle cycle;              // 保活探测间隔
    ModeDuration duration;        // 心跳模式持续时间
    bool wakeupFlag;              // 是否心跳唤醒对端设备
    ModeAction action;            // 选择模式动作
} GearMode;

typedef enum {
    HIGH_FREQ_CYCLE = 30,         // 心跳间隔30s
    MID_FREQ_CYCLE = 60,          // 心跳间隔60s
    LOW_FREQ_CYCLE = 5 * 60,      // 心跳间隔5min
    DEFAULT_FREQ_CYCLE = 10 * 60, // 心跳间隔10min
} ModeCycle;

// 按照策略对TCP长连接的keepalive参数进行调整
int32_t ShiftLNNGear(const char *pkgName, const char *callerId, const char *targetNetworkId, const GearMode *mode);

    2.业务指定不同的保活探测间隔,对应不同的TCP保活时长。

HIGH_FREQ_CYCLE = 30,代表TCP保活时长在40s以内;
MID_FREQ_CYCLE = 60,代表TCP保活时长在70s以内;
LOW_FREQ_CYCLE = 5*60,代表TCP保活时长在315s以内;
DEFAULT_FREQ_CYCLE = 10*60,代表TCP保活时长在615s以内。

 

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐