.net core下使用Thrift
因网站组(.net)与游戏服务端(c++)原来使用REST API通讯效率稍显低下,准备下期重构时改用rpc方式,经比较Thrift和gRPC两者的优劣(参照网上的对比结果),最终决定使用Thrift。
首先下载Thrift代码生成器,编写根据Thrift的语法规范(可参看https://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167669.html)编写脚本文件OrderService.thrift,如下:
namespace csharp Qka.Contract
service OrderService{
InvokeResult Create(1:Order order)
Order Get(1:i32 orderId)
list<Order> GetListByUserId(1:i32 userId,2:bool isPaid)
InvokeResult Delete(1:i32 orderId)
}
enum ResponseCode {
SUCCESS = 0,
FAILED = 1,
}
struct Order {
1: required i32 OrderId;
2: required i32 SkuId;
3: required i32 Amount;
4: optional string Remark;
}
struct InvokeResult {
1: required ResponseCode code;
2: optional string Message;
}
在Thrift代码生成器的目录下执行命令:./thrift.exe -gen csharp OrderService.thrift,发现同目录下多了一个gen-csharp文件夹,生成的代码放在这个文件夹里面。
新建一个.net core的解决方案,结构如下:

三个项目均添加apache-thrift-netcore的nuget包(这里服务端寄宿在asp.net core程序的原因是因为我们采用微服务的模式,每一块业务的UI、Rest API、RPC Server全部放在一块),将刚刚生成的代码文件拷至Qka.Contract项目里,其他两个项目添加Qka.Contract项目的引用。
在Qka.WebServer中实现服务接口:
public class OrderServiceImpl : Iface
{
public InvokeResult Create(Order order)
{
return new InvokeResult
{
Code = ResponseCode.SUCCESS,
Message = $"订单{order.OrderId}创建成功!"
};
} public InvokeResult Delete(int orderId)
{
return new InvokeResult
{
Code = ResponseCode.SUCCESS,
Message = $"订单{orderId}删除成功成功!"
};
} public Order Get(int orderId)
{
return new Order
{
OrderId = ,
SkuId = ,
Amount = ,
Remark = "黄金万两"
};
} public List<Order> GetListByUserId(int userId, bool isPaid)
{
return new List<Order>
{
new Order
{
OrderId = ,
SkuId = ,
Amount = ,
Remark = "黄金万两"
},
new Order
{
OrderId = ,
SkuId = ,
Amount = ,
Remark = "白银百两"
},
};
}
}
编写ApplicationExtenssion,代码如下:
public static class ApplicationExtenssion
{
public static IApplicationBuilder UseThriftServer(this IApplicationBuilder appBuilder)
{
var orderService = new OrderServiceImpl();
Processor processor = new Processor(orderService);
TServerTransport transport = new TServerSocket();
TServer server = new TThreadPoolServer(processor, transport); var services = appBuilder.ApplicationServices.CreateScope().ServiceProvider; var lifeTime = services.GetService<IApplicationLifetime>();
lifeTime.ApplicationStarted.Register(() =>
{
server.Serve();
});
lifeTime.ApplicationStopped.Register(() =>
{
server.Stop();
transport.Close();
}); return appBuilder;
}
}
上面的代码用的是TThreadPoolServer,网上的代码均采用TSimpleServer,通过反编译比较TSimpleServer、TThreadedServer、TThreadPoolServer,发现TSimpleServer只能同时响应一个客户端,TThreadedServer则维护了一个clientQueue,clientQueue最大值是100,TThreadPoolServer则用的是用线程池响应多个客户请求,生产环境绝不能用TSimpleServer。
在Startup.cs文件的Configure方法中添加:
app.UseThriftServer();
服务端代码大功告成,再来编写客户端调用代码:
class Program
{
static void Main(string[] args)
{
TTransport transport = new TSocket("localhost", );
TProtocol protocol = new TBinaryProtocol(transport);
var client = new OrderService.Client(protocol);
transport.Open(); var createResult = client.Create(new Order
{
OrderId = ,
SkuId = ,
Amount = ,
Remark = "测试创建订单"
});
var order = client.Get();
var list = client.GetListByUserId(, true);
var deleteResult = client.Delete(); transport.Close(); Console.ReadKey();
}
}
下面这段话引自https://www.cnblogs.com/cyfonly/p/6059374.html,解释上面代码中为什么采用TSocket和TBinaryProtocol:
Thrift 支持多种传输协议,用户可以根据实际需求选择合适的类型。Thrift 传输协议上总体可划分为文本 (text) 和二进制 (binary) 传输协议两大类,一般在生产环境中使用二进制类型的传输协议为多数(相对于文本和 JSON 具有更高的传输效率)。常用的协议包含:
TBinaryProtocol:是Thrift的默认协议,使用二进制编码格式进行数据传输,基本上直接发送原始数据
TCompactProtocol:压缩的、密集的数据传输协议,基于Variable-length quantity的zigzag 编码格式
TJSONProtocol:以JSON (JavaScript Object Notation)数据编码协议进行数据传输
TDebugProtocol:常常用以编码人员测试,以文本的形式展现方便阅读
关于以上几种类型的传输协议,如果想更深入更具体的了解其实现及工作原理,可以参考站外相关文章《thrift源码研究》。 传输方式
与传输协议一样,Thrift 也支持几种不同的传输方式。
1. TSocket:阻塞型 socket,用于客户端,采用系统函数 read 和 write 进行读写数据。
2. TServerSocket:非阻塞型 socket,用于服务器端,accecpt 到的 socket 类型都是 TSocket(即阻塞型 socket)。
3. TBufferedTransport 和 TFramedTransport 都是有缓存的,均继承TBufferBase,调用下一层 TTransport 类进行读写操作吗,结构极为相似。其中 TFramedTransport 以帧为传输单位,帧结构为:4个字节(int32_t)+传输字节串,头4个字节是存储后面字节串的长度,该字节串才是正确需要传输的数据,因此 TFramedTransport 每传一帧要比 TBufferedTransport 和 TSocket 多传4个字节。
4. TMemoryBuffer 继承 TBufferBase,用于程序内部通信用,不涉及任何网络I/O,可用于三种模式:(1)OBSERVE模式,不可写数据到缓存;(2)TAKE_OWNERSHIP模式,需负责释放缓存;(3)COPY模式,拷贝外面的内存块到TMemoryBuffer。
5. TFileTransport 直接继承 TTransport,用于写数据到文件。对事件的形式写数据,主线程负责将事件入列,写线程将事件入列,并将事件里的数据写入磁盘。这里面用到了两个队列,类型为 TFileTransportBuffer,一个用于主线程写事件,另一个用于写线程读事件,这就避免了线程竞争。在读完队列事件后,就会进行队列交换,由于由两个指针指向这两个队列,交换只要交换指针即可。它还支持以 chunk(块)的形式写数据到文件。
6. TFDTransport 是非常简单地写数据到文件和从文件读数据,它的 write 和 read 函数都是直接调用系统函数 write 和 read 进行写和读文件。
7. TSimpleFileTransport 直接继承 TFDTransport,没有添加任何成员函数和成员变量,不同的是构造函数的参数和在 TSimpleFileTransport 构造函数里对父类进行了初始化(打开指定文件并将fd传给父类和设置父类的close_policy为CLOSE_ON_DESTROY)。
8. TZlibTransport 跟 TBufferedTransport 和 TFramedTransport一样,调用下一层 TTransport 类进行读写操作。它采用<zlib.h>提供的 zlib 压缩和解压缩库函数来进行压解缩,写时先压缩再调用底层 TTransport 类发送数据,读时先调用 TTransport 类接收数据再进行解压,最后供上层处理。
9. TSSLSocket 继承 TSocket,阻塞型 socket,用于客户端。采用 openssl 的接口进行读写数据。checkHandshake()函数调用 SSL_set_fd 将 fd 和 ssl 绑定在一起,之后就可以通过 ssl 的 SSL_read和SSL_write 接口进行读写网络数据。
10. TSSLServerSocket 继承 TServerSocket,非阻塞型 socket, 用于服务器端。accecpt 到的 socket 类型都是 TSSLSocket 类型。
11. THttpClient 和 THttpServer 是基于 Http1.1 协议的继承 Transport 类型,均继承 THttpTransport,其中 THttpClient 用于客户端,THttpServer 用于服务器端。两者都调用下一层 TTransport 类进行读写操作,均用到TMemoryBuffer 作为读写缓存,只有调用 flush() 函数才会将真正调用网络 I/O 接口发送数据。
.net core下使用Thrift的更多相关文章
- 在.net core中使用Thrift
Thrift应用比较广泛,这里不介绍Thrift的基本概念和使用.Thrift对.net支持的很好,但自从.net core诞生引来,我曾多次关注Thrift的官方网站,看看对.net core是否提 ...
- 4.5 .net core下直接执行SQL语句并生成DataTable
.net core可以执行SQL语句,但是只能生成强类型的返回结果.例如var blogs = context.Blogs.FromSql("SELECT * FROM dbo.Blogs& ...
- .Net Core 之 图形验证码 本文介绍.Net Core下用第三方ZKWeb.System.Drawing实现验证码功能。
本文介绍.Net Core下用第三方ZKWeb.System.Drawing实现验证码功能. 通过测试的系统: Windows 8.1 64bit Ubuntu Server 16.04 LTS 64 ...
- .NET Core下使用gRpc公开服务(SSL/TLS)
一.前言 前一阵子关于.NET的各大公众号都发表了关于gRpc的消息,而随之而来的就是一波关于.NET Core下如何使用的教程,但是在这众多的教程中基本都是泛泛而谈,难以实际在实际环境中使用,而该篇 ...
- .Net Core下如何管理配置文件
一.前言 根据该issues来看,System.Configuration在.net core中已经不存在了,那么取而代之的是由Microsoft.Extensions.Cnfiguration.XX ...
- .Net Core下如何管理配置文件(转载)
原文地址:http://www.cnblogs.com/yaozhenfa/p/5408009.html 一.前言 根据该issues来看,System.Configuration在.net core ...
- c# .net core 下的网络请求
本文章是在VS2017的环境下,.net core 1.1版本以上. 在这期间,由于.net core 并不基于IIS,我们的过去的网络请求代码在.net core框架下,有可能会出现不兼容,报错的现 ...
- .Net Core下通过Proxy 模式 使用 WCF
.NET Core下的WCF客户端也是开源的,这次发布.NET Core 2.0,同时也发布了 WCF for .NET Core 2.0.0, 本文介绍在.NET Core下如何通过Proxy 消费 ...
- .Net Core下使用WCF
在.net core 下的wcf 和framework下的wcf使用方式有点不太一样.在core下用wc,需要安装VS扩展Visual Studio WCF Connected Service,目前这 ...
随机推荐
- ScrollView与ListView嵌套使用,导致ListView下拉失效
在一次项目开发中,在Scrollv中嵌套进ListView,当触摸ListView范围下拉时,整个展示页面滑动,而不是ListView内容滑动, 也就是说ListView滑动事件被ScrollView ...
- int类型被强制转换成较低精度的byte类型
公司的项目上线之前会进行代码合规性检查,其中很容易违反的一个规则就是“不要把原始类型转换成较低的精度”,实际开发的过程中,很多方法在处理数据时,尤其在做移位操作的时候,难免要把int类型转换成byte ...
- SNMP相关的RFC建议和链接
1. SNMP Books or Articleshttp://www.faqs.org/faqs/snmp-faq/part1/http://www.faqs.org/faqs/snmp-faq/p ...
- 以太坊智能合约虚拟机(EVM)原理与实现
以太坊 EVM原理与实现 以太坊底层通过EVM模块支持合约的执行与调用,调用时根据合约地址获取到代码,生成环境后载入到EVM中运行.通常智能合约的开发流程是用solidlity编写逻辑代码,再通过编译 ...
- SQLServer中PRECISION和LENGTH,还有SCALE的区别
总是搞不清楚,每次自己测试之后又忘记.故今天记录在案 CST_NAME输入大于5个字符或两个汉字加一个字符,报错String or binary data would be truncated.The ...
- linux 下查看wwn号
PC server主机与FC存储进行连接时,一般需要加装HBA卡,两者之间衔接的一个重要参数就是wwn号.redhat或suse下查看wwn号的方法如下.一.SuSE Linux 9查看 /proc/ ...
- redis安装、使用
官网:http://redis.io/ github地址:https://github.com/antirez/redis 简介: redis是一个key-value存储系统.和Mem ...
- mysql安装与配置(以mysql-5.7.10-winx64为例)
一.在官网上下载相应的mysql安装包,本人下载的是:mysql-5.7.10-winx64 (Windows (x86, 64-bit), ZIP Archive) 附下载地址:http://dev ...
- flex 生成多边形时内、外环计算
//顺时钟 var pA:Array = [{x:"2969925.6674000006",y:"476254.4874999998"},{x:"29 ...
- Java多线程:生命周期,实现与调度
Java线程生命周期 Java线程实现方法 继承Thread类,重写run()方法 实现Runnable接口,便于继承其他类 Callable类替换Runnable类,实现返回值 Future接口对任 ...