每个请求都会执行Client.call,方法内会获取connection(getConnection):从connections中获取,若不存在则新建
getConnection:这里会对要返回的connection执行setupIOstreams
setupIOstreams:做连接认证 --> 请求发送
可以看到这里会对connection 设置I/O:可以看到这里对于已有的connection不会再进行saslConnect、writeConnectionContext,直接return
对于这个connection的ticket(UGI),通过remoteId.getTicket()获取
构造remoteId(ConnectionId);传入前可先设置displayUser:
【A】循环直到,connection连接上server:(这里是连接磋商)
1.writeConnectionHeader(ipcStreams) : 这里把authProtocol.callId 写入ipcStreams中
2.【authProtocol == AuthProtocol.SASL】如果是SASL,则setupSaslConnection(ipcStreams) >> 执行saslRpcClient.saslConnect(streams) :
a、先执行一次sendSaslMessage方式把ipcStreams数据发送给server(磋商):SaslState.NEGOTIATE
b、循环磋商,直到连接成功;读取response:saslMessage 做判断处理
接收回复数据saslMessage,通过saslMessage.getState 返回判定服务认证方式()
NEGOTIATE:需要再认证:sendSaslMessage:SaslState.INITIATE -->
responseToken:
1.saslAuthType.hasChallenge() --> challengeToken = saslAuthType.getChallenge().toByteArray();
2.saslClient.hasInitialResponse() --> challengeToken = new byte[0];
3. null
CHALLENGE:server已下发过token,需要获取saslMessage内token回复认证:sendSaslMessage:SaslState.RESPONSE
SUCCESS:认证成功
NEGOTIATE\CHALLENGE时需要回复server:
【B】执行writeConnectionContext,创建ConnectionContext、Header,并写入到ResponseBuffer,最终通过ipcStreams.sendRequest 发送给服务端:callId=CONNECTION_CONTEXT_CALL_ID=-3,这里只有第一个线程才会执行
1. 调用 ProtoUtil.makeIpcConnectionContext完成ConnectionContext的创建:
ProtoUtil.makeIpcConnectionContext
在ConnectionContext中设置:Protocol、UGI
2. 调用 ProtoUtil.makeRpcRequestHeader完成Header的创建
ProtoUtil.makeRpcRequestHeader
在header中设置:RpcKind、RpcOp、CallId、RetryCount、ClientId、CallerContext、alignmentContext
这里的CallId为RpcConstants中静态值(固定):在做连接时用到
CallerContext中可配置:clientIp、clientPort、clientId、clientCallId、realUser
获取到connection后执行sendRpcRequest(call),完成RPC调用: