gRPC中,Server、Client共享的Class不是很多,所以我们可以单独的分别讲解Server和Client的源码。

通过第一篇,我们知道对于gRPC来说,建立Server是非常简单的,还记得怎么写的?还是以example里 HelloWorldServer 例子来看

server = ServerBuilder.forPort(port)
.addService(new GreeterImpl())
.build()
.start();

你没有看错,就是这么几行搞定。

如果需要看懂gRPC的源码,首先有几点需要明白

  • Builder模式生成Entity

  • Provider(SPI)模式解耦,动态选择服务提供方

  • abstract class用于扩展

0. 流程图

1. Builder

ServerBuilder是一个抽象类,不同的服务提供方(Provider),将继承实现它。如何找到这些继承者呢?ServerProvider就是用来找到不同的provider的。

2. Provider

如上图,ServerProvider也是一个抽象类,实现者都有哪些呢?我们通过SPI模式找到他们。

通过搜索文件知道gRPC中 io.grpc.ServerProvider 的实现方只有:Netty

io.grpc.netty.NettyServerProvider,
这个类就是ServerProvider的实现者,它的builderForPort返回ServerBuilder

3. NettyServer

最后,我们来看下当链接建立时是如何创建handle的。

public void initChannel(Channel ch) throws Exception {
eventLoopReferenceCounter.retain();
ch.closeFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
eventLoopReferenceCounter.release();
}
});
NettyServerTransport transport = new NettyServerTransport(ch, protocolNegotiator,
maxStreamsPerConnection, flowControlWindow, maxMessageSize, maxHeaderListSize);
ServerTransportListener transportListener;
// This is to order callbacks on the listener, not to guard access to channel.
synchronized (NettyServer.this) {
if (channel != null && !channel.isOpen()) {
// Server already shutdown.
ch.close();
return;
} transportListener = listener.transportCreated(transport);
}
transport.start(transportListener);
}

看code可知,当一个链接建立时,会生成一个NettyServerTransport,所有的数据处理都将在这里实现。

4. NettyServerTransport

public void start(ServerTransportListener listener) {
Preconditions.checkState(this.listener == null, "Handler already registered");
this.listener = listener; // Create the Netty handler for the pipeline.
final NettyServerHandler grpcHandler = createHandler(listener);
HandlerSettings.setAutoWindow(grpcHandler); // Notify when the channel closes.
channel.closeFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
notifyTerminated(grpcHandler.connectionError());
}
}); ChannelHandler negotiationHandler = protocolNegotiator.newHandler(grpcHandler);
channel.pipeline().addLast(negotiationHandler);
}

我们看到当调用start方法是,最重要的就是createHandle,在这个方法里将看到如何绑定HTTP/2的处理器的。

5. NettyServerHandle

static NettyServerHandler newHandler(ServerTransportListener transportListener,
int maxStreams,
int flowControlWindow,
int maxHeaderListSize,
int maxMessageSize) {
Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive");
// 就是一个log
Http2FrameLogger frameLogger = new Http2FrameLogger(LogLevel.DEBUG, NettyServerHandler.class);
Http2HeadersDecoder headersDecoder = new GrpcHttp2ServerHeadersDecoder(maxHeaderListSize);
// reader
Http2FrameReader frameReader = new Http2InboundFrameLogger(
new DefaultHttp2FrameReader(headersDecoder), frameLogger);
// writer
Http2FrameWriter frameWriter =
new Http2OutboundFrameLogger(new DefaultHttp2FrameWriter(), frameLogger);
return newHandler(frameReader, frameWriter, transportListener, maxStreams, flowControlWindow,
maxMessageSize);
} @VisibleForTesting
static NettyServerHandler newHandler(Http2FrameReader frameReader, Http2FrameWriter frameWriter,
ServerTransportListener transportListener,
int maxStreams,
int flowControlWindow,
int maxMessageSize) {
Preconditions.checkArgument(maxStreams > 0, "maxStreams must be positive");
Preconditions.checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
Preconditions.checkArgument(maxMessageSize > 0, "maxMessageSize must be positive");
// 一个channel一个connection
Http2Connection connection = new DefaultHttp2Connection(true); // Create the local flow controller configured to auto-refill the connection window.
connection.local().flowController(
new DefaultHttp2LocalFlowController(connection, DEFAULT_WINDOW_UPDATE_RATIO, true)); Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, frameWriter);
Http2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder,
frameReader); Http2Settings settings = new Http2Settings();
settings.initialWindowSize(flowControlWindow);
settings.maxConcurrentStreams(maxStreams); return new NettyServerHandler(transportListener, decoder, encoder, settings, maxMessageSize);
}

gRPC源码分析2-Server的建立的更多相关文章

  1. gRPC源码分析0-导读

    gRPC是Google开源的新一代RPC框架,官网是http://www.grpc.io.正式发布于2016年8月,技术栈非常的新,基于HTTP/2,netty4.1,proto3.虽然目前在工程化方 ...

  2. Kafka源码分析(三) - Server端 - 消息存储

    系列文章目录 https://zhuanlan.zhihu.com/p/367683572 目录 系列文章目录 一. 业务模型 1.1 概念梳理 1.2 文件分析 1.2.1 数据目录 1.2.2 . ...

  3. grpc源码分析之域名解析

    环境: win7_x64,VS2015.grpc_1.3.1 场景: 在客户端中使用grpc连接服务器,在多次输入非法的地址后,再次输入正确的地址连出现连接超时的现象.侯捷先生说过“源码面前,了无秘密 ...

  4. Apache Kafka源码分析 – Broker Server

    1. Kafka.scala 在Kafka的main入口中startup KafkaServerStartable, 而KafkaServerStartable这是对KafkaServer的封装 1: ...

  5. Go合集,gRPC源码分析,算法合集

    年初时,朋友圈见到的最多的就是新的一年新的FlAG,年末时朋友圈最多的也是xxxx就要过去了,你的FLAG实现了吗? 这个公众号2016就已经创建了,但截至今年之前从来没发表过文章,现在想想以前很忙, ...

  6. kafka源码分析之一server启动分析

    0. 关键概念 关键概念 Concepts Function Topic 用于划分Message的逻辑概念,一个Topic可以分布在多个Broker上. Partition 是Kafka中横向扩展和一 ...

  7. gRPC源码分析(c++)

    首先需要按照grpc官网上说的办法从github上下载源码,编译,然后跑一跑对应的测试代码.我分析的代码版本为v1.20.0. 在cpp的helloworld例子中,client端,第一个函数是创建c ...

  8. gRPC源码分析1-SSL/TLS

    引子 前几天看到微信后台团队分享了TLS相关文章,正好gRPC里TLS数据加密是很重要的一块,于是整理出了这篇文章. 在gRPC里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...

  9. Django源码分析之server

    乍见 Django内置的server基本包括两部分:django.core.servers和django.core.handlers 相识 servers.basehttp是Django自身提供的一个 ...

随机推荐

  1. Flex 布局教程:语法篇

    作者: 阮一峰 网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便 ...

  2. 【SAP业务模式】之ICS(三):前台操作

    本片博文开始讲解SAP前台是如何实现ICS业务模式的. 一.VA01开立销售订单 我这里为了方便,创建了一个订单类型ZMIV作为公司间销售的订单类型,其实公司间销售订单跟标准的销售订单是一致的.同时, ...

  3. Xcode 锁终端

    锁终端 输入: <1>cd /Applications/Xcode.app 回车 结果显示: Xcode.app 输入: <2>sudo chown -hR root:whee ...

  4. 个人也能申请微信小程序获得APPID和手机测试效果

    微信小程序昨晚火爆公测,我也第一时间注册了小程序账号开启公测之旅. 注册过程可以看文档:https://my.oschina.net/imhoodoo/blog/780901 进入后台之后我们其实主要 ...

  5. js月份,日期加一天

    js没有直接可以用的函数,所以只能自己写,其中需要涉及到每个月天数的判断,如果是2月份的话,还要涉及到闰年的判断 var addDate = { //日期,在原有日期基础上,增加days天数,默认增加 ...

  6. Mono 4.0 Mac上运行asp.net mvc 5.2.3

    Mono 4.0 已经发布,二进制包已经准备好,具体的发布说明参见:http://www.mono-project.com/docs/about-mono/releases/4.0.0/. 今天在Ma ...

  7. React 其实比 MVVM 架构更加卡顿

    React 号称通过引入 Virtual DOM 带来了性能的提升,而其实 React 之所以需要 Virtual DOM,是因为它的架构下,state 的变更是全量的,然后触发 render 返回全 ...

  8. redis的面试题

    1:使用redis有哪些好处? (1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) (2) 支持丰富数据类型,支持string,lis ...

  9. 4.2w起步的软件公司创业历程

    调查说,中国民营企业的生命期平均是2.8年,如今我的企业已走过近四年,而这一年却是我的迷茫期,不知道何去何从,现在写下 来与大家一起分享一下,写得较为凌乱,大家将就着看一下吧:) 先交待一下自己,我来 ...

  10. 搭建LNAMP环境(一)- 源码安装MySQL5.6

    1.yum安装编译mysql需要的包 yum -y install gcc-c++ make cmake bison-devel ncurses-devel perl 2.为mysql创建一个新的用户 ...