- 本次目标 -
上次课我们看到响应被写到了 ResponseQueue 队列中,接下来我们来看看服务端发送响应的准备工作。- 源码剖析 -
我们再次回到Processor的run方法,Processor线程是一个非常重要的线程,可以说所有的事就靠这个线程来完成的。
override def run() { startupComplete() while (isRunning) { try { configureNewConnections() //TODO 处理队列里的响应 processNewResponses() poll() processCompletedReceives() processCompletedSends() processDisconnected() } catch { .... } } ... }
重点研究
processNewResponses
方法:
private def processNewResponses() { //从队列里面获取响应 var curr = requestChannel.receiveResponse(id) while (curr != null) { try { curr.responseAction match { case RequestChannel.NoOpAction => // There is no response to send to the client, we need to read more pipelined requests // that are sitting in the server's socket buffer curr.request.updateRequestMetrics trace("Socket server received empty response to send, registering for read: " + curr) selector.unmute(curr.request.connectionId) case RequestChannel.SendAction => //TODO 发送响应 sendResponse(curr) case RequestChannel.CloseConnectionAction => curr.request.updateRequestMetrics trace("Closing socket connection actively according to the response code.") close(selector, curr.request.connectionId) } } finally { curr = requestChannel.receiveResponse(id) } } }
看一下
sendResponse
方法:
/* `protected` for test usage */ protected[network] def sendResponse(response: RequestChannel.Response) { trace(s"Socket server received response to send, registering for write and sending data: $response") val channel = selector.channel(response.responseSend.destination) // `channel` can be null if the selector closed the connection because it was idle for too long if (channel == null) { warn(s"Attempting to send response via channel for which there is no open connection, connection id $id") response.request.updateRequestMetrics() } else { //核心方法 selector.send(response.responseSend) inflightResponses += (response.request.connectionId -> response) } }
send方法:
publicvoidsend(Send send) { //响应要和对应的连接绑定。 KafkaChannel channel = channelOrFail(send.destination()); try { //TODO 重要 channel.setSend(send); } catch (CancelledKeyException e) { this.failedSends.add(send.destination()); close(channel); } } publicvoidsetSend(Send send) { if (this.send != null) thrownew IllegalStateException("Attempt to begin a send operation with prior send operation still in progress."); this.send = send; //TODO 关键的代码出来了,这儿注册了OP_WRITE事件 //这样后面如果监听到这个事件就可以往客户端发送消息了 this.transportLayer.addInterestOps(SelectionKey.OP_WRITE); }
- 总结 -
到目前为止,我们总结一下本小节我们看到的代码,每个Processor线程不断的从队列里获取响应,然后把响应和KafkaChannel绑定起来,让SocketChannel监听OP_WRITE事件,为后面向客户端发送响应做好初始化工作。所有的准备工作都准备好了,下一讲我们再具体分析一下响应消息是如何发送给客户端的?
大家加油!!!
![ab11d3ad32a1bf2af159e1d7ef9b4371.png](https://img-blog.csdnimg.cn/img_convert/ab11d3ad32a1bf2af159e1d7ef9b4371.png)