服务端
基本原理
服务端(OpenHiva::ServiceServer)创建和处理消息的关键流程如图1所示。

- 服务必须全局唯一,不可重复不可同名。
- 由于涉及共享内存文件读写,服务端进程和客户端进程的用户权限必须相同,否则可能通信失败。
- 一个服务端只起一个线程,回调处理是串行的,不同服务的回调处理是并行的。
- 对于同一个服务,客户端和服务端的入参serviceName、reqDataSize、resDataSize、blockNum等必须完全一致。
- 服务端处理太慢可能会导致客户端call超时。
- 资源初始化。
用户在调用OpenHiva接口之前,需要先调用OpenHiva::Init接口进行初始化,返回值为0代表初始化成功,否则失败。
- 创建服务端。
- 构造服务端对象(ServiceServer)之前,必须先注册节点,即创建节点句柄OpenHiva::Node n。
- 通过调用OpenHiva::ServiceOptions里BuildShmOptions设置服务端的属性值,例如示例代码中的请求数据大小(reqDataSize)、响应数据大小(resDataSize)、数据缓存量(blockNum)。注意,这些属性值均不能为0,消息大小msgSize=reqDataSize或resDataSize+消息头(64字节),单个消息大小msgSize不能超过30M,blockNum*msgSize需小于300M。
- 使用创建的节点句柄n调用CreateServer接口创建ServiceServer对象,设置要访问的服务名称(serviceName)并初始化处理客户端请求的回调函数。
- 使能服务端。
创建OpenHiva::ServiceServer对象后,服务端还不能正常工作,需要调用OpenHiva::ServiceServer::Enable接口使能服务端。当接口返回值为0时,表示使能成功,否则使能失败。
当服务端未使能或使能失败时,客户端调用的OpenHiva::ServiceClient::InvokeService接口(发送请求)会发生超时失败。
- 接收请求并响应。
服务端使能成功后,可以接收客户端发送的请求(req),然后调用事先注册的回调函数进行处理,并将响应写回客户端的入参res中。注意,回调函数必须判断长度,不可越界。
- 资源释放。
进程结束前,依次释放ServiceServer对象和OpenHiva资源。资源释放后,定义的OpenHiva接口将无法使用。
示例代码
服务端创建和响应请求的关键步骤代码示例如下,仅供参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
#include <iostream> #include <string> #include <memory> #include <unistd.h> #include "open/init.h" #include "open/node.h" #include "open/service_server.h" #include "open/service_options.h" #include "std_msgs/include/StringMessage.h" static constexpr uint32_t MAX_NAME_SIZE = 100; static constexpr uint32_t DEFAULT_SLEEP_TIME_IN_CALLBACK = 10; // 单位ms uint32_t g_cbSleep = DEFAULT_SLEEP_TIME_IN_CALLBACK; int cnt = 0; void Usage() { std::cout << "Usage: pmupload test_create_server nodeName topicName groupName bindType reqSize resSize blockNum enableOrDisable" << std::endl; std::cout << "if argc==2, server will use default value: pmupload test_create_server testNodeServer testService testGroupServer 0 100 100 10 0" << std::endl; std::cout << "bindType can be 0 1 2" << std::endl; std::cout << "Pointing: req/res size must bigger than messageSize + 8, or serialize will fail" << std::endl; } // 用户根据自身业务逻辑,定义回调函数用于处理request消息 bool ResCb(Hiva::StdMsgs::StringMessage &reqBuf, Hiva::StdMsgs::StringMessage &resBuf) { HIVA_INFO("callback req %s.", reqBuf.stringData.c_str()); std::string key = "sssss"; resBuf.stringData = reqBuf.stringData + key; HIVA_WARN("cb_sleep=%u ms", g_cbSleep); usleep(g_cbSleep * 1000); return true; } int main(int argc, char **argv) { // 1. 资源初始化 std::string nodeName = "testNodeServer"; std::string groupName = "testGroupServer"; std::string serviceName = "testService"; OpenHiva::ScheduleType scheType = OpenHiva::ScheduleType(0); int32_t reqDataSize = 100; int32_t resDataSize = 100; int32_t blockNum = 10; bool enableOrDisable = false; int argNum = 9; if (argc < argNum) { Usage(); if (argc != 2) { return 0; } } else { nodeName = argv[1]; serviceName = argv[2]; groupName = argv[3]; scheType = (OpenHiva::ScheduleType)strtol(argv[4], NULL, 10); reqDataSize = (int32_t)strtol(argv[5], NULL, 10); resDataSize = (int32_t)strtol(argv[6], NULL, 10); blockNum = (int32_t)strtol(argv[7], NULL, 10); enableOrDisable = (bool)strtol(argv[8], NULL, 10); } // 定义线程组 std::vector<OpenHiva::ScheduleGroup> scheGrpVec; OpenHiva::ScheduleGroup scheGrp; scheGrp.groupName = groupName; scheGrp.scheduleType = scheType; scheGrpVec.push_back(scheGrp); // 调用资源初始化接口 OpenHiva::Init(argc, argv, scheGrpVec); HIVA_EVENT("service server init ok!"); HIVA_INFO("reqDataSize=%d.", reqDataSize); HIVA_INFO("resDataSize=%d.", resDataSize); HIVA_INFO("blockNum=%d.", blockNum); // 2. 创建服务端 // 构造Node对象 OpenHiva::Node node(nodeName); // 构造ServiceOptions OpenHiva::ServiceOptions serOps; serOps.BuildShmOptions(reqDataSize, resDataSize, blockNum); // 通过NodeHandle对象调用CreateServer接口创建ServiceServer对象 std::function<bool(Hiva::StdMsgs::StringMessage&, Hiva::StdMsgs::StringMessage&)> callback = ResCb; std::shared_ptr<OpenHiva::ServiceServer> server = node.CreateServer(serviceName, serOps, callback); // 当构造ServiceServer对象失败时,调用Shutdown函数释放资源并退出 if (server == nullptr) { HIVA_ERROR("create server failed"); OpenHiva::Shutdown(); return 0; } // 3. 使能服务端,接收request消息并response auto ret = server->Enable(); bool enableFlag = true; // 当使能失败时,主调用Shutdown函数释放资源并退出 if (ret != Hiva::HIVA_SUCCESS) { HIVA_ERROR("enable server failed"); OpenHiva::Shutdown(); return 0; } // 判断Hiva节点状态。当节点是使能状态,返回true;当节点是shutdown或初始化失败状态,返回false,收发包均不能正确进行 while (OpenHiva::Ready()) { if (enableOrDisable) { if (cnt % 10 == 5) { if (enableFlag) { server->Disable(); enableFlag = false; HIVA_EVENT("service server disable"); } else { server->Enable(); enableFlag = true; HIVA_EVENT("service server enable"); } } } cnt++; sleep(1); } // 4. 资源释放 server->Disable(); server->Destroy(); OpenHiva::Shutdown(); return 0; } |
父主题: 消息请求-响应