sogou / srpc

RPC framework based on C++ Workflow. Supports SRPC, Baidu bRPC, Tencent tRPC, thrift protocols.
Apache License 2.0
1.93k stars 382 forks source link

关于一个server有多个service,不能正常访问 #394

Open longyn opened 2 months ago

longyn commented 2 months ago

1. DeviceStatus

service TDeviceStatus
{
  bool isRunning();
}

2. TPingService

service TPingService
{
  /** ping  */
  void ping();
}

3. Server

#include <string>
#include <memory>
#include <cstdio>
#include <signal.h>
#include <workflow/WFFacilities.h>
#include "TPingService.srpc.h"
#include "TDeviceStatus.srpc.h"

static WFFacilities::WaitGroup wait_group(1);

static void sig_handler(int signo) {
  wait_group.done();
}

class PingServiceImpl : public TPingService::Service {
private:
  static int mCallCount;

public:
  virtual void ping() {
    printf("ping %d\n", ++mCallCount);
  }
};

int PingServiceImpl::mCallCount = 0;

class DeviceStatusImpl : public TDeviceStatus::Service {
public:
  virtual bool isRunning() {
    printf("is running = true\n");
    return true;
  }
};

class PingAccess {
private:
  int mPort;

public:
  PingAccess()
      : mPort(9090) {
  }

  bool start() {
    signal(SIGINT, sig_handler);
    signal(SIGTERM, sig_handler);

    srpc::ThriftServer server;
    PingServiceImpl    pingservice_impl;
    server.add_service(&pingservice_impl);

    DeviceStatusImpl devicestatus_impl;
    server.add_service(&devicestatus_impl);

    if (server.start(mPort) == 0) {
      printf("server start 0.0.0.0:%s ...\n", mPort);
      wait_group.wait();
      server.stop();
    } else {
      printf("error server start\n");
    }

    return true;
  }
};

int main(int argc, char const *argv[]) {
  PingAccess ping;
  ping.start();
  return 0;
}

Client

#include <string>
#include <memory>
#include <cstdio>

#include "TPingService.srpc.h"
#include "TDeviceStatus.srpc.h"

class PingAccess {
private:
  std::shared_ptr<TPingService::ThriftClient> mspTclient;
  std::shared_ptr<TDeviceStatus::ThriftClient> mspDeviceClient;
  std::string                                              mIp;
  int                                                      mPort;

public:
  PingAccess()
      : mIp("127.0.0.1")
      , mPort(9090) {
  }

  bool start() {
    mspTclient = std::make_shared<TPingService::ThriftClient>(mIp.c_str(), mPort);
    mspDeviceClient = std::make_shared<TDeviceStatus::ThriftClient>(mIp.c_str(), mPort);

    {
      mspTclient->ping();
      if (mspTclient->thrift_last_sync_success()) {
        printf("TService::ping => OK\n");
      } else {
        auto const &sync_ctx = mspTclient->thrift_last_sync_ctx();
        printf("TService::ping => error: %s\n", sync_ctx.errmsg);
      }

      mspDeviceClient->isRunning();
      if (mspDeviceClient->thrift_last_sync_success()) {
        printf("Status::isRunning=> OK\n");
      } else {
        auto const &sync_ctx = mspDeviceClient->thrift_last_sync_ctx();
        printf("Status::isRunning=> error: %s\n", sync_ctx.errmsg);
      }
    }

    return true;
  }
};

int main(int argc, char const *argv[]) {
  PingAccess ping;
  ping.start();
  return 0;
}

5. Client输出结果

TService::ping => OK
Status::isRunning=> error: TApplicationException: Wrong method name

我查看文档 docs-03-server.md中,有如下描述: - 每一个Server可以拥有任意的Service,但在当前Server里ServiceName必须唯一, 已确认当ServiceName唯一,分别为"TPingService"和"TDeviceStatus"

如果只分别启动一个服务,都可以正常访问,同时启动2个服务,只能访问最前面一个服务的接口,请问下是那里没有使用正确吗?

Barenboim commented 2 months ago

你好。我们docs-03-server里的service,还不是thrift里的service。主要是在展示可以把thrift和protobuf两种不同的IDL生成的serivce,放到同一个server里,而不是支持thrift的多service。不支持的原因是,thrift的framed协议根本不支持多service,而我们主要只支持framed。

不过!我们的srpc::SRPCServer(非srpc::ThriftServer),是可以放入thrift idl生成的service的,这个在通讯中使用的并非thrift framed协议。你可以试一下用这个能不能支持(参考docs-03-server里的写法)。

Barenboim commented 2 months ago

我试过了,你这个代码里,把ThriftServer替换成SRPCServer,把TriftClient替换成SRPCClient(包括TPingService::SRPCClient和TDeviceStatus::SRPCClient),在SRPCServer里,加入两个service,是可以正常用的。通信协议是SRPC协议。

Barenboim commented 2 months ago

Server

#include <string>
#include <memory>
#include <cstdio>
#include <signal.h>
#include <workflow/WFFacilities.h>
#include "TPingService.srpc.h"
#include "TDeviceStatus.srpc.h"

static WFFacilities::WaitGroup wait_group(1);

static void sig_handler(int signo) {
  wait_group.done();
}

class PingServiceImpl : public TPingService::Service {
private:
  static int mCallCount;

public:
  virtual void ping() {
    printf("ping %d\n", ++mCallCount);
  }
};

int PingServiceImpl::mCallCount = 0;

class DeviceStatusImpl : public TDeviceStatus::Service {
public:
  virtual bool isRunning() {
    printf("is running = true\n");
    return true;
  }
};

class PingAccess {
private:
  int mPort;

public:
  PingAccess()
      : mPort(9090) {
  }

  bool start() {
    signal(SIGINT, sig_handler);
    signal(SIGTERM, sig_handler);

    srpc::SRPCServer server;
    PingServiceImpl    pingservice_impl;
    server.add_service(&pingservice_impl);

    DeviceStatusImpl devicestatus_impl;
    server.add_service(&devicestatus_impl);

    if (server.start(mPort) == 0) {
      printf("server start 0.0.0.0:%d ...\n", mPort);
      wait_group.wait();
      server.stop();
    } else {
      printf("error server start\n");
    }

    return true;
  }
};

int main(int argc, char const *argv[]) {
  PingAccess ping;
  ping.start();
  return 0;
}

Client

#include <string>
#include <memory>
#include <cstdio>

#include "TPingService.srpc.h"
#include "TDeviceStatus.srpc.h"

class PingAccess {
private:
  std::shared_ptr<TPingService::SRPCClient> mspTclient;
  std::shared_ptr<TDeviceStatus::SRPCClient> mspDeviceClient;
  std::string                                              mIp;
  int                                                      mPort;

public:
  PingAccess()
      : mIp("127.0.0.1")
      , mPort(9090) {
  }

  bool start() {
    mspTclient = std::make_shared<TPingService::SRPCClient>(mIp.c_str(), mPort);
    mspDeviceClient = std::make_shared<TDeviceStatus::SRPCClient>(mIp.c_str(), mPort);

    {
      mspTclient->ping();
      if (mspTclient->thrift_last_sync_success()) {
        printf("TService::ping => OK\n");
      } else {
        auto const &sync_ctx = mspTclient->thrift_last_sync_ctx();
        printf("TService::ping => error: %s\n", sync_ctx.errmsg.c_str());
      }

      mspDeviceClient->isRunning();
      if (mspDeviceClient->thrift_last_sync_success()) {
        printf("Status::isRunning=> OK\n");
      } else {
        auto const &sync_ctx = mspDeviceClient->thrift_last_sync_ctx();
        printf("Status::isRunning=> error: %s\n", sync_ctx.errmsg.c_str());
      }
    }

    return true;
  }
};

int main(int argc, char const *argv[]) {
  PingAccess ping;
  ping.start();
  return 0;
}

用这个代码,就可以跑了。试一下。

longyn commented 2 months ago

好的,谢谢,明白了

Barenboim commented 2 months ago

你那边的需求是什么?是只要用thrift IDL就可以,还是想和原生thrift服务器通信。

---原始邮件--- 发件人: "Frank @.> 发送时间: 2024年6月26日(周三) 晚上6:52 收件人: @.>; 抄送: @.**@.>; 主题: Re: [sogou/srpc] 关于一个server有多个service,不能正常访问 (Issue #394)

好的,谢谢,明白了

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

longyn commented 2 months ago

现在服务端的代码用的是muplexed protocol实现的,多路复用一个端口,一个server有多个服务,因为涉及到多种客户端,想考虑一下怎么在最小的代价下能够迁移到srpc。 所以首先还是想跟原生的thrift服务器通信。

Barenboim commented 2 months ago

嗯嗯,因为thrift本身就不是一种协议,出现新的功能需求从来不考虑协议兼容性,如果multiplexed protocol兼容一下framed,我们直接支持这个协议就可以了。

所以我们只能选一种最常用的协议来实现,也就是framed。理论上如果愿意改代码,我们也可以增加一种ThriftMultiplexedServer和Client来支持multiplexed protocol的通信,不影响现在的service书写。

你可以认为SRPCServer+thrift IDL是一种我们私有的thrift通讯协议,可以解决多service问题。

longyn commented 2 months ago

嗯好的,我先研究下,怎么加上ThriftMuplexedServer,这种应该修改代价比较小 使用SRPCServer + thrift IDL做为一个备选方案

Barenboim commented 2 months ago

关于thrift消息的解析,可以看这个地方: https://github.com/sogou/srpc/blob/226a0c32f56d171aa8e952271ac7f65fdf1cca53/src/message/rpc_message_thrift.cc#L24 这里解析了framed格式的thrift消息。

如果要支持multiplexed,需要再搞一套消息出来。其实也不难,SRPC里可以随意增加新的RPC通讯协议,甚至可以增加新的IDL格式。