尽管这里是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. 详解vue生命周期

    vue生命周期 @(vue)[生命周期] 前言 在使用vue一个多礼拜后,感觉现在还停留在初级阶段,虽然知道怎么和后端做数据交互,但是对于mounted这个挂载还不是很清楚的.放大之,对vue的生命周 ...

  2. 把一个机器上1天内新增的文件用rsync传送到另外一台机器

    我的shell很菜,只好用shell和php结合来做 1.查找新增的文件,构造rsync的参数,把结果写入到log中 find /data/bmob/test/teststorage/data/ -m ...

  3. java编程思想-第13章-某些练习题

    . 匹配任意一个字符 * 表示匹配0个或多个前面这个字符 + 表示1个或多个前面这个字符 ? 表示0个或1个前面这个字符 ^ 表示一行的开始 ^[a-zA-Z] :表示开头是a-z或者A-Z [^0- ...

  4. resteasy简单实例

    1.建一个maven web项目 新建一个maven项目,next,第一个框不要勾选 选择maven-archetype-webapp,建一个web项目 键入项目组织id与项目id 一般此时搭建的只是 ...

  5. mvc 三个 之间 肮脏的交易

    就当个小零食一样写. MVC 是 Model-View-Controller 的缩写,Model代表的是应用的业务逻辑(通过 JavaBean,EJB 组件实现),View 是应用的表示层(由 JSP ...

  6. eclipse使用javaFX写一个HelloWorkld

    ------------------------------------------------ 操作系统:Ubuntu18.04 EclipseVersion: Oxygen.3a Release ...

  7. appium----【已解决】【Mac】ANDROID_HOME的环境变量配置

    在搭建appium的环境时,提示Android_home的环境没有配置,经过一会的奋战终于解决,再次记录下解决方式. 1.安装android-sdk-macosx 下载路径:http://down.t ...

  8. json数组的解析

    一直以来,经常会遇到json数据从前端或者我经常从网站上爬取的数据中会有json数据的存在,这样如果想要获取json数据就需要对json数据进行解析 在开发过程中,经常需要和别的系统交换数据,数据交换 ...

  9. mySql入门-(一)

    学了很多乱七杂八的东西,但是依然停留在前端,在工作中一直和后端交流,但是不太了解数据库是怎么回事,为了加强学习,准备学习一些关于数据库相关的东西. 说起数据库可能会有很多很多,SQLServer.Or ...

  10. 【推荐】.NETCore 简单且高级的库 csredis v3.0.0

    前言 .NETCore 从1.0发布历经坎坷,一开始各种库缺失到现在的部分完善,走到今天实属不易. 比如 redis-cli SDK 简直是坑出不穷. 过去 .net 最有名望的 ServiceSta ...