客户端请求发送与获取响应
在Netty
里,发送请求的过程可以分为两步:1. 将请求写到缓存队列中,2.将缓存队列中的请求进行 flush —– 调用原生的SocketChannel
进行发送。
在客户端初始化时,讲到客户端的Channel
会在Selector
上注册OP_READ
操作,当有服务端响应结果时,则触发OP_READ
事件。
请求发送
首先来看发送请求的过程:SocketChannel 有两个方法用于发送请求,write
和writeAndFlush
,其中write
用于将请求ByteBuf
放入发送队列中,writeAndFlush
则将请求发送到队列中,并把发送队列中的数据发送出去。这里以writeAndFlush
来讲解整个过程
调用writeAndFlush
方法最终会调用AbstractChannelHandlerContext.write
方法。
1 | private void write(Object msg, boolean flush, ChannelPromise promise) { |
其判断发起请求操作 channel
的对应的线程上下文中,不是则创建任务并将其扔进EventLoop
的任务队列中。
1 | private void invokeWriteAndFlush(Object msg, ChannelPromise promise) { |
这里就可以看到invokeWrite0
和invokeFlush0
两个过程:
- invokeWrite0调用链如下:
1 | HeadContext.write |
最终可以看到,write的过程是将msg
包装进Entry
然后加到outboundBuffer
中,并没有做真正的发送。
在看flush
方法:
1 | public final void flush() { |
flush方法先讲outboundBuffer
之前add
的消息标记为已发送,然后调用flush0进行真正的发送。
获取响应
当 Server 端接收到请求并处理后返回结果给Client端。Client端的NioEventLoop.Selector
会告诉客户端数据已准备好可读触发unsafe.read方法:
1 | public final void read() { |
可以看到大体流程是,先调用allocHandle分配一个ByteBuf,然后从ScoketChannel
中读取数据,触发pipeline.fireChannelRead(执行channelHandler
的channelRead
方法)方法,读取完成后再执行pipeline.fireChannelReadComplete方法(执行channelHandler
的channelRead
方法)。