尽管这里是hadoop的rpc服务,但是hadoop还是做到了一次连接仅有一次认证。具体的流程待我慢慢道来。
  客户端:这里我们假设ConnectionId对应的Connection并不存在。在调用getConnection方法时,这里构造了Connection,由于入参ConnectionId.doPing一般为true,因此,在Connection的构造方法时,会构造相应的pingHeader写入到成员变量pingRequest中。接着将call加入到connection中后,调用了connection.setupIOstreams,这里一开始就调用了writeConnectionHeader,一共写了7个字节的内容到服务端(分别是"hrpc",Version、Service Class、AuthProtocol,显然,前面是四个字节,后面三个都是一个字节)。另外,由于这里的成员变量doPing为true,因此,这里使用PingInputStream封装了上面获取的输入流。该方法内接着调用了writeConnectionContext,该方法就是rpc的认证调用。这里的callId设置为CONNECTION_CONTEXT_CALL_ID,这里最后调用了request.write,将request中的信息写到了out中,注意,这里并没有调用其flush方法。但是,这里封装了一次请求。接着,调用了connection.sendRpcRequest,这里将请求的call继续写入到out中,并调用了flush方法。至此,客户端的流程也就完成了。
  服务端:关于服务端的流程,我从Server.Listener.run讲起。这里一开始是阻塞的。当客户端调用了flush之后,这里的阻塞被打断。这里然后调用到了doAccept方法。在该方法中首先调用到了ConnectionManager.register,这里新构造了Connection并且将其加入到成员结合connections中。在Connection的构造中封装了客户端的channel、socket等相关信息。然后将新构造的connection作为attachment绑定到SelectionKey上,然后调用reader.addConnection将其加入到阻塞队列pendingConnections,并调用wakeup唤醒了reader在doRunLoop方法中的readSelector.select阻塞。而Server.Listener中的方法继续阻塞。
  接下来,我们重点关注Server.Listener.Reader.doRunLoop。这里的readSelector.select阻塞打断后,由于此时的readSelector中并没有相关的selectedKeys,因此继续循环执行。接着从pendingConnections队列中取出封装了客户端相关信息的Connection,然后将Connection.channel注册到readSelector选择器上,由于客户端已经将信息flush过来,所以,这里的注册后的readSelector不会阻塞,且其中含有相应的selectedKeys,故,接下来会调用到doRead方法,接着调用到了Connection.readAndProcess。接下来另起一段着重讲解。
这里dataLengthBuffer.remaining()>0判断成立,调用channelRead将客户端的版本信息读入。接着将Version、Service Class、AuthProtocol读入到connectionHeaderBuf中,然后调用了dataLengthBuffer.flip,方便下次读取数据长度,并且将connectionHeaderRead置为true,也就是下一次遍历的时候不会再读取头部的相关信息。只是读取实际数据长度。然后,由于data == null,因此,这里为data分配空间,然后调用了processOneRpc,由于这里是封装的CONNECTION_CONTEXT_CALL_ID的call,因此,这里来到processRpcOutOfBandRequest方法,该方法完成了认证的相关流程。由于一开始connectionContextRead为false,而在processRpcOutOfBandRequest方法中被置为true,因此,这里会调用continue。这里重新读取的数据的长度,然后继续调用了processOneRpc。这一次callId不小于0,因此会调用到方法processRpcRequest。该方法是完成真正请求的,也就是说,前面的几次调用只是前期的校验。所谓真正的请求,也就是要调用服务端的相关方法。processRpcRequest方法将客户端的相关信息封装到Call,并将其加入到callQueue中。
  另一方面,在Handler.run中一直在等待callQueue中成员的加入。通过其take方法可以看到内部的阻塞队列一直在轮询等待成员的加入。这里接着调用了CurCall.set(call),方便后面获取客户端的ugi。接着就调用到了RPC.Server.call,由于这里的Server继承自org.apache.hadoop.ipc.Server(该类是一个抽象类),而前面的Server覆写了后面Server的抽象方法call。最终调用了ProtobufRpcEngine.cal,该方法完成了服务端对应方法的调用,并且将结果返回。
  另外,如果客户端在请求超时之后,会调用sendPing方法,用于测试服务端的服务是否仍然开启,此时的callId为PING_CALL_ID。

  至此,hdfs中客户端与服务端的交互就比较详细的展现给大家了。

hadoop rpc协议客户端与服务端的交互流程的更多相关文章

  1. Hadoop RPC源码阅读-服务端Server

    Hadoop版本Hadoop2.6 RPC主要分为3个部分:(1)交互协议 (2)客户端(3)服务端 (3)服务端 RPC服务端的实例代码: public class Starter { public ...

  2. 二、网络编程-socket之TCP协议开发客户端和服务端通信

    知识点:之前讲的udp协议传输数据是不安全的,不可靠不稳定的,tcp协议传输数据安全可靠,因为它们的通讯机制是不一样的.udp是用户数据报传输,也就是直接丢一个数据包给另外一个程序,就好比寄信给别人, ...

  3. Fresco 源码分析(二) Fresco客户端与服务端交互(3) 前后台打通

    4.2.1.2.4 PipelineDraweeControllerBuilder.obtainController()源码分析 续 上节中我们提到两个核心的步骤 obtainDataSourceSu ...

  4. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  5. RPC学习--C#使用Thrift简介,C#客户端和Java服务端相互交互

    本文主要介绍两部分内容: C#中使用Thrift简介 用Java创建一个服务端,用C#创建一个客户端通过thrift与其交互. 用纯C#实现Client和Server C#服务端,Java客户端 其中 ...

  6. 使用Thrift RPC编写程序(服务端和客户端)

    1. Thrift类介绍 Thrift代码包(位于thrift-0.6.1/lib/cpp/src)有以下几个目录: concurrency:并发和时钟管理方面的库processor:Processo ...

  7. java网络编程客户端与服务端原理以及用URL解析HTTP协议

    常见客户端与服务端 客户端: 浏览器:IE 服务端: 服务器:web服务器(Tomcat),存储服务器,数据库服务器. (注:会用到Tomact服务器,在webapps下有一个自己创建的目录myweb ...

  8. 网络编程 UDP协议 TCP局域网客户端与服务端上传下载电影示例

    UDP协议 (了解) 称之为数据包协议,又称不可靠协议. 特点: 1) 不需要建立链接. 2) 不需要知道对方是否收到. 3) 数据不安全 4) 传输速度快 5)能支持并发 6) 不会粘包 7) 无需 ...

  9. java 从零开始手写 RPC (03) 如何实现客户端调用服务端?

    说明 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RPC (02)-netty4 实现客户端和服务端 写完了客户端和服务端,那么如何实现客户端和服务端的 ...

随机推荐

  1. 如何解决python升级后yum报错

    当我们yum命令的时候,会提示 "File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ SyntaxEr ...

  2. [TJOI2015] 棋盘

    Description 为了提高智商,ZJY去新世界旅游了.可是旅游过后的ZJY杯具的发现要打开通往原来世界的门,必须要解开门上面画的谜题.谜题是这样的:有个\(n\)行\(m\)列的棋盘,棋盘上可以 ...

  3. Flask开发微电影网站(三)

    页面完成后的最终布局 可以看到,页面共同的部分是顶部导航和底部导航 所以我们可以把页面顶部导航和底部导航部分单独定义一个文件home.html,然后让需要使用顶部导航和底部导航的页面都继承home.h ...

  4. 某校高中生利用Python,巧妙获取考试成绩,看到成绩后无言以对!

    Python是非常有吸引力的编程语言,学习Python的不是帅哥就是美女.为什么这么说呢?因为我和我的女朋友都是学习Python认识的,小编肯定是帅哥,不用去怀疑,而且我眼光特高. 给大伙讲一个故事, ...

  5. auth.go

    ), fmt.Errorf("invalid permission type: %s", s) } type authenticator struct {     conn *gr ...

  6. 【最小生成树】BZOJ1016: [JSOI2008]最小生成树计数

    Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...

  7. bzoj 2500 幸福的道路 树上直径+set

    首先明确:树上任意一点的最长路径一定是直径的某一端点. 所以先找出直径,求出最长路径,然后再求波动值<=m的最长区间 #include<cstdio> #include<cst ...

  8. C#进度框

    1.方法一:使用线程 功能描述:在用c#做WinFrom开发的过程中.我们经常需要用到进度条(ProgressBar)用于显示进度信息.这时候我们可能就需要用到多线程,如果不采用多线程控制进度条,窗口 ...

  9. 如何运行vue项目

    首先,列出来我们需要的东西:   node.js环境(npm包管理器) vue-cli 脚手架构建工具 cnpm  npm的淘宝镜像   安装node.js 从node.js官网下载并安装node,安 ...

  10. Windows上安装配置SSH教程(1)——知识点汇总

    1.是什么SSH? 维基百科:https://zh.wikipedia.org/wiki/Secure_Shell 其他博客:http://www.ruanyifeng.com/blog/2011/1 ...