每个请求都会执行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调用:
