我知道Thrift主要针对成熟的客户端-服务器RPC,但是从高级架构的角度来看,它似乎也可以完美地用于双向消息传递。
我想在两端(C,.NET Core)上构建的内容如下:
我不需要线程服务器,……任何花哨的东西。从本质上讲,我想超越例如Protobuffs提供了开箱即用的处理功能,可以在接收端缓冲整个消息,通常还可以缓存消息。
问题是我找不到关于如何使用当前库(我个人对.NET Core和C语言的API)进行构建的文档。我唯一发现的是这个question,但实际上并没有指向任何资源。
答案 0 :(得分:1)
Thrift是一个RPC和序列化框架。这意味着,您也可以仅使用序列化部分而不使用RPC。
与消息传递系统结合使用时,通常(大致)如下:
如果您打算通过同一通道发送不同类型的消息,则最好使用一个union
信封结构来包含所有可能的消息正文:
struct MessageOne {
// contents of this message type
}
struct MessageTwo {
// contents of this message type
}
struct MessageThree {
// contents of this message type
}
union MyMessageEnvelope {
1: MessageOne one
2: MessageTwo two
3: MessageThree three
// easily extendable
}
为使其更美观/可重用,还可以实现一种自定义传输来满足需要并进一步封装逻辑。 Thrift的模块化结构使其变得容易(您所链接的帖子也对此进行了引用)。源树的/contrib
文件夹中有一些示例可以用作起点。
如果您完全不知道从哪里开始:先看一下教程,再看一下测试套件程序,它们都是Thrift入门者的学习资源。
答案 1 :(得分:1)
做一些非常类似的事的笔记:
The suggestion to put all messages in a top-level union是一个很好的选择,因为它将使反序列化消息变得更加容易。
给出以下节约条件:
struct SubscribeRequest {
1: string topic,
2: string appid,
}
struct SubscribeReply {
1: bool success,
2: string topic,
}
service HttpService {
HttpSDKDataTypes.SubscribeReply Subscribe(1: HttpSDKDataTypes.SubscribeRequest message),
}
thrift -gen netcore
为您提供:
public async Task<Ruyi.SDK.Http.SubscribeReply> SubscribeAsync(Ruyi.SDK.Http.SubscribeRequest message, CancellationToken cancellationToken)
{
await OutputProtocol.WriteMessageBeginAsync(new TMessage("Subscribe", TMessageType.Call, SeqId), cancellationToken);
消息标识符包含在RPC调用中。如果您不使用RPC调用,则会得到“原始”结构,而没有指示如何反序列化它们。
将它们放入union
:
union UnionExample {
1: SubscribeRequest request,
2: SubscribeReply reply,
}
为您处理:
public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)
{
oprot.IncrementRecursionDepth();
try
{
var struc = new TStruct("SubscribeRequest");
await oprot.WriteStructBeginAsync(struc, cancellationToken);
var field = new TField();
if (Topic != null && __isset.topic)
{
field.Name = "topic";
field.Type = TType.String;
field.ID = 1;
反序列化后,可以使用以下方法处理它们:
public void handler(UnionExample example)
{
if (example.__isset.request)
{
SubscribeRequest msg = example.request;
// ...
}
else if (example.__isset.reply)
{
SubscribeReply msg = example.reply;
// ...
}
检查生成器中可用的选项。 thrift -gen "csharp:union,async"
让您使用pattern matching:
public void handler(UnionExample example)
{
switch (example.Data)
{
case SubscribeRequest msg:
//...
case SubscribeReply msg:
//...
不幸的是,netcore
生成器在0.11.0中没有这样做。
节俭的github存储库具有examples of serializing into memory(而不是使用RPC)。一般来说,它类似于:
Stream stm = new MemoryStream();
TTransport trans = new TStreamTransport(null, stm);
TProtocol prot = new TJSONProtocol(trans);
如果要创建很多MemoryStream
实例,请查看Microsoft.IO.RecycableMemoryStream
。
使用自定义协议/传输将简化发送消息的过程,因为它将处理样板(并避免先将多余的对象序列化到内存,然后再对其进行处理)。已经提到了thrift contrib/
folder。
Here's our C# example使用Thrift over ZeroMQ。
最后的笔记。如果您完全要使用RPC功能,请使用单个struct参数编写服务方法。含义:
service HttpService {
// Do this
string Subscribe(1: SubscribeRequest message),
// Not this
string Subscribe(1: string topic, 2: string appid,),
}
这将使摆脱RPC和/或重用消息更加容易。