精华内容
下载资源
问答
  • blobmsg_json用于json对象的序列化 参考链接:https://www.cnblogs.com/embedded-linux/p/6792359.html 一 : blob 的使用 (熟悉使用blob的各种api) #include <stdio.h> #include <sys/types.h> #...

    Blob :二进制大对象

    Blobmsg :二进制对象网络序列化。

    blobmsg_json   用于json对象的序列化

    参考链接:https://www.cnblogs.com/embedded-linux/p/6792359.html

    一 : blob 的使用  (熟悉使用blob的各种api)

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <pthread.h>
    #include <sys/ioctl.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/time.h>
    #include <unistd.h>
    #include <time.h>
    #include <getopt.h>
    #include <sys/signal.h>
    #include "libubox/uloop.h"
    #include "libubox/ustream.h"
    #include "libubox/utils.h"
    #include "libubus.h"
    #include "json-c/json.h"
    #include "libubox/blob.h"
    #include "libubox/blobmsg.h"
    #include "libubox/blobmsg_json.h"
    #include "libubox/ulog.h"
    #include "libubox/runqueue.h"
    #include <libubox/list.h>
    #include <libubox/uloop.h>
    #include <libubox/ustream.h>
    #include "termios.h"
      int main()
    {

    static struct blob_buf b;
    struct blob_attr *attr1,*attr2;
    char * str,*str1;
    void *ptr;
    struct blob_attr * pos;
    int rem=0;
    blob_buf_init(&b, 0);

    //设置blob数据
    attr1=blob_put_string(&b, 1, "hello");

    attr2=blob_put_u8(&b, 2, 100);

    //获取blob数据
    str=blob_get_string(attr1);
    int a1=blob_get_u8(attr2);

    //打印数据

    printf("str=%s\n",str);    
    printf("a1=%d\n",a1);

    //输出有效数据地址  和 id
    ptr=blob_data(attr1);   // blob_data
    printf("ptr=%p\n",ptr);   
    printf("id =%d",blob_id(attr1));  //blob_id

    printf(" 有效存储空间大小  blob_len =%d\n",blob_len(attr1));       // blob_len 
    printf("完全存储空间大小  blob_raw_len =%d\n",blob_raw_len(attr1));   // blob_raw_len
    printf("blob属性填补后空间存储大小  blob_pad_len =%d\n",blob_raw_len(attr1)); //blob_raw_len


    rem=12;
    __blob_for_each_attr(pos,attr1,rem)  //遍历
    {
      str1=blob_get_string(pos);
      printf("str1 =%s\n",str1);
    }
    return 0;
    }

     

    展开全文
  • enum blobmsg_type { //blobmsg 数据类型 BLOBMSG_TYPE_UNSPEC, BLOBMSG_TYPE_ARRAY, BLOBMSG_TYPE_TABLE, BLOBMSG_TYPE_STRING, BLOBMSG_TYPE_INT64, BLOBMSG_TYPE_INT32, BLOBMSG_TYPE_INT16, BLOBMSG_...

    一、简介
    OpenWrt路由操作系统的框架基础软件有很多,大部分是通用的软件模块,如 dhcp 、dnsmasq、iproute、cmwp、vpn、ipsec等等;OpenWrt还集成部分具有专属特征软件模块,也是OpenWRT系统核心框架软件组件,从此篇开始分析 《OpenWrt系统框架基础软件模块》系列文章。
    OpenWrt 核心软件:procd、uci、libubox、ubus、ubox、luci、netifd 软件组件内容,此部分软件模块是构成OpenWrt框架基础软件。
    因为OpenWRT是小型软路由操作系统、网络协议栈知识内容十分丰富、望而生畏;我们先把庞大网络协议栈知识放一下,从易于入手的OpenWRT这个开源软路由开始入手,无论是网络协议栈还是OpenWRT的学习,总是要找到起点或入口;OpenWRT入口处就是 libubox ,因为其他软件是依托libubox库 api 接口构建起来的应用,请参考《详解 OpenWRT系统框架基础软件模块之libubox》

    本篇文章分享的是libblobmsg_json库组件,这个库是 libubox的组成部分。

    二、libblobmsg_json

    OpenWrt支持c、shell、lua三种语言的进程通过ubus进行进程间通讯,ubus通讯的消息格式遵循json格式。

    json(JavaScript object Notation)是一种轻量级的数据交换格式,易于人读写,也易于机器解析和生成。json是一种独立于编程语言之外的文本格式,兼容多种编程语言,如c、c++、Java、JavaScript、php、Python等。
    json格式是{ key:value} 模式,数据类型如下:

    • string
      格式是key:value,value为字符串;
      object是一个name/vale对,格式是{name:value},相当于c语言中的结构体、哈希表等。

    • number
      格式是key:value,value为整数;

    • boolean
      格式是key:value,value为1或者0;

    • object
      object相当于c语言中中的结构体,格式是key:{key1:value1,key2:value2,…},value可以是string、number、boolean、object或者array;

    • array
      array相当于c语言中的数组,格式是key:[value1,value2,…],value可以是string、number、boolean、object或者array。

    2.1 json 脚本语言封装

    OpenWrt 使用shell语言封装对json支持,在console中通过执行 source /usr/share/libubox/jshn.sh 脚本,初始env环境后、就可以调用脚本中封装的接口api,可参考 jshn.sh 分析shell具体封装方法,shell封装 json处理api 接口列表:

    函数描述
    json_init初始化json环境
    json_cleanup清空json环境
    json_add_string添加string类型的element
    json_add_int添加int类型的element
    json_add_boolean添加boolean类型的element
    json_add_table
    json_close_table添加table类型的element
    json_add_array
    json_close_array添加array类型的element
    json_load从字符串中导入到json格式
    json_select进入到某个element,必须有是table或array才能使用json_select
    json_get_keys获取所有element的key
    json_get_values获取所有element的value
    json_get_var根据key获取value
    json_get_type获取element的类型

    具体使用方法实例如下:

    //产生 json 串用例
    root@LEDE:~# source /usr/share/libubox/jshn.sh
    root@LEDE:~# json_init
    root@LEDE:~# json_add_string "str" "Hi, hela!"
    root@LEDE:~# json_add_object "obj"
    root@LEDE:~# json_add_int "num" "100"
    root@LEDE:~# json_add_boolean "bool" "0"
    root@LEDE:~# json_close_object
    root@LEDE:~# json_add_array "array"
    root@LEDE:~# json_add_string "arraystr" "array string"
    root@LEDE:~# json_add_int "" "110"
    root@LEDE:~# json_add_boolean "" "1"
    root@LEDE:~# json_close_array
    root@LEDE:~# MSG=`json_dump`
    root@LEDE:~# echo ${MSG}
    { "str": "Hi, hela!", "obj": { "num": 100, "bool": false }, "array": [ "array string", 110, true ] }
    // 解析 json 串用例
    root@LEDE:~# 
    root@LEDE:~# json_load "$MSG"
    root@LEDE:~# json_get_var varstr str
    root@LEDE:~# json_select obj
    root@LEDE:~# json_get_var varnum num
    root@LEDE:~# json_get_var varbool bool
    root@LEDE:~# json_select ..
    root@LEDE:~# json_select array
    root@LEDE:~# json_get_var array1 "1"
    root@LEDE:~# json_get_var array2 "2"
    root@LEDE:~# json_get_var array3 "3"
    root@LEDE:~# cat << EOF
    > {
    >   msg : $varstr,
    >   obj: {
    >       num : $varnum,
    >       bool : $varbool },
    >   array: [ $array1, $array2, $array3 ]
    > }
    > EOF
    {
      msg : Hi, hela!,
      obj: {
          num : 100,
          bool : 0 },
      array: [ array string, 110, 1 ]
    }
    

    通过环境变量保持参数:

    // 执行 env 查看环境变量
    root@LEDE:~# env
    array2=110
    T_J_A2_1=string
    array3=1
    T_J_A2_2=int
    SSH_CLIENT=192.168.15.214 64657 22
    USER=root
    T_J_A2_3=boolean
    T_J_V_obj=object
    SHLVL=1
    J_T1_num=100
    HOME=/root
    J_V_str=Hi, hela!
    SSH_TTY=/dev/pts/0
    T_J_T1_bool=boolean
    J_V_array=J_A2
    PS1=\[\e]0;\u@\h: \w\a\]\u@\h:\w\$ 
    J_A2_1=array string
    J_A2_2=110
    J_A2_3=1
    LOGNAME=root
    K_J_A2= 1 2 3
    J_V_obj=J_T1
    varnum=100
    TERM=xterm
    J_T1_bool=0
    PATH=/usr/sbin:/usr/bin:/sbin:/bin
    DISPLAY=localhost:10.0
    K_J_V= str obj array
    varstr=Hi, hela!
    SHELL=/bin/ash
    varbool=0
    T_J_T1_num=int
    JSON_CUR=J_A2
    PWD=/root
    K_J_T1= num bool
    T_J_V_str=string
    SSH_CONNECTION=192.168.15.214 64657 192.168.15.1 22
    T_J_V_array=array
    array1=array string
    //再次打印json 串内容
    root@LEDE:~# json_dump
    { "str": "Hi, hela!", "obj": { "num": 100, "bool": false }, "array": [ "array string", 110, true ] }
    //清楚 json 并查看 env 内容
    root@LEDE:~# json_cleanup
    root@LEDE:~# env
    array2=110
    array3=1
    SSH_CLIENT=192.168.15.214 64657 22
    USER=root
    SHLVL=1
    HOME=/root
    SSH_TTY=/dev/pts/0
    PS1=\[\e]0;\u@\h: \w\a\]\u@\h:\w\$ 
    LOGNAME=root
    varnum=100
    TERM=xterm
    PATH=/usr/sbin:/usr/bin:/sbin:/bin
    DISPLAY=localhost:10.0
    varstr=Hi, hela!
    SHELL=/bin/ash
    varbool=0
    PWD=/root
    SSH_CONNECTION=192.168.15.214 64657 192.168.15.1 22
    array1=array string
    
    //再次打印 json 内容
    root@LEDE:~# json_dump
    { }
    
    

    通过上面两个例子,应该对 shell 封装api接口有所了解。

    2.2 C语言封装

    OpenWrt中提供的C语言封装、数据格式采用 blob & blobmsg 形式组成的,blob是一种二进制字节序列,封装形式如下:

    2.2.1 blob_attr 数据格式

    struct blob_attr {
        uint32_t id_len;
        char data[];
    };
    
    

    数据包封装过程如下

    #define BLOB_ATTR_EXTENDED 0x80000000    //blob-attr 扩展标志 1 bit
    #define BLOB_ATTR_ID_MASK  0x7f000000    //blob-id: ID编码 7 bit
    #define BLOB_ATTR_ID_SHIFT 24            //blob-len:数据长度
    #define BLOB_ATTR_LEN_MASK 0x00ffffff    
    #define BLOB_ATTR_ALIGN    4
    
    // 最后 id 和 数据长度函数
    static void
    blob_init(struct blob_attr *attr, int id, unsigned int len)
    {
    	len &= BLOB_ATTR_LEN_MASK;
    	len |= (id << BLOB_ATTR_ID_SHIFT) & BLOB_ATTR_ID_MASK;
    	attr->id_len = cpu_to_be32(len);
    }
    //数据区内容
    void
    blob_fill_pad(struct blob_attr *attr)
    {
    	char *buf = (char *) attr;
    	int len = blob_pad_len(attr);
    	int delta = len - blob_raw_len(attr);
    
    	if (delta > 0)
    		memset(buf + len - delta, 0, delta);
    }
    // 增加一个 blob_attr 元素接口
    static struct blob_attr *
    blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload)
    {
    	int offset = attr_to_offset(buf, pos);
    	int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen;
    	struct blob_attr *attr;
    
    	if (required > 0) {
    		if (!blob_buf_grow(buf, required))
    			return NULL;
    		attr = offset_to_attr(buf, offset);
    	} else {
    		attr = pos;
    	}
    
    	blob_init(attr, id, payload + sizeof(struct blob_attr));
    	blob_fill_pad(attr);
    	return attr;
    }
    

    由程序逻辑可描绘 blob-attr 内存中组成形式如下
    在这里插入图片描述

    • 1.*Data 是数据内容的指针、数据内容长度为 blob-len - (sizeof(struct blob_attr));
    • 2.数据区内容,由专门接口负责申请内存、填充内容。
    • 3.blob是符合TLV格式的,TLV表示Type-Length-Value,上图中,ID即使Type,Len即是Length,Payload即是Value。

    2.2.2 blobmsg 数据格式

    blobmsg是在blob的基础上扩展出来的,数据封装形式如下:

    struct blob_buf {
    	struct blob_attr *head;
    	bool (*grow)(struct blob_buf *buf, int minlen);    //封装的方法
    	int buflen;                                        //增加数据区长度
    	void *buf;                                         //数据区地址指针
    };
    
    
    struct blobmsg_policy {
    	const char *name;
    	enum blobmsg_type type;
    };
    
    enum blobmsg_type {  //blobmsg 数据类型
    	BLOBMSG_TYPE_UNSPEC,
    	BLOBMSG_TYPE_ARRAY,
    	BLOBMSG_TYPE_TABLE,
    	BLOBMSG_TYPE_STRING,
    	BLOBMSG_TYPE_INT64,
    	BLOBMSG_TYPE_INT32,
    	BLOBMSG_TYPE_INT16,
    	BLOBMSG_TYPE_INT8,
    	BLOBMSG_TYPE_DOUBLE,
    	__BLOBMSG_TYPE_LAST,
    	BLOBMSG_TYPE_LAST = __BLOBMSG_TYPE_LAST - 1,
    	BLOBMSG_TYPE_BOOL = BLOBMSG_TYPE_INT8,
    };
    

    blobmsg数据格式封装过程如下:

    struct blobmsg_hdr {
    	uint16_t namelen;
    	uint8_t name[];
    } __packed;
    
    // 增加 blobmsg 数据项的接口api , 以字符串类型为例
    static inline int
    blobmsg_add_string(struct blob_buf *buf, const char *name, const char *string)
    {
    	return blobmsg_add_field(buf, BLOBMSG_TYPE_STRING, name, string, strlen(string) + 1);
    }
    // 函数 blobmsg_add_field 最终调用到 blobmsg_new 函数,此函数为数据格式封装。
    static struct blob_attr *
    blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data)
    {
    	struct blob_attr *attr;
    	struct blobmsg_hdr *hdr;
    	int attrlen, namelen;
    	char *pad_start, *pad_end;
    
    	if (!name)
    		name = "";
    	namelen = strlen(name);
    	attrlen = blobmsg_hdrlen(namelen) + payload_len;
    	attr = blob_new(buf, type, attrlen);      //调用 blob_new 底层接口,BLOBMSG_TYPE_STRING 类型作为 blob_id 的内容。
    	if (!attr)
    		return NULL;
    
    	attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);  //处理blob_ext扩展位 和 数据长度
    	hdr = blob_data(attr);
    	hdr->namelen = cpu_to_be16(namelen);
    
    	memcpy(hdr->name, name, namelen);
    	hdr->name[namelen] = '\0';
    
    	pad_end = *data = blobmsg_data(attr);       // 填充数据区内容
    	pad_start = (char *) &hdr->name[namelen];
    	if (pad_start < pad_end)
    		memset(pad_start, 0, pad_end - pad_start);
    
    	return attr;
    }
    

    blobmsg的string类型数据格式内存结构,如下图:
    在这里插入图片描述

    • 1.保留 blob_attr 基础结构不便
    • 2.blob的数据区中,分为 blobmsg_hdr 、 key 数据 和 value 数据,
    • 3.key 数据 和 value 数据的长度在 blobmsg_hdr 头中Namelen 描述

    blobmsg中扩展标准位extended等于1,payload拆分出key和value两个字段,ID表示blogmsg的梳理类型,类型参考 enum blobmsg_type 定义。

    由此我们基本理解 blobmsg 的数据封装形式,是在 blob_attr 基础上扩展出来,是对 blob_attr 的再次封装,主要提供接口内容如下:

    string
    blobmsg_add_string
    blobmsg_get_string

    int
    blobmsg_add_u8
    blobmsg_add_u16
    blobmsg_add_u32
    blobmsg_add_u64
    blobmsg_get_u8
    blobmsg_get_u16
    blobmsg_get_u32
    blobmsg_get_u64

    bool
    bool转换成u8的0或者1

    table
    blobmsg_open_table
    blobmsg_close_table

    2.2.3 blobmsg 用例

    #include <stdio.h>
    #include <float.h>
    #include <limits.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    #include "blobmsg.h"
    #include "blobmsg_json.h"
    
    static const char *indent_str = "\t\t\t\t\t\t\t\t\t\t\t\t\t";
    
    #define indent_printf(indent, ...) do { \
    	if (indent > 0) \
    		fwrite(indent_str, indent, 1, stderr); \
    	fprintf(stderr, __VA_ARGS__); \
    } while(0)
    
    static void dump_attr_data(struct blob_attr *data, int indent, int next_indent);
    
    static void
    dump_table(struct blob_attr *head, size_t len, int indent, bool array)
    {
    	struct blob_attr *attr;
    	struct blobmsg_hdr *hdr;
    
    	indent_printf(indent, "{\n");
    	__blob_for_each_attr(attr, head, len) {
    		hdr = blob_data(attr);
    		if (!array)
    			indent_printf(indent + 1, "%s : ", hdr->name);
    		dump_attr_data(attr, 0, indent + 1);
    	}
    	indent_printf(indent, "}\n");
    }
    
    static void dump_attr_data(struct blob_attr *data, int indent, int next_indent)
    {
    	int type = blobmsg_type(data);
    	switch(type) {
    	case BLOBMSG_TYPE_STRING:
    		indent_printf(indent, "%s (str)\n", blobmsg_get_string(data));
    		break;
    	case BLOBMSG_TYPE_INT8:
    		indent_printf(indent, "%d (i8)\n", (int8_t) blobmsg_get_u8(data));
    		break;
    	case BLOBMSG_TYPE_INT16:
    		indent_printf(indent, "%d (i16)\n", (int16_t) blobmsg_get_u16(data));
    		break;
    	case BLOBMSG_TYPE_INT32:
    		indent_printf(indent, "%d (i32)\n", (int32_t) blobmsg_get_u32(data));
    		break;
    	case BLOBMSG_TYPE_INT64:
    		indent_printf(indent, "%"PRId64" (i64)\n", (int64_t) blobmsg_get_u64(data));
    		break;
    	case BLOBMSG_TYPE_DOUBLE:
    		indent_printf(indent, "%lf (dbl)\n", blobmsg_get_double(data));
    		break;
    	case BLOBMSG_TYPE_TABLE:
    	case BLOBMSG_TYPE_ARRAY:
    		if (!indent)
    			indent_printf(indent, "\n");
    		dump_table(blobmsg_data(data), blobmsg_data_len(data),
    			   next_indent, type == BLOBMSG_TYPE_ARRAY);
    		break;
    	}
    }
    
    enum {
    	FOO_MESSAGE,
    	FOO_LIST,
    	FOO_TESTDATA
    };
    
    static const struct blobmsg_policy pol[] = {
    	[FOO_MESSAGE] = {
    		.name = "message",
    		.type = BLOBMSG_TYPE_STRING,
    	},
    	[FOO_LIST] = {
    		.name = "list",
    		.type = BLOBMSG_TYPE_ARRAY,
    	},
    	[FOO_TESTDATA] = {
    		.name = "testdata",
    		.type = BLOBMSG_TYPE_TABLE,
    	},
    };
    
    #ifndef ARRAY_SIZE
    #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
    #endif
    
    static void dump_message(struct blob_buf *buf)
    {
    	struct blob_attr *tb[ARRAY_SIZE(pol)];
    
    	if (blobmsg_parse(pol, ARRAY_SIZE(pol), tb, blob_data(buf->head), blob_len(buf->head)) != 0) {
    		fprintf(stderr, "Parse failed\n");
    		return;
    	}
    	if (tb[FOO_MESSAGE])
    		fprintf(stderr, "Message: %s\n", (char *) blobmsg_data(tb[FOO_MESSAGE]));
    
    	if (tb[FOO_LIST]) {
    		fprintf(stderr, "List: ");
    		dump_table(blobmsg_data(tb[FOO_LIST]), blobmsg_data_len(tb[FOO_LIST]), 0, true);
    	}
    	if (tb[FOO_TESTDATA]) {
    		fprintf(stderr, "Testdata: ");
    		dump_table(blobmsg_data(tb[FOO_TESTDATA]), blobmsg_data_len(tb[FOO_TESTDATA]), 0, false);
    	}
    }
    
    static void
    fill_message(struct blob_buf *buf)
    {
    	void *tbl;
    
    	blobmsg_add_string(buf, "message", "Hello, world!");
    
    	tbl = blobmsg_open_table(buf, "testdata");
    	blobmsg_add_double(buf, "dbl-min", DBL_MIN);
    	blobmsg_add_double(buf, "dbl-max", DBL_MAX);
    	blobmsg_add_u8(buf, "foo", 0);
    	blobmsg_add_u8(buf, "poo", 100);
    	blobmsg_add_u8(buf, "moo-min", INT8_MIN);
    	blobmsg_add_u8(buf, "moo-max", INT8_MAX);
    	blobmsg_add_u16(buf, "bar-min", INT16_MIN);
    	blobmsg_add_u16(buf, "bar-max", INT16_MAX);
    	blobmsg_add_u32(buf, "baz-min", INT32_MIN);
    	blobmsg_add_u32(buf, "baz-max", INT32_MAX);
    	blobmsg_add_u64(buf, "taz-min", INT64_MIN);
    	blobmsg_add_u64(buf, "taz-max", INT64_MAX);
    	blobmsg_add_string(buf, "world", "2");
    	blobmsg_close_table(buf, tbl);
    
    	tbl = blobmsg_open_array(buf, "list");
    	blobmsg_add_u8(buf, NULL, 0);
    	blobmsg_add_u8(buf, NULL, 100);
    	blobmsg_add_u8(buf, NULL, INT8_MIN);
    	blobmsg_add_u8(buf, NULL, INT8_MAX);
    	blobmsg_add_u16(buf, NULL, INT16_MIN);
    	blobmsg_add_u16(buf, NULL, INT16_MAX);
    	blobmsg_add_u32(buf, NULL, INT32_MIN);
    	blobmsg_add_u32(buf, NULL, INT32_MAX);
    	blobmsg_add_u64(buf, NULL, INT64_MIN);
    	blobmsg_add_u64(buf, NULL, INT64_MAX);
    	blobmsg_add_double(buf, NULL, DBL_MIN);
    	blobmsg_add_double(buf, NULL, DBL_MAX);
    	blobmsg_close_table(buf, tbl);
    }
    
    int main(int argc, char **argv)
    {
    	char *json = NULL;
    	static struct blob_buf buf;
    
    	blobmsg_buf_init(&buf);
    	fill_message(&buf);
    	fprintf(stderr, "[*] blobmsg dump:\n");
    	dump_message(&buf);
    
    	json = blobmsg_format_json(buf.head, true);
    	if (!json)
    		exit(EXIT_FAILURE);
    
    	fprintf(stderr, "\n[*] blobmsg to json: %s\n", json);
    
    	blobmsg_buf_init(&buf);
    	if (!blobmsg_add_json_from_string(&buf, json))
    		exit(EXIT_FAILURE);
    
    	fprintf(stderr, "\n[*] blobmsg from json:\n");
    	dump_message(&buf);
    
    	if (buf.buf)
    		free(buf.buf);
    	free(json);
    
    	return 0;
    }
    
    
    展开全文
  • ubus实现进程间通信举例

    万次阅读 2017-11-27 15:16:37
     json_list = blobmsg_open_table(&b, NULL);   blobmsg_add_string(&b,  "name" , uri_list[idx].name);   blobmsg_add_u32(&b,  "channel" , uri_list[idx].chn_id);   blobmsg_close_...

    转载自http://blog.csdn.net/jasonchen_gbd/article/details/46055885

    上一篇文章介绍了ubus的组件和实现原理,本文通过代码实例介绍使用ubus进行进程间通信的三种方式。

    1. invoke的方式实现端对端通信

    最简单的情景就是一个提供服务的server端,一个请求服务的client端,client请求server的服务。
    下面的例子中,server注册了一个名为“scan_prog”的对象,该对象中提供一个“scan”方法:
    ubus_invoke.h:
    [cpp]  view plain  copy
    1. #ifndef __UBUS_INVOKE_H__  
    2. #define __UBUS_INVOKE_H__  
    3. #include <json/json.h>  
    4. #include <libubox/blobmsg_json.h>  
    5.   
    6.   
    7. struct prog_attr {  
    8. <span style="white-space:pre">  </span>char name[64];  
    9. <span style="white-space:pre">  </span>int chn_id;  
    10. };  
    11. #define PROG_MAX<span style="white-space:pre">  </span>8  
    12.   
    13.   
    14. #endif  /* __UBUS_INVOKE_H__ */  

    invoke_server.c:

    [cpp]  view plain  copy
    1. #include <libubox/uloop.h>  
    2. #include <libubox/ustream.h>  
    3. #include <libubox/utils.h>  
    4. #include <libubus.h>  
    5. #include <json/json.h>  
    6. #include <libubox/blobmsg_json.h>  
    7. #include "ubus_invoke.h"  
    8.   
    9. static struct ubus_context * ctx = NULL;  
    10. static struct blob_buf b;  
    11. static const char * sock_path;  
    12.   
    13. static struct prog_attr uri_list[PROG_MAX] =   
    14. {  
    15.     {"program_beijing", 1},  
    16.     {"program_guangzhou", 2},  
    17.     {"program_shanghai", 3},  
    18.     {"", -1},  
    19. };  
    20.   
    21. enum  
    22. {  
    23.     SCAN_CHNID,  
    24.     SCAN_POLICY_MAX,  
    25. };  
    26.   
    27. static const struct blobmsg_policy scan_policy[SCAN_POLICY_MAX] = {  
    28.     [SCAN_CHNID] = {.name = "chnID", .type = BLOBMSG_TYPE_INT32},  
    29. };  
    30.   
    31. static int ubus_start_scan(struct ubus_context *ctx, struct ubus_object *obj,  
    32.               struct ubus_request_data *req, const char *method,  
    33.               struct blob_attr *msg)  
    34. {  
    35.     int ret = -1;  
    36.     void * json_list = NULL;  
    37.     void * json_uri = NULL;  
    38.     int idx;  
    39.   
    40.     blob_buf_init(&b, 0);  
    41.       
    42.     struct blob_attr *tb[SCAN_POLICY_MAX];  
    43.     blobmsg_parse(scan_policy, SCAN_POLICY_MAX, tb, blob_data(msg), blob_len(msg));  
    44.   
    45.     /* 
    46.     本例子中,如果请求特定的节目号,返回节目名称。 
    47.     如果请求节目号是0,则返回所有节目列表。 
    48.     */  
    49.     if (tb[SCAN_CHNID] != NULL)  
    50.     {  
    51.         int chnid = blobmsg_get_u32(tb[SCAN_CHNID]);  
    52.   
    53.         if (chnid == 0)  
    54.         {  
    55.             json_uri = blobmsg_open_array(&b, "prog_list");  
    56.             for (idx = 0; idx < PROG_MAX; idx++)  
    57.             {  
    58.                 if ('\0' != uri_list[idx].name[0])  
    59.                 {  
    60.                     json_list = blobmsg_open_table(&b, NULL);  
    61.                     blobmsg_add_string(&b, "name", uri_list[idx].name);  
    62.                     blobmsg_add_u32(&b, "channel", uri_list[idx].chn_id);  
    63.                     blobmsg_close_table(&b, json_list);  
    64.                 }  
    65.             }  
    66.             blobmsg_close_array(&b, json_uri);  
    67.             ret = 0;  
    68.         }  
    69.         else  
    70.         {  
    71.             for (idx = 0; idx < PROG_MAX; idx++)  
    72.             {  
    73.                 if ('\0' != uri_list[idx].name[0] && uri_list[idx].chn_id == chnid)  
    74.                 {  
    75.                     blobmsg_add_string(&b, "name", uri_list[idx].name);  
    76.                     ret = 0;  
    77.                 }  
    78.             }  
    79.         }  
    80.     }  
    81.       
    82.     blobmsg_add_u32(&b, "result", ret);  
    83.     ubus_send_reply(ctx, req, b.head);  
    84.       
    85.     return 0;  
    86. }  
    87.   
    88. /* 方法列表 */  
    89. static struct ubus_method scan_methods[] =   
    90. {  
    91.     UBUS_METHOD("scan", ubus_start_scan, scan_policy),  
    92. };  
    93.   
    94. /* type目前没有实际用处 */  
    95. static struct ubus_object_type scan_obj_type  
    96. = UBUS_OBJECT_TYPE("scan_prog", scan_methods);  
    97.   
    98. static struct ubus_object scan_obj =   
    99. {  
    100.     .name = "scan_prog"/* 对象的名字 */  
    101.     .type = &scan_obj_type,  
    102.     .methods = scan_methods,  
    103.     .n_methods = ARRAY_SIZE(scan_methods),  
    104. };  
    105.   
    106. static void ubus_add_fd(void)  
    107. {  
    108.     ubus_add_uloop(ctx);  
    109.   
    110. #ifdef FD_CLOEXEC  
    111.     fcntl(ctx->sock.fd, F_SETFD,  
    112.         fcntl(ctx->sock.fd, F_GETFD) | FD_CLOEXEC);  
    113. #endif  
    114. }  
    115.   
    116. static void ubus_reconn_timer(struct uloop_timeout *timeout)  
    117. {  
    118.     static struct uloop_timeout retry =  
    119.     {  
    120.         .cb = ubus_reconn_timer,  
    121.     };  
    122.     int t = 2;  
    123.   
    124.     if (ubus_reconnect(ctx, sock_path) != 0) {  
    125.         uloop_timeout_set(&retry, t * 1000);  
    126.         return;  
    127.     }  
    128.   
    129.     ubus_add_fd();  
    130. }  
    131.   
    132. static void ubus_connection_lost(struct ubus_context *ctx)  
    133. {  
    134.     ubus_reconn_timer(NULL);  
    135. }  
    136.   
    137. static int display_ubus_init(const char *path)  
    138. {  
    139.     uloop_init();  
    140.     sock_path = path;  
    141.   
    142.     ctx = ubus_connect(path);  
    143.     if (!ctx)  
    144.     {  
    145.         printf("ubus connect failed\n");  
    146.         return -1;  
    147.     }  
    148.       
    149.     printf("connected as %08x\n", ctx->local_id);  
    150.     ctx->connection_lost = ubus_connection_lost;  
    151.   
    152.     ubus_add_fd();  
    153.   
    154.     /* 向ubusd注册对象和方法,供其他ubus客户端调用。 */  
    155.     if (ubus_add_object(ctx, &scan_obj) != 0)  
    156.     {  
    157.         printf("ubus add obj failed\n");  
    158.         return -1;  
    159.     }  
    160.   
    161.     return 0;  
    162. }  
    163.   
    164. static void display_ubus_done(void)  
    165. {  
    166.     if (ctx)  
    167.         ubus_free(ctx);  
    168. }  
    169.   
    170. int main(int argc, char * argv[])  
    171. {  
    172.     char * path = NULL;  
    173.       
    174.     if (-1 == display_ubus_init(path))  
    175.     {  
    176.         printf("ubus connect failed!\n");  
    177.         return -1;  
    178.     }  
    179.   
    180.     uloop_run();  
    181.   
    182.     display_ubus_done();  
    183.   
    184.     return 0;  
    185. }  
    客户端代码invoke_client.c去调用server端的"scan_prog"对象的"scan"方法:
    [cpp]  view plain  copy
    1. #include <libubox/uloop.h>  
    2. #include <libubox/ustream.h>  
    3. #include <libubox/utils.h>  
    4. #include <libubus.h>  
    5. #include <json/json.h>  
    6. #include <libubox/blobmsg_json.h>  
    7. #include "ubus_invoke.h"  
    8.   
    9. static struct ubus_context * ctx = NULL;  
    10. static struct blob_buf b;  
    11. static const char * cli_path;  
    12.   
    13. enum  
    14. {  
    15.     SCAN_CHNID,  
    16.     SCAN_POLICY_MAX,  
    17. };  
    18.   
    19. static const struct blobmsg_policy scan_policy[SCAN_POLICY_MAX] = {  
    20.     [SCAN_CHNID] = {.name = "chnID", .type = BLOBMSG_TYPE_INT32},  
    21. };  
    22.   
    23. static int timeout = 30;  
    24. static bool simple_output = false;  
    25.   
    26. static void scanreq_prog_cb(struct ubus_request *req, int type, struct blob_attr *msg)  
    27. {  
    28.     char *str;  
    29.     if (!msg)  
    30.         return;  
    31.   
    32.     /*  
    33.     在这里处理返回的消息。 
    34.     本例子只是将返回的消息打印出来。 
    35.     */  
    36.     str = blobmsg_format_json_indent(msg, true, simple_output ? -1 : 0);  
    37.     printf("%s\n", str);  
    38.     free(str);  
    39. }  
    40.   
    41. static int client_ubus_call()  
    42. {  
    43.     unsigned int id;  
    44.     int ret;  
    45.   
    46.     blob_buf_init(&b, 0);  
    47.   
    48.     /* 需要传递的参数 */  
    49.     blobmsg_add_u32(&b, scan_policy[SCAN_CHNID].name, 0);  
    50.   
    51.     /* 
    52.     向ubusd查询是否存在"scan_prog"这个对象, 
    53.     如果存在,返回其id 
    54.     */  
    55.     ret = ubus_lookup_id(ctx, "scan_prog", &id);  
    56.     if (ret != UBUS_STATUS_OK) {  
    57.         printf("lookup scan_prog failed\n");  
    58.         return ret;  
    59.     }  
    60.     else {  
    61.         printf("lookup scan_prog successs\n");  
    62.     }  
    63.       
    64.     /* 调用"scan_prog"对象的"scan"方法 */  
    65.     return ubus_invoke(ctx, id, "scan", b.head, scanreq_prog_cb, NULL, timeout * 1000);  
    66. }  
    67.   
    68. /* 
    69. ubus_invoke()的声明如下: 
    70. int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method, 
    71.                 struct blob_attr *msg, ubus_data_handler_t cb, void *priv, int timeout); 
    72.                  
    73. 其中cb参数是消息回调函数,其函数类型定义为: 
    74. typedef void (*ubus_data_handler_t)(struct ubus_request *req, 
    75.                     int type, struct blob_attr *msg); 
    76. 参数type是请求消息的类型,如UBUS_MSG_INVOKE,UBUS_MSG_DATA等。 
    77.  
    78. 参数msg存放从服务端得到的回复消息,struct blob_attr类型,同样用blobmsg_parse()来解析。 
    79.  
    80. 参数req保存了请求方的消息属性,其中req->priv即ubus_invoke()中的priv参数, 
    81. 用这个参数可以零活的传递一些额外的数据。 
    82. */  
    83.   
    84. static int client_ubus_init(const char *path)  
    85. {  
    86.     uloop_init();  
    87.     cli_path = path;  
    88.   
    89.     ctx = ubus_connect(path);  
    90.     if (!ctx)  
    91.     {  
    92.         printf("ubus connect failed\n");  
    93.         return -1;  
    94.     }  
    95.       
    96.     printf("connected as %08x\n", ctx->local_id);  
    97.   
    98.     return 0;  
    99. }  
    100.   
    101. static void client_ubus_done(void)  
    102. {  
    103.     if (ctx)  
    104.         ubus_free(ctx);  
    105. }  
    106.   
    107. int main(int argc, char * argv[])  
    108. {  
    109.     /* ubusd创建的unix socket,默认值为"/var/run/ubus.sock" */  
    110.     char * path = NULL;  
    111.   
    112.     /* 连接ubusd */  
    113.     if (UBUS_STATUS_OK != client_ubus_init(path))  
    114.     {  
    115.         printf("ubus connect failed!\n");  
    116.         return -1;  
    117.     }  
    118.   
    119.     /* 调用某个ubus方法并处理返回结果 */  
    120.     client_ubus_call();  
    121.   
    122.     client_ubus_done();  
    123.   
    124.     return 0;  
    125. }  
    先执行server程序,再执行client程序,可以看到client发出请求后,server返回了相应的节目号,在client打印出了接收到的消息。
    也可以通过shell命令来请求server的服务,例如:
    ubus call scan_prog scan '{"chnID": 0}'
    这条命令和执行client程序的作用相同。

    2. subscribe/notify的方式实现订阅

    ubus支持以订阅的方式进行进程间通信,通信方式如下图:


    被订阅者(server)又称为notifier,订阅者(client)又称为subscriber。这样一来,可以同时有多个client订阅server的某个服务,当server通过该服务广播消息时,所有client都会被通知,并执行各自的处理。

    主要过程为:

    server进程:

    1. 连接ubusd。
    2. 注册一个object,用于client订阅。
    3. server可以向订阅者广播消息。
    4. 等待消息。

    client进程:

    1. 连接ubusd。
    2. 向server订阅object,并定义收到server的消息时的处理函数。
    3. 等待消息。

    代码示例:下面这个例子中,server注册了一个名为“test”的对象,并定期广播消息。而client去订阅这个对象,并对server发出的消息做处理。

    notify_server.c:

    [cpp]  view plain  copy
    1. #include <unistd.h>  
    2. #include <libubox/blobmsg_json.h>  
    3. #include <libubox/uloop.h>  
    4. #include <libubus.h>  
    5.   
    6. static struct ubus_context *ctx;  
    7.   
    8. static void test_client_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)  
    9. {  
    10.     fprintf(stderr, "Subscribers active: %d\n", obj->has_subscribers);  
    11. }  
    12.   
    13. /* 这个空的method列表,只是为了让object有个名字,这样client可以通过object name来订阅。 */  
    14. static struct ubus_method test_methods[] = {};  
    15.   
    16. static struct ubus_object_type test_obj_type =   
    17.     UBUS_OBJECT_TYPE("test", test_methods);  
    18.   
    19. static struct ubus_object test_object = {  
    20.     .name = "test"/* object的名字 */  
    21.     .type = &test_obj_type,  
    22.     .subscribe_cb = test_client_subscribe_cb,  
    23. };  
    24.   
    25. static void notifier_main(void)  
    26. {  
    27.     int ret;  
    28.   
    29.     /* 注册一个object,client可以订阅这个object */  
    30.     ret = ubus_add_object(ctx, &test_object);  
    31.     if (ret) {  
    32.         fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));  
    33.         return;  
    34.     }  
    35.   
    36.     /* 在需要的时候,向所有客户端发送notify消息 */  
    37.       
    38.     /* step1: 如果需要传递参数,则保存到struct blob_attr类型的结构体中。 */  
    39.   
    40.     /*  
    41.     int ubus_notify(struct ubus_context *ctx, struct ubus_object *obj, const char *type, struct blob_attr *msg, int timeout); 
    42.     type是一个字符串,自定义的。msg是需要携带的参数。如果需要等待回复,timeout需设置为>=0。 
    43.     */  
    44.     while (1) {  
    45.         sleep(2);  
    46.         /* step2: 广播notification消息。 */  
    47.         ubus_notify(ctx,  &test_object, "say Hi!", NULL, -1);  
    48.     }  
    49. }  
    50.   
    51. int main(int argc, char **argv)  
    52. {  
    53.     const char *ubus_socket = NULL;  
    54.   
    55.     uloop_init();  
    56.   
    57.     ctx = ubus_connect(ubus_socket);  
    58.     if (!ctx) {  
    59.         fprintf(stderr, "Failed to connect to ubus\n");  
    60.         return -1;  
    61.     }  
    62.   
    63.     ubus_add_uloop(ctx);  
    64.   
    65.     notifier_main();  
    66.       
    67.     uloop_run();  
    68.   
    69.     ubus_free(ctx);  
    70.     uloop_done();  
    71.   
    72.     return 0;  
    73. }  
    notify_client.c:客户端订阅“test”对象,在收到3次消息后,随即取消对“test”对象的订阅。

    [cpp]  view plain  copy
    1. #include <unistd.h>  
    2. #include <libubox/blobmsg_json.h>  
    3. #include <libubox/uloop.h>  
    4. #include <libubus.h>  
    5.   
    6. static struct ubus_context *ctx;  
    7.   
    8. static int counter = 0;  
    9. static uint32_t obj_id;  
    10. static struct ubus_subscriber test_event;  
    11.   
    12. static int test_notify(struct ubus_context *ctx, struct ubus_object *obj,  
    13.                   struct ubus_request_data *req,  
    14.                   const char *method, struct blob_attr *msg)  
    15. {  
    16.     printf("notify handler...\n");  
    17.     counter++;  
    18.     if (counter > 3)  
    19.         ubus_unsubscribe(ctx, &test_event, obj_id); /* 取消订阅 */  
    20.     return 0;  
    21. }  
    22.   
    23. static void test_handle_remove(struct ubus_context *ctx,  
    24.                       struct ubus_subscriber *obj, uint32_t id)  
    25. {  
    26.     printf("remove handler...\n");  
    27. }  
    28.   
    29. static void subscriber_main(void)  
    30. {  
    31.     int ret;  
    32.       
    33.     /* 通知到来时的处理函数。 */  
    34.     test_event.cb = test_notify;  
    35.     test_event.remove_cb = test_handle_remove; //server主动发起删除该client的订阅的cb函数(如server退出的时候)  
    36.   
    37.     /* 注册test_event */  
    38.     ret = ubus_register_subscriber(ctx, &test_event);  
    39.     if (ret)  
    40.         fprintf(stderr, "Failed to add watch handler: %s\n", ubus_strerror(ret));  
    41.       
    42.     /* 得到要订阅的object的id */  
    43.     ret = ubus_lookup_id(ctx, "test", &obj_id);  
    44.     if (ret)  
    45.         fprintf(stderr, "Failed to lookup object: %s\n", ubus_strerror(ret));  
    46.   
    47.     /* 订阅object */  
    48.     ret = ubus_subscribe(ctx, &test_event, obj_id);  
    49.     if (ret)  
    50.         fprintf(stderr, "Failed to subscribe: %s\n", ubus_strerror(ret));  
    51. }  
    52.   
    53. int main(int argc, char **argv)  
    54. {  
    55.     const char *ubus_socket = NULL;  
    56.   
    57.     uloop_init();  
    58.   
    59.     ctx = ubus_connect(ubus_socket);  
    60.     if (!ctx) {  
    61.         fprintf(stderr, "Failed to connect to ubus\n");  
    62.         return -1;  
    63.     }  
    64.   
    65.     ubus_add_uloop(ctx);  
    66.   
    67.     subscriber_main();  
    68.       
    69.     uloop_run();  
    70.   
    71.     ubus_free(ctx);  
    72.     uloop_done();  
    73.   
    74.     return 0;  
    75. }  
    先运行server&,注册可订阅的对象“test”,并随即每2秒向外广播通知消息。这时还没有client订阅这个对象。
    运行多个client程序,由于每个client都订阅了“test”对象,则所有client都会收到server发出的消息。当client取消订阅后,则不再收到server端的消息。

    event的方式实现事件通知

    event机制从一对一的进程之间通信来讲,和invoke机制类似。不过event机制中,发送方不需要知道谁要接收这个消息,实际上就是一个广播消息。这类似于U盘的热插拔:当插上或拔出U盘时,内核会广播一个NETLINK事件,之后内核继续做自己的事情,而不关心谁会去监听和处理这个事件。

    下面的例子中,client端同时监听了“add_device”和“rm_device”两个事件,而server端会触发“add_device”事件并携带device的一些信息发送出去。

    event_client.c:

    [cpp]  view plain  copy
    1. #include <libubox/uloop.h>  
    2. #include <libubox/ustream.h>  
    3. #include <libubox/utils.h>  
    4. #include <libubus.h>  
    5. #include <json/json.h>  
    6. #include <libubox/blobmsg_json.h>  
    7.   
    8. static struct ubus_context * ctx = NULL;  
    9. static const char * cli_path;  
    10.   
    11. #define UBUS_EVENT_ADD_DEVICE   "add_device"  
    12. #define UBUS_EVENT_REMOVE_DEVICE    "rm_device"  
    13.   
    14. static void ubus_probe_device_event(struct ubus_context *ctx, struct ubus_event_handler *ev,  
    15.               const char *type, struct blob_attr *msg)  
    16. {  
    17.     char *str;  
    18.   
    19.     if (!msg)  
    20.         return;  
    21.   
    22.     /*  
    23.     在这里实现收到事件后的动作。 
    24.     event也可以传递消息,放在msg中。 
    25.      
    26.     本例子只是将返回的消息打印出来。 
    27.     */  
    28.     str = blobmsg_format_json(msg, true);  
    29.     printf("{ \"%s\": %s }\n", type, str);  
    30.     free(str);  
    31. }  
    32.   
    33. static int client_ubus_register_events()  
    34. {  
    35.     static struct ubus_event_handler listener;  
    36.     int ret = 0;  
    37.   
    38.     /* 注册特定event的listener。多个event可以使用同一个listener */  
    39.     memset(&listener, 0, sizeof(listener));  
    40.     listener.cb = ubus_probe_device_event;  
    41.       
    42.     ret = ubus_register_event_handler(ctx, &listener, UBUS_EVENT_ADD_DEVICE);  
    43.     if (ret)  
    44.     {  
    45.         fprintf(stderr, "register event failed.\n");  
    46.         return -1;  
    47.     }  
    48.   
    49.     ret = ubus_register_event_handler(ctx, &listener, UBUS_EVENT_REMOVE_DEVICE);  
    50.     if (ret)  
    51.     {  
    52.         ubus_unregister_event_handler(ctx, &listener);  
    53.         fprintf(stderr, "register event failed.\n");  
    54.         return -1;  
    55.     }  
    56.   
    57.     return 0;  
    58. }  
    59.   
    60. static void ubus_add_fd(void)  
    61. {  
    62.     ubus_add_uloop(ctx);  
    63.   
    64. #ifdef FD_CLOEXEC  
    65.     fcntl(ctx->sock.fd, F_SETFD,  
    66.         fcntl(ctx->sock.fd, F_GETFD) | FD_CLOEXEC);  
    67. #endif  
    68. }  
    69.   
    70. static void ubus_reconn_timer(struct uloop_timeout *timeout)  
    71. {  
    72.     static struct uloop_timeout retry =  
    73.     {  
    74.         .cb = ubus_reconn_timer,  
    75.     };  
    76.     int t = 2;  
    77.   
    78.     if (ubus_reconnect(ctx, cli_path) != 0) {  
    79.         uloop_timeout_set(&retry, t * 1000);  
    80.         return;  
    81.     }  
    82.   
    83.     ubus_add_fd();  
    84. }  
    85.   
    86. static void ubus_connection_lost(struct ubus_context *ctx)  
    87. {  
    88.     ubus_reconn_timer(NULL);  
    89. }  
    90.   
    91. static int client_ubus_init(const char *path)  
    92. {  
    93.     uloop_init();  
    94.     cli_path = path;  
    95.       
    96.     ctx = ubus_connect(path);  
    97.     if (!ctx)  
    98.     {  
    99.         printf("ubus connect failed\n");  
    100.         return -1;  
    101.     }  
    102.       
    103.     printf("connected as %08x\n", ctx->local_id);  
    104.     ctx->connection_lost = ubus_connection_lost;  
    105.   
    106.     ubus_add_fd();  
    107.   
    108.     return 0;  
    109. }  
    110.   
    111. static void client_ubus_done(void)  
    112. {  
    113.     if (ctx)  
    114.         ubus_free(ctx);  
    115. }  
    116.   
    117. int main(int argc, char * argv[])  
    118. {  
    119.     char * path = NULL;  
    120.   
    121.     /* 连接ubusd */  
    122.     if (UBUS_STATUS_OK != client_ubus_init(path))  
    123.     {  
    124.         printf("ubus connect failed!\n");  
    125.         return -1;  
    126.     }  
    127.   
    128.     /* 注册某个事件的处理函数 */  
    129.     client_ubus_register_events();  
    130.   
    131.     uloop_run();  
    132.       
    133.     client_ubus_done();  
    134.   
    135.     return 0;  
    136. }  
    event_server.c:

    [cpp]  view plain  copy
    1. #include <libubox/uloop.h>  
    2. #include <libubox/ustream.h>  
    3. #include <libubox/utils.h>  
    4. #include <libubus.h>  
    5. #include <json/json.h>  
    6. #include <libubox/blobmsg_json.h>  
    7.   
    8. static struct ubus_context * ctx = NULL;  
    9. static struct blob_buf b;  
    10. static const char * sock_path;  
    11.   
    12. static int server_ubus_send_event(void)  
    13. {  
    14.     blob_buf_init(&b, 0);  
    15.   
    16.     /* 需要传递的参数 */  
    17.     blobmsg_add_u32(&b, "major", 3);  
    18.     blobmsg_add_u32(&b, "minor", 56);  
    19.     blobmsg_add_string(&b, "name""mmc01");  
    20.   
    21.     /* 广播名为"add_device"的事件 */  
    22.     return ubus_send_event(ctx, "add_device", b.head);  
    23. }  
    24.   
    25. static int display_ubus_init(const char *path)  
    26. {  
    27.     uloop_init();  
    28.     sock_path = path;  
    29.   
    30.     ctx = ubus_connect(path);  
    31.     if (!ctx)  
    32.     {  
    33.         printf("ubus connect failed\n");  
    34.         return -1;  
    35.     }  
    36.       
    37.     printf("connected as %08x\n", ctx->local_id);  
    38.   
    39.     return 0;  
    40. }  
    41.   
    42. static void display_ubus_done(void)  
    43. {  
    44.     if (ctx)  
    45.         ubus_free(ctx);  
    46. }  
    47.   
    48. int main(int argc, char * argv[])  
    49. {  
    50.     char * path = NULL;  
    51.       
    52.     if (-1 == display_ubus_init(path))  
    53.     {  
    54.         printf("ubus connect failed!\n");  
    55.         return -1;  
    56.     }  
    57.   
    58.     server_ubus_send_event();  
    59.   
    60.     display_ubus_done();  
    61.   
    62.     return 0;  
    63. }  
    先运行client &注册事件。我们同时启动两个client程序。
    再执行server主动触发"add_device"事件,则凡是注册了这个事件的client都会收到该事件并执行各自的处理。
    [plain]  view plain  copy
    1. root@NVR:~# ./server  
    2. connected as fdecbdc1  
    3. { "add_device": { "major": 3, "minor": 56, "name": "mmc01" } }  
    4. { "add_device": { "major": 3, "minor": 56, "name": "mmc01" } }  
    也可以通过命令行的ubus send命令触发事件:
    [plain]  view plain  copy
    1. root@NVR:~# ubus send "rm_device" '{ "major": 3, "minor": 56, "name": "mmc01" }'  
    2. { "rm_device": { "major": 3, "minor": 56, "name": "mmc01" } }  
    3. { "rm_device": { "major": 3, "minor": 56, "name": "mmc01" } }  

    在使用ubus时,可根据实际的场景来选择用哪种方式进行进程间通信。如之前所说,ubus是为发送消息而设计的,不合适传输大量数据。

    展开全文
  • Openwrt ubus: 进程间通信的例子

    千次阅读 2019-05-28 11:19:37
    1. ubusd守护进程: 管理ubus服务端和客户端的注册,并作为服务端和客户端的中间人, 进行消息转发, 所有消息均封装成json格式。向ubus服务端传递ubus客户端的请求(call),向ubus客户端传递ubus服务端的执行结果。 2....

    ubus是Openwrt实现进程间通信的一种总线机制,  由三部分协作完成通信过程:ubusd守护进程,ubus服务端,ubus客户端。

    1. ubusd守护进程: 管理ubus服务端和客户端的注册,并作为服务端和客户端的中间人, 进行消息转发, 所有消息均封装成json格式。向ubus服务端传递ubus客户端的请求(call),向ubus客户端传递ubus服务端的执行结果。

    2. ubus服务端(ubus server object):  提供软件各种具体功能模块的实现(methods), 服务端的对象名称和具体的mothd名称向ubusd进行注册后,就可以被其他ubus客户端进行传呼(call) 。

    3. ubus客户端(ubus client object):  是具体功能(method)的传呼方(caller), 其通用ubusd向某个ubus服务端呼叫请求(call)执行指定method。

    4. 实际上,一个ubus object对象,即可以作为服务端提供各种方法(method),也可以作为客户端来传呼(call)其他对象的方法。

    5. 下面是具体的实现例子:

    ubus_server.c:     向ubusd注册了一个名为"ering_uobj"的对象 ,  提供一个名称为"ering_method“的方法, 这个方法的实现依靠3个名称为"id","data","msg"的参数。 为了简单实现这个例子, 程序只将收到的这3个参数打印出来, 完成后向客户端传送一条确认消息。方法请求是通过回调函数来实现的,程序本身不会退出。

    /*------------------------ ubus_server.c -----------------------------
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
    published by the Free Software Foundation.
    
    An example for Openwrt UBUST communication.
    
    Midas Zhou
    ---------------------------------------------------------------------*/
    #include <stdio.h>
    #include <stdint.h>
    #include <libubus.h>
    
    static struct ubus_context *ctx;
    static struct ubus_request_data req_data;
    static struct blob_buf	bb;
    
    static int ering_handler( struct ubus_context *ctx, struct ubus_object *obj,
    			  struct ubus_request_data *req, const char *method,
    			  struct blob_attr *msg );
    
    /* Enum for EGI policy order */
    enum {
    	ERING_ID,
    	ERING_DATA,
    	ERING_MSG,
    	__ERING_MAX,
    };
    
    /* Ubus Policy */
    static const struct blobmsg_policy ering_policy[] =
    {
    	[ERING_ID]  = { .name="id", .type=BLOBMSG_TYPE_INT32},
    	[ERING_DATA] = { .name="data", .type=BLOBMSG_TYPE_INT32 },
    	[ERING_MSG] = { .name="msg", .type=BLOBMSG_TYPE_STRING },
    };
    
    /* Ubus Methods */
    static const struct ubus_method ering_methods[] =
    {
    	UBUS_METHOD("ering_method", ering_handler, ering_policy),
    };
    
    /* Ubus object type */
    static struct ubus_object_type ering_obj_type =
    	UBUS_OBJECT_TYPE("ering_uobj", ering_methods);
    
    /* Ubus object */
    static struct ubus_object ering_obj=
    {
    	.name = "ering.host", 	/* with APP name */
    	.type = &ering_obj_type,
    	.methods = ering_methods,
    	.n_methods = ARRAY_SIZE(ering_methods),
    	//.path= /* useless */
    };
    
    
    void main(void)
    {
    	int ret;
    	const char *ubus_socket=NULL; /* use default UNIX sock path: /var/run/ubus.sock */
    
    	/* 1. create an epoll instatnce descriptor poll_fd */
    	uloop_init();
    
    	/* 2. connect to ubusd and get ctx */
    	ctx=ubus_connect(ubus_socket);
    	if(ctx==NULL) {
    		printf("Fail to connect to ubusd!\n");
    		return;
    	}
    
    	/* 3. registger epoll events to uloop, start sock listening */
    	ubus_add_uloop(ctx);
    
    	/* 4. register a usb_object to ubusd */
    	ret=ubus_add_object(ctx, &ering_obj);
    	if(ret!=0) {
    		printf("Fail to register an object to ubus.\n");
    		goto UBUS_FAIL;
    
    	} else {
    		printf("Add '%s' to ubus @%u successfully.\n", ering_obj.name, ering_obj.id);
    	}
    
    	/* 5. uloop routine: events monitoring and callback provoking */
    	uloop_run();
    
    
    	uloop_done();
    UBUS_FAIL:
    	ubus_free(ctx);
    }
    
    
    /*---------------------------------------------
    A callback function for ubus methods handling
    ----------------------------------------------*/
    static int ering_handler( struct ubus_context *ctx, struct ubus_object *obj,
    			  struct ubus_request_data *req, const char *method,
    			  struct blob_attr *msg )
    {
    	struct blob_attr *tb[__ERING_MAX]; /* for parsed attr */
    
    	/* Parse blob_msg from the caller to request policy */
    	blobmsg_parse(ering_policy, ARRAY_SIZE(ering_policy), tb, blob_data(msg), blob_len(msg));
    
    	/* print request msg */
    	printf("Receive msg from caller: ");
    	if(tb[ERING_ID])
    	     printf("UBUS_ID=%u  ", blobmsg_get_u32(tb[ERING_ID]));
    	if(tb[ERING_DATA])
    	     printf("DATA=%u  ", blobmsg_get_u32(tb[ERING_DATA]));
    	if(tb[ERING_MSG])
    	     printf("MSG='%s' \n", blobmsg_data(tb[ERING_MSG]));
    
    	/* Do some job here according to caller's request */
    
    	/* send a reply msg to the caller for information */
    	blob_buf_init(&bb, 0);
    	blobmsg_add_string(&bb,"Ering reply", "Request is being proceeded!");
    	ubus_send_reply(ctx, req, bb.head);
    
    	/* 	-----  reply results to the caller -----
    	 * NOTE: we may put proceeding job in a timeout task, just to speed up service response.
    	 */
    	ubus_defer_request(ctx, req, &req_data);
    	ubus_complete_deferred_request(ctx, req, UBUS_STATUS_OK);
    }
    

    ubus_client.c:       向ubusd注册了一个名为"ering_caller" 的对象, 没有注册任何method。它向"ering_uobj"对象传呼(call)了"ering_method"方法,  在接收到服务端反馈的消息后将它打印出来,然后退出程序。

    /*-------------------------  ubus_client.c  ------------------------
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as
    published by the Free Software Foundation.
    
    An example for Openwrt UBUS communication.
    
    Midas Zhou
    ------------------------------------------------------------------*/
    #include <stdio.h>
    #include <libubus.h>
    #include <libubox/blobmsg_json.h>
    
    static struct ubus_context *ctx;
    static struct blob_buf	bb;
    
    static void result_handler(struct ubus_request *req, int type, struct blob_attr *msg);
    
    /* ubus object assignment */
    static struct ubus_object ering_obj=
    {
    	.name = "ering_caller",
    	#if 0
    	.type = &ering_obj_type,
    	.methods = ering_methods,
    	.n_methods = ARRAY_SIZE(ering_methods),
    	.path= /* useless */
    	#endif
    };
    
    
    void main(void)
    {
    	int ret;
    	uint32_t host_id; /* ering host id */
    	const char *ubus_socket=NULL; /* use default UNIX sock path: /var/run/ubus.sock */
    
    	/* 1. create an epoll instatnce descriptor poll_fd */
    	uloop_init();
    
    	/* 2. connect to ubusd and get ctx */
    	ctx=ubus_connect(ubus_socket);
    	if(ctx==NULL) {
    		printf("Fail to connect to ubusd!\n");
    		return;
    	}
    
    	/* 3. registger epoll events to uloop, start sock listening */
    	ubus_add_uloop(ctx);
    
    	/* 4. register a usb_object to ubusd */
    	ret=ubus_add_object(ctx, &ering_obj);
    	if(ret!=0) {
    		printf("Fail to register an object to ubus.\n");
    		goto UBUS_FAIL;
    
    	} else {
    		printf("Add '%s' to ubus @%u successfully.\n",ering_obj.name, ering_obj.id);
    	}
    
    	/* 5. search a registered object with a given name */
    	if( ubus_lookup_id(ctx, "ering.host", &host_id) ) {
    		printf("ering.host is NOT found in ubus!\n");
    		goto UBUS_FAIL;
    	}
    	printf("ering.host is found in ubus @%u.\n",host_id);
    
    	/* 6. prepare request method policy and data */
    	blob_buf_init(&bb,0);
    	blobmsg_add_u32(&bb,"id", ering_obj.id); 	/* ERING_ID */
    	blobmsg_add_u32(&bb,"data", 123456); 		/* ERING_DATA */
    	blobmsg_add_string(&bb,"msg", "Hello, ERING!"); /* ERING_DATA */
    
    	/* 7. call the ubus host object */
    	ret=ubus_invoke(ctx, host_id, "ering_method", bb.head, result_handler, 0, 3000);
    	printf("Call result: %s\n", ubus_strerror(ret));
    
    	/* 8. uloop routine: events monitoring and callback provoking
    	      However, we just ignore uloop in this example.
    	 */
    	 //uloop_run();
    
    	uloop_done();
    UBUS_FAIL:
    	ubus_free(ctx);
    }
    
    /* callback function for ubus_invoke to process result from the host
     * Here we just print out the message.
     */
    static void result_handler(struct ubus_request *req, int type, struct blob_attr *msg)
    {
            char *strmsg;
    
            if(!msg)
                    return;
    
            strmsg=blobmsg_format_json_indent(msg,true, 0); /* 0 type of format */
            printf("Response from the host: %s\n", strmsg);
            free(strmsg); /* need to free strmsg */
    }
    

    6.  本例子在openwrt  widora环境下编译通过, Makefile 如下, Makefile环境变量请根据自己实际情况修改:

    export STAGING_DIR=/home/midas-zhou/openwrt_widora/staging_dir
    COMMON_USRDIR=/home/midas-zhou/openwrt_widora/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/
    CC= $(STAGING_DIR)/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mipsel-openwrt-linux-gcc
    
    CFLAGS  += -I$(COMMON_USRDIR)/include
    LDFLAGS += -L$(COMMON_USRDIR)/lib
    LIBS   += -lubus -lubox -lblobmsg_json -ljson_script -ljson-c
    
    all:	 ubus_server ubus_client
    
    ubus_server:   ubus_server.c
    	$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) ubus_server.c -o ubus_server 
    
    ubus_client:   ubus_client.c
    	$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) ubus_client.c -o ubus_client
    
    clean:
    	rm -rf *.o ubus_server ubus_client

    7.  试着将ubus封装成EGI RING模块, 以方便程序调用。具体代码见  https://github.com/widora/ctest/tree/master/wegi/ering

    展开全文
  • str = blobmsg_format_json_indent(msg, true, simple_output ? -1 : 0); printf("%s\n", str); free(str); } static int client_ubus_call() { unsigned int id; int ret; blob_buf_init(&b, 0); /* ...
  • ubus

    2017-05-01 11:39:00
    ubus能够以json格式和用户进行数据交换。常见场景(应用详见 ubus实现进程间通信举例 ): 1)客户端/服务器模式。 2)订阅通知模式(struct ubus_subscriber)。 3)事件模式(ubus_event_handler)。 ...
  • UBUS代码例程以及分析

    千次阅读 2020-03-18 16:45:34
    /** 定义set方法参数列表 */ static const struct blobmsg_policy obj_set_attrs[__OBJ_SET_ATTR_MAX] = { [OBJ_SET_ARG1] = { .name = "arg1", .type = BLOBMSG_TYPE_STRING }, [OBJ_SET_ARG2 ] = { .name = "arg2...
  • ubus实现进程间通信

    千次阅读 2017-12-02 10:45:52
    #include <libubox/blobmsg_json.h>       struct  prog_attr {   style= "white-space:pre" >  char  name[64];   style= "white-space:pre" >  int  chn_id;  };  #define PROG_MAX style=...
  • */ jsonstr = blobmsg_format_json_indent(msg, true, simple_output ? -1 : 0); //用完记得free(jsonstr); } int client_ubus_call(char *object, char *method) { unsigned int id; int ret; blob_buf_init(&b, 0...

空空如也

空空如也

1
收藏数 12
精华内容 4
关键字:

blobmsg_format_json_indent