如何用 C 语言编写 gRPC 客户端/服务器?

问题描述 投票:0回答:3

我有一个用 C 编写的程序,想在其中包含 gRPC。然而,gRPC 的 API 是用 C++ 编写的。

我查看了这里并让 foo_client 和 foo_server 正常工作。 https://github.com/Juniper/grpc-c/tree/master/examples

但是,C 客户端与我的 gRPC C++ 服务器不兼容。他们不会互相交谈。我相信这是因为我使用的是最新的 gRPC,它使用 protocbuf 版本 3.2.0。 Juniper 的 grpc-c 使用的是旧版本的 gRPC,该版本使用 protocbuf 版本 3.0.0。

因此,C 语言的 Juniper 版本似乎不适用于新的 gRPC。我知道 gRPC 低级 C API 应该在这里:https://github.com/grpc/grpc/blob/master/include/grpc/grpc.h 但我在实施它时遇到了困难。谁能帮我理解一下吗?

我有一段时间没有用 C 编程了,所以我有点生疏了。

c grpc
3个回答
5
投票

如果您直接使用 gRPC 核心库,那么您将需要执行自己的序列化,并处理https://github.com/grpc/grpc/blob/master/include/grpc/ 中记录的低级操作impl/codegen/grpc_types.h.

如果您有任何具体问题,我们很乐意为您提供帮助,但如果这只是一次性的事情,那么解决版本不兼容问题可能会更容易,或者简单地用 C 接口包装 C++ 实现。


0
投票

有几种方法可以解决这个问题:

  1. 从 C 代码调用 gRPC 的 CPP 函数:为此,请创建一个 C API 来公开 C++ 代码的功能。编写标有 extern "C" 的 C++ 函数,并设计封装 C++ 库的纯 C API。更多详细信息请参见:如何从 C 调用 C++ 函数? 以及此处:混合 C 和 Cpp
  2. 使用 C 语言的非官方 gRPC 库:我在几个不同的地方看到过 juniper-grpc-c (Github) 提到。
  3. 使用 HTTP/2 C 库:gRPC 构建在 HTTP2 之上,因此使用像 https://nghttp2.org/ 这样的库,您可以为 gRPC 提供 C 绑定。
  4. 使用 Apache Thrift:Thrift 是一个轻量级、独立于语言的软件堆栈,用于具有 C 客户端的点对点 RPC 实现。如果可以选择替换 gRPC,您可以尝试一下。

0
投票

有一个用 C 编写的

EZgRPC
服务器,但有一些限制,例如:

  1. SSL(当前)尚未实施。
  2. 服务器(当前)不支持流消息。
  3. 客户端 EZgRPC 未实现。只有服务器。
  4. 当使用其他消息格式(如protobuf)时,用户将不得不处理grpc消息的序列化。不过,如果他们喜欢生吃,这是可能的。
  5. 仅适用于基于 Linux 的操作系统。

摘自

hello_world_server.c

/* the author disclaims copyright to this example source code
 * and releases it into the public domain
 */

#include "ezgrpc.h"

int whatever_service1(ezgrpc_message_t *req, ezgrpc_message_t **res, void *userdata){
  ezgrpc_message_t *msg = calloc(1, sizeof(ezgrpc_message_t));
  printf("called service1. received %u bytes\n", req->data_len);

  msg->is_compressed = 0;
  msg->data_len = 3;
  msg->data = malloc(3);
  /* protobuf serialized message */
  msg->data[0] = 0x08;
  msg->data[1] = 0x96;
  msg->data[2] = 0x02;
  msg->next = NULL;

  *res = msg;
  //sleep(2);
  return 0;
}

int another_service2(ezgrpc_message_t *req, ezgrpc_message_t **res, void *userdata){
  printf("called service2\n");
  return 0;
}

int main(){

  int pfd[2];
  if (pipe(pfd))
    assert(0);
  
  sigset_t sig_mask;
  ezhandler_arg ezarg = {&sig_mask, pfd[1]};
  if (ezgrpc_init(ezserver_signal_handler, &ezarg)) {
    fprintf(stderr, "fatal: couldn't init ezgrpc\n");
    return 1;
  }

  EZGRPCServer *server_handle = ezgrpc_server_init();
  assert(server_handle != NULL);

  ezgrpc_server_add_service(server_handle, "/test.yourAPI/whatever_service1", whatever_service1, NULL, NULL, 0);
  ezgrpc_server_add_service(server_handle, "/test.yourAPI/another_service2", another_service2, NULL, NULL, 0);

  ezgrpc_server_set_ipv4_bind_addr(server_handle, "0.0.0.0");
  ezgrpc_server_set_ipv4_bind_port(server_handle, 19009);

  ezgrpc_server_set_ipv6_bind_addr(server_handle, "::");
  ezgrpc_server_set_ipv6_bind_port(server_handle, 19009);
  ezgrpc_server_set_shutdownfd(server_handle, pfd[0]);

  /* This call is blocking.
   * when a SIGINT/SIGTERM is received, it should return */
  ezgrpc_server_start(server_handle);

  ezgrpc_server_free(server_handle);

  return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.