昇腾社区首页
中文
注册

服务端

基本原理

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

图1 服务端创建和响应流程
  • 服务必须全局唯一,不可重复不可同名。
  • 由于涉及共享内存文件读写,服务端进程和客户端进程的用户权限必须相同,否则可能通信失败。
  • 一个服务端只起一个线程,回调处理是串行的,不同服务的回调处理是并行的。
  • 对于同一个服务,客户端和服务端的入参serviceName、reqDataSize、resDataSize、blockNum等必须完全一致。
  • 服务端处理太慢可能会导致客户端call超时。
  1. 资源初始化。

    用户在调用OpenHiva接口之前,需要先调用OpenHiva::Init接口进行初始化,返回值为0代表初始化成功,否则失败。

  2. 创建服务端。
    1. 构造服务端对象(ServiceServer)之前,必须先注册节点,即创建节点句柄OpenHiva::Node n。
    2. 通过调用OpenHiva::ServiceOptions里BuildShmOptions设置服务端的属性值,例如示例代码中的请求数据大小(reqDataSize)、响应数据大小(resDataSize)、数据缓存量(blockNum)。注意,这些属性值均不能为0,消息大小msgSize=reqDataSize或resDataSize+消息头(64字节),单个消息大小msgSize不能超过30M,blockNum*msgSize需小于300M。
    3. 使用创建的节点句柄n调用CreateServer接口创建ServiceServer对象,设置要访问的服务名称(serviceName)并初始化处理客户端请求的回调函数。
  3. 使能服务端。

    创建OpenHiva::ServiceServer对象后,服务端还不能正常工作,需要调用OpenHiva::ServiceServer::Enable接口使能服务端。当接口返回值为0时,表示使能成功,否则使能失败。

    当服务端未使能或使能失败时,客户端调用的OpenHiva::ServiceClient::InvokeService接口(发送请求)会发生超时失败。

  4. 接收请求并响应。

    服务端使能成功后,可以接收客户端发送的请求(req),然后调用事先注册的回调函数进行处理,并将响应写回客户端的入参res中。注意,回调函数必须判断长度,不可越界。

  5. 资源释放。

    进程结束前,依次释放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;
}