前2天刚刚小小的分析下Client端的流程,走的还是比较通顺的,但是RPC的服务端就显然没有那么简单了,毕竟C-S这种模式的,压力和重点都是放在Server端的,所以我也只能做个大概的分析,因为里面细节的东西太多,我也不可能理清所有细节,但是我会集合源代码把主要的流程理理清。如果读者想进一步学习的话,可自行查阅源码。
Server服务端和Client客户端在某些变量的定义上还是一致的,比如服务端也有Call,和Connection,这个很好理解,Call回调,和Connection连接是双向的。首先看一个Server类的定义:
public abstract class Server {
private final boolean authorize;
private boolean isSecurityEnabled;
/**
* The first four bytes of Hadoop RPC connections
* Hadoop RPC的连接魔数字符‘hrpc’
*/
public static final ByteBuffer HEADER = ByteBuffer.wrap("hrpc".getBytes());
// 1 : Introduce ping and server does not throw away RPCs
// 3 : Introduce the protocol into the RPC connection header
// 4 : Introduced SASL security layer
public static final byte CURRENT_VERSION = 4;
....
这里定义了基本的一些信息,版本号了,还有用于验证的魔数了等等。下面看看他的2个关键内部类,Connection连接和Call回调类
/** A call queued for handling. */
/** 服务端的Call列表队列 ,与客户端的是不同的*/
private static class Call {
//客户端的Call Id,是从客户端上传过类的
private int id; // the client's call id
//Call回调参数
private Writable param; // the parameter passed
//还保存了与客户端的连接
private Connection connection; // connection to client
//接收到response回应的时间
private long timestamp; // the time received when response is null
// the time served when response is not null
//对于此回调的回应值
private ByteBuffer response; // the response for this call
......
在内部变量的设置上还是有小小的不同的,到时服务端就是通过往Call中写response处理回复的。还有一个是连接类:
/** Reads calls from a connection and queues them for handling. */
public class Connection {
//连接的RPC头部是否已读
private boolean rpcHeaderRead = false; // if initial rpc header is read
//版本号之后的头部信息是否已读
private boolean headerRead = false; //if the connection header that
//follows version is read.
private SocketChannel channel;
//字节缓冲用于读写回复
private ByteBuffer data;
private ByteBuffer dataLengthBuffer;
//回复Call列表
private LinkedList<Call> responseQueue;
//此连接下的RPC请求数
private volatile int rpcCount = 0; // number of outstanding rpcs
private long lastContact;
private int dataLength;
private Socket socket;
// Cache the remote host & port info so that even if the socket is
// disconnected, we can say where it used to connect to.
private String hostAddress;
private int remotePort;
private InetAddress addr;
.....
上面的变量也很好理解,不解释了,在Server端多出了下面几个关键的变量:
.....
volatile private boolean running = true; // true while server runs
//阻塞式Call待处理的队列
private BlockingQueue<Call> callQueue; // queued calls
//与客户端的连接数链表
private List<Connection> connectionList =
Collections.synchronizedList(new LinkedList<Connection>());
//maintain a list
//of client connections
//服务端的监听线程
private Listener listener = null;
//处理应答线程
private Responder responder = null;
private int numConnections = 0;
//处理请求线程组
private Handler[] handlers = null;
.....
callQueue,待处理请求列表,ConnectionList连接列表,还有3大线程,监听,处理,应答请求线程,待处理请求人家用的还是BlockingQueue阻塞式队列,队列如果满了是插入不了需要等待的,队列为空是取不出数据也是要等待。在这点上作者是有自己的考虑的。通过上面的描述,Server类的大体框图就出来了:
好了,下面的分析重点就是3大线程的具体操作了。3大线程的在Server start操作后就会开始工作:
/** Starts the service. Must be called b