1. 程式人生 > >ubus客戶端向伺服器請求資訊的例子

ubus客戶端向伺服器請求資訊的例子

openwrt使用者空間進中通訊常用的通訊方式是使用ubus通訊,下面給出一個例子,是客戶端向伺服器請求ap的個數。

伺服器端程式碼

#include <unistd.h>
#include <signal.h>

#include "libubus.h"

static struct ubus_context *ctx;
static struct blob_buf b;

enum {
	REQ_STATION_COUNT,
	REQ_AP_NAME,
	__REQ_MAX
};

/* 接收的解析格式, client傳送過來的呼叫是 blobmsg_add_u32(&b, "getcnt", ap_index); */
static const struct blobmsg_policy fun2_message_parse_policy[__REQ_MAX] = {
	[REQ_STATION_COUNT] = { .name = "getcnt", .type = BLOBMSG_TYPE_INT32 },
	[REQ_STATION_COUNT] = { .name = "apname", .type = BLOBMSG_TYPE_STRING },
};

static int fun2_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[__REQ_MAX];
	//模擬ap陣列中station的個數
	int ap_array[] = {-1, 11111,22222,33333};
	int ap_index;

	blobmsg_parse(fun2_message_parse_policy, __REQ_MAX, tb, blob_data(msg), blob_len(msg));
	if (!tb[REQ_STATION_COUNT])
		return UBUS_STATUS_INVALID_ARGUMENT;
		
	ap_index = blobmsg_get_u32(tb[REQ_STATION_COUNT]);
	
	fprintf(stdout, "someone ask the ap[%d]' info \n", ap_index);
	
	if (ap_index > (sizeof(ap_array) / sizeof(int)))
		ap_index = 0;
		
	
	blob_buf_init(&b, 0);
	//返回客戶端請求的station個數
	blobmsg_add_u32(&b, "stacnt", ap_array[ap_index]);
	//傳送
	ubus_send_reply(ctx, req, b.head);
	
	return 0;
}


static const struct ubus_method test_methods[] = {
	UBUS_METHOD("fun2", fun2_handler, fun2_message_parse_policy),
};

static struct ubus_object_type test_object_type =
	UBUS_OBJECT_TYPE("server_fun", test_methods);

	//定義一個ubus 物件。
	//其他程序通過呼叫相應字串給執行對應的回撥函式
	//註冊成功後可以通過命令ubus list -v 檢視到obj
	//' server_fun' @79a8beac
	// 		"fun2" : {"getcnt":"Iterger","apname":"String"}
static struct ubus_object test_object = {
	.name = "server_fun",
	.type = &test_object_type,
	.methods = test_methods,
	.n_methods = ARRAY_SIZE(test_methods),
};

static void server_main(void)
{
	int ret;

	//向ubusd新增一個物件,之後test_object在ubusd中有一個id號,其他程序通過該id號來向test_object傳送訊息。
	ret = ubus_add_object(ctx, &test_object);
	if (ret)
		fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));

	uloop_run();
}

int main(int argc, char **argv)
{
	const char *ubus_socket = NULL;
	int ch;

	while ((ch = getopt(argc, argv, "cs:")) != -1) {
		switch (ch) {
		case 's':
			ubus_socket = optarg;
			break;
		default:
			break;
		}
	}

	argc -= optind;
	argv += optind;

	uloop_init();
	signal(SIGPIPE, SIG_IGN);

	ctx = ubus_connect(ubus_socket);
	if (!ctx) {
		fprintf(stderr, "Failed to connect to ubus\n");
		return -1;
	}

	ubus_add_uloop(ctx);

	server_main();

	ubus_free(ctx);
	uloop_done();

	return 0;
}


客戶端程式碼

#include <sys/time.h>
#include <unistd.h>

#include "libubus.h"

static struct ubus_context *ctx;
static struct blob_buf b;

enum {
	RETURN_CODE,
	__RETURN_MAX,
};

static const struct blobmsg_policy return_policy[__RETURN_MAX] = {
	[RETURN_CODE] = { .name = "stacnt", .type = BLOBMSG_TYPE_INT32 },
};

static void get_result_data_cb(struct ubus_request *req,
				    int type, struct blob_attr *msg)
{
	struct blob_attr *tb[__RETURN_MAX];
	int rc;
	
	//返回的資料也是有tlv格式的,按照return_policy格式進行解析。
	blobmsg_parse(return_policy, __RETURN_MAX, tb, blob_data(msg), blob_len(msg));
	if (!tb[RETURN_CODE]) {
		fprintf(stderr, "No return code received from server\n");
		return;
	}

	rc = blobmsg_get_u32(tb[RETURN_CODE]);

	fprintf(stderr, "get station number is %d \n", rc);
}

static void client_main(void)
{
	static struct ubus_request req;
	uint32_t id;
	int ret;
	int ap_index=2;

	//查詢ubusd上的server_fun物件。該物件由server端註冊
	if (ubus_lookup_id(ctx, "server_fun", &id)) {
		fprintf(stderr, "Failed to look up test object\n");
		return;
	}

	//b 為全域性變數,初始化
	blob_buf_init(&b, 0);
	
	//添加發送buffer的tlv,格式由server_main.c的fun2_message_parse_policy定義
	blobmsg_add_u32(&b, "getcnt", ap_index);
	
	//觸發server端註冊的函式,並接收返回值,處理函式為get_result_data_cb
	ubus_invoke(ctx, id, "fun2", b.head, get_result_data_cb, NULL, 3000);
}

int main(int argc, char **argv)
{
	const char *ubus_socket = NULL;
	int ch;

	while ((ch = getopt(argc, argv, "cs:")) != -1) {
		switch (ch) {
		case 's':
			ubus_socket = optarg;
			break;
		default:
			break;
		}
	}

	argc -= optind;
	argv += optind;

	uloop_init();

	ctx = ubus_connect(ubus_socket);
	if (!ctx) {
		fprintf(stderr, "Failed to connect to ubus\n");
		return -1;
	}

	ubus_add_uloop(ctx);

	client_main();

	ubus_free(ctx);
	uloop_done();

	return 0;
}


以上程式碼:伺服器端向ubusd註冊了個server_fun的伺服器物件,客戶端通過server_fun ubus物件與伺服器端通訊。

其他:ubus shell呼叫格式

ubus send linkinspect '{"ac_cmd":1}'