1@page uservice uservice 2 3[更正文档](https://gitee.com/alios-things/uservice/edit/master/README.md)      [贡献说明](https://help.aliyun.com/document_detail/302301.html) 4 5# 概述 6 7uService (微服务) 是一种支持RPC请求/应用的交互,并支持状态消息发布的一种服务机制,客户端可以通过发送请求消息并待回复的方式调用uService(微服务)提供的服务,也可以通过订阅服务的事件,来处理服务的事件状态。 8 9serviceTask (服务任务)是利用操作系统的多任务系统,实现消息的分发机制,一个 serviceTask中创建一个OS 的Task。一个serviceTask 下可以注册多个微服务,同一个服务任务下的所有微服务的消息采用先进先处理的顺序执行。 10 11# 接口定义 12 13## RPC 14 15```c 16typedef struct _rpc_t { 17 uservice_t *srv; 18 uint32_t cmd_id; 19 rpc_buffer_t *data; 20} rpc_t; 21``` 22 23* cmd_id: RPC 序号 24* data: 存RPC相关参数的buffer 25 26## RPC 初始化 27 28```c 29int rpc_init(rpc_t *rpc, int cmd_id, int timeout_ms); 30``` 31 32初始化 RPC,设置 RPC 的命令号(cmd_id), 命令调用的超时时间(timeout_ms),单位毫秒 33 34* 参数: 35 * rpc: rpc 36 * cmd_id: RPC 的命令号 37 * timeout_ms: 命令调用等待超时时间,0时为异步调用,调用者立即返回,等于 AOS_WAIT_FOREVER为同步调用,等到服务端命令执行完,当 timeout_ms 大于0时,为超时调用,调用者指定的时间内等待服务端返回,如果服务器未返回,则超时退出 38* 返回值: 39 * 0: 成功 40 * -ENOMEM: 内存不足 41 * -EINVAL: 无效参数 42 43## RPC 写参数复位 44 45```c 46void rpc_put_reset(rpc_t *rpc); 47``` 48 49清空 rpc 内部的参数。rpc 参数是调用者向服务端传递输入参数,也是服务端向调用者反回参数。编写服务端程序时,在处理完成 rpc 的参数,需要向调用者返回值时,通过调用该函数,清空参数区,然后通过 rpc_put_xxx 函数向 rpc 写入返回值。 50 51## RPC 写入参数 52 53```c 54int rpc_put_int(rpc_t *rpc, int v); 55int rpc_put_uint8(rpc_t *rpc, uint8_t v); 56int rpc_put_double(rpc_t *rpc, double v); 57int rpc_put_point(rpc_t *rpc, const void *v); 58int rpc_put_buffer(rpc_t *rpc, const void *data, size_t size); 59int rpc_put_string(rpc_t *rpc, char *str); 60``` 61 62向 rpc 参数区写入参数, rpc 的参数可以写入多个参数,根据写入的顺序存放。参数区可以写入 int、uint8_t、double、point、string、array 类型的数据。 63 64* 返回值: 65 * 0: 成功 66 * -ENOMEM: 内存不足 67 68## RPC 参数读取复位 69 70```c 71void rpc_get_reset(rpc_t *rpc); 72``` 73 74RPC 参数区读取位复。rpc 参数区的参数通管 rpc_get_xxx 一组函数读取,每调用一次读取函数则取出一个参数,序号递增,如果需要从头重新读取参数,则通过 rpc_get_reset 函数,将参数序号移到起始位置。 75 76## RPC 参数读取 77 78```c 79int rpc_get_int(rpc_t *rpc); 80uint8_t rpc_get_uint8(rpc_t *rpc); 81double rpc_get_double(rpc_t *rpc); 82char *rpc_get_string(rpc_t *rpc); 83void *rpc_get_point(rpc_t *rpc); 84void *rpc_get_buffer(rpc_t *rpc, int *count); 85``` 86 87从参数区读取参数,在参数读取时,要调用与写入时的参数顺序一致,参数区的参数是顺序读取,每调用一次 rpc_get_xxx 函数,则依次读出一个参数。参数读取类型不一致时,会导致异常。 88返回参数值。 89 90## RPC 应答 91 92```c 93void rpc_reply(rpc_t *rpc); 94``` 95 96该函数在编写服务端时调用,当服务端处理完一条 rpc 时,必须调用该函数完成 rpc 的任务处理。 97 98 99## RPC 回收 100 101```c 102void rpc_deinit(rpc_t *rpc); 103``` 104 105该函数在调用端执行,当调用者使用 uservice_call 函数调用 rpc时,在处理完 rpc 返回值后,需要调用 rpc_deinit 函数回收 rpc 资源。 106 107# 微服务 (uService) 108 109## 创建微服务 110 111```c 112uservice_t *uservice_new(const char *name, process_t process_rpc, void *context); 113``` 114 115根据指定的微服务名称,上下文、最大命令ID,创建微服务,创建成功返回 uservice_t 指针,失败返回NULL 116 117* 参数: 118 * name: 服务名字 119 * process_rpc: 服务远程调用处理函数 120 * context: 服务自定义上下文,用户在编写微服务处理函数时,可使用该上下文 121* 返回值: 122 创建成功返回 uservice_t 指针,失败返回NULL 123 124## 释放微服务 125 126```c 127void uservice_destroy(uservice_t *srv); 128``` 129 130释放微服务 srv 所占用所有资源,释放srv 之前,需要确定 众uservice_task 中移出 uService 131 132## 微服务 rpc 处理函数 133 134```c 135typedef int (*process_t)(void *context, rpc_t *rpc); 136``` 137 138微服务的远程调用(RPC) 的主处理函数,在微服务开发时,尽可能减少 process_rpc 的处理时间。 139 140 * context: 创建微服务时传入的 context 141 * rpc:远程序调用对象 142 143 144## 同步调用微服务命令 145 146```c 147int uservice_call_sync(uservice_t *srv, int cmd, void *param, void *resp, size_t resp_size); 148``` 149 150向微服务发送一条同步执行命令 151 152* 参数: 153 * srv: 微服务 154 * cmd:指定需要执行的命令号 155 * param: 命令的参数 156 * resp:命令的返回值 157 * resp_size: 命令返回值空间大小 158* 返回值: 159 调用成功,返回0,否则返回 -1 160 161## 异步调用微服务命令 162```c 163int uservice_call_async(uservice_t *srv, int cmd, void *param, size_t param_size); 164``` 165 166向微服务发送一条异步执行命令 167 168* 参数: 169 * srv: 微服务 170 * cmd:指定需要执行的命令号 171 * param: 命令的参数 172 * param_size: 命令参数空间大小 173* 返回值: 174 调用成功,返回0,否则返回 -1 175 176## 自定义调用微服务命令 177 178```c 179int uservice_call(uservice_t *srv, rpc_t *rpc); 180``` 181 182使用自定义 rpc 实现微服务的命令调用,该命令可以通过 rpc_t 实现同步、异步、超时调用,也可以用 rpc_put_xxx 函数,向 rpc 中传入多个参数。服务器也可以通过 rpc 返回多个数据,可以实现复杂参数传输调用。 183 184* 参数: 185 * srv: 微服务 186 * rpc: 调用的 RPC 指令 187* 返回值: 188 调用成功,返回0,否则返回 -1 189 190## 微服务锁操作 191 192```c 193void uservice_lock(uservice_t *srv); 194void uservice_unlock(uservice_t *srv); 195``` 196 197## 微服务事件订阅 198 199```c 200void uservice_subscribe(uservice_t *srv, uint32_t event_id); 201``` 202 203该函数用于微服务中,调用该函数订阅事件,并将事件发送到微服务的 RPC 任务队列中, 204RPC 的 cmd_id 等于 event_id,通过 rpc_get_pointer 可以获取 事件的 data 参数。 205 206```c 207 208struct demo_service { 209 uservice_t *srv; 210} demo_svr; 211 212static void process_rpc(void *context, rpc_t *rpc) 213{ 214 switch (rpc->cmd_id) { 215 case EVENT_NETMGR_GOT_IP: { 216 /* EVENT_NETMGR_GOT_IP 事件处理 */ 217 void *data = rpc_get_pointer(rpc); 218 if (data != NULL) { 219 // TODO: 220 } 221 ... 222 break; 223 } 224 ... 225 } 226 227 rpc_reply(rpc); 228} 229 230void demo_service_init() 231{ 232 /* 创建一个微服务 */ 233 demo_svr.srv = uservice_new("demo", process_rpc, NULL); 234 /* 订阅微服务事件 “EVENT_NETMGR_GOT_IP”*/ 235 uservice_subscribe(demo_svr.srv, EVENT_NETMGR_GOT_IP); 236} 237 238``` 239 240# 事件 241 242YoC 中,支持全局事件,已定义的事件在 include/uservice/eventid.h 文件中。事件有两种,一种是普通事件,事件的 event_id 由用户定义,由于事件的ID是全局唯一,用户自定义事件时,不能与系统事件冲突。一种是设备(网络)句柄数据可读事件,当设备有数据可读时,会触发 fd 事件。 243 244## 事件订阅 245 246```c 247void event_subscribe(uint32_t event_id, event_callback_t cb, void *context); 248void event_subscribe_fd(uint32_t fd, event_callback_t cb, void *context); 249``` 250 251```c 252typedef void (*event_callback_t)(uint32_t event_id, const void *data, void *context); 253``` 254 255event_subscribe 订阅普通事件,event_subscribe_fd 订阅设备(网络)句柄数据可读事件 256 257* 参数: 258 * event_id: 事件号, event_subscribe_fd 函数,fd 为设备/网络句柄。 259 * cb: 事件处理函数,该参数不能为 NULL,否则会触发异常 260 * context: 用户数据,该数据会传入到 cb 的 context 参数中 261* 返回值: 262 无 263 264## 事件订阅取消 265 266```c 267void event_unsubscribe(uint32_t event_id, event_callback_t cb, void *context); 268void event_unsubscribe_fd(uint32_t fd, event_callback_t cb, void *context); 269``` 270 271取消事件订阅,取消事件订阅时,要求传入的参数与订阅时的参数一致方可取消 272 273* 参数: 274 * event_id: 事件号, event_subscribe_fd 函数,fd 为设备/网络句柄。 275 * cb: 事件处理函数,该参数不能为 NULL,否则会触发异常 276 * context: 用户数据,该数据会传入到 cb 的 context 参数中 277* 返回值: 278 无 279 280## 事件发布 281 282```c 283void event_publish(uint32_t event_id, void *data); 284void event_publish_fd(uint32_t fd, void *data, int sync); 285``` 286 287发布事件 288 289* 参数: 290 * event_id: 事件号, event_publish_fd 函数,fd 为设备/网络句柄。 291 * data: 事件附带数据,该数据会传到订阅者的回调函数参数 data中,由于事件是异步处理,使用者要小心使用 data 的作用域,订阅者能正常访问该数据 292 * sync: 同步标志,1:同步 0:异步 293* 返回值: 294 无 295 296# 微服务任务 (uTask) 297 298## 创建微服务任务 299 300```c 301utask_t *utask_new(const char *name, size_t stack_size, int queue_length, int prio); 302``` 303 304- 参数: 305 306 - name: utask名 307 - stack_size:栈大小 308 - queue_length:队列个数 309 - prio:优先级 310 311- 返回值: 312 313 非NULL:成功 NULL:失败 314 315## 释放微服务任务 316 317```c 318void utask_destroy(utask_t *task); 319``` 320 321## 向微服务任务中添加(删除)微服务 322 323```c 324void utask_add(utask_t *task, uservice_t *srv); 325``` 326 327```c 328void utask_remove(utask_t *task, uservice_t *srv); 329``` 330 331## 等待微服务任务退出并收回占用资源 332 333```c 334void utask_join(utask_t *task); 335``` 336 337# 示例代码 338 339## 服务接口及事件定义 340 341```c 342#ifndef DEMO_SERVICE_H 343#define DEMO_SERVICE_H 344 345#define EVENT_A 0x1000 346#define EVENT_B 0x1001 347#define EVENT_C 0x1002 348 349int demo_add(int a, int b); 350 351#endif 352``` 353 354## 服务实现 355 356```c 357#include <uservice/uservice.h> 358 359struct demo_uservice { 360 uservice_t *srv; 361 int a, b, c; 362 rpc_t *current_cmd; 363 rpc_t *current_oob; 364}; 365 366/* cmd 列表 */ 367enum DEMO_CMD { 368 CMD_1 = 0, 369 CMD_2 = 1, 370 CMD_RECV, 371 372 CMD_DATA = 10, 373 CMD_MAX 374}; 375/* 事件ID */ 376#define EVENT_A 0x1000 377#define EVENT_B 0x1001 378#define EVENT_C 0x1002 379 380struct cmd_param { 381 int a, b, c; 382}; 383 384/* 微服务处理函数*/ 385static int process_rpc(void *context, rpc_t *rpc) 386{ 387 struct demo_uservice *d = (struct demo_uservice *)context; 388 389 if (rpc->cmd_id < CMD_DATA) { 390 d->current_cmd = rpc; 391 } 392 393 switch (rpc->cmd_id) { 394 case CMD_RECV: 395 // d->current_cmd = rpc; 396 break; 397 398 case CMD_1: { 399 /* 加法cmd 处理 */ 400 struct cmd_param *p = (struct cmd_param *)rpc_get_point(rpc); 401 402 d->c = p->a + p->b; 403 404 /* 发布 EVENT_A 事件 */ 405 event_publish(EVENT_A, (void *)d->c); 406 break; 407 } 408 409 case CMD_DATA: 410 if (d->current_cmd != NULL) { 411 rpc_reply(d->current_cmd); 412 d->current_cmd = NULL; 413 event_publish(EVENT_A, (void *)d->c); 414 } 415 /* rpc应答 */ 416 rpc_reply(rpc); 417 break; 418 419 default: 420 /* rpc应答 */ 421 rpc_reply(rpc); 422 break; 423 } 424 425 return 0; 426} 427 428static struct demo_uservice demo; 429void demo_service_init() 430{ 431 static utask_t *srv; 432 /* 创建微服务 */ 433 srv = utask_new("demo_srv", 2 * 1024, QUEUE_MSG_COUNT, AOS_DEFAULT_APP_PRI); 434 /* 创建utask */ 435 demo.srv = uservice_new("demo", process_rpc, &demo); 436 437 /* 将微服务加入到utask中 */ 438 utask_add(srv, demo.srv); 439} 440 441void demo_add(int a, int b) 442{ 443 struct cmd_param cmd; 444 cmd.a = a; 445 cmd.b = b; 446 int c; 447 448 /* 微服务同步调用 CMD_1 */ 449 uservice_call_sync(demo.srv, CMD_1, &cmd, &c, sizeof(int)); 450} 451``` 452 453## 服务调用 454 455```c 456int demo_subscribe(uint16_t event_id, event_callback_t cb, void *context) 457{ 458 return uservice_subscribe(demo.srv, event_id, cb, context); 459} 460 461static void event_a_callback(uint16_t event_id, const void *data, void *context) 462{ 463 printf("%d\n", (int)data); 464} 465 466void demo_test() 467{ 468 demo_service_init(); 469 demo_subscribe(EVENT_A, event_a_callback, NULL); 470 demo_add(1, 4); 471} 472``` 473