在上一篇ConnectInterceptor,介绍了Http的连接过程。本篇将介绍Http如何发送和接收数据,在OkHttp中,CallServerInterceptor用来发送和接收数据。接下来以Http2.0,介绍数据发送接收的大体过程,在Http2.0协议中,数据会被封装成数据帧进行发送。
CallServerInterceptor概览:
Http2Connection:表示了一个Http连接,包含了Http2Writer,其负责将数据帧发送给服务器,Http2Reader其负责接收服务发送的数据。
Http2Stream:每一个Http2Stream都与一个Http请求相关联,其包含一个streamId,在发送和接收数据时,数据帧都会含有此id,用来区别不同的Http请求。
FramingSink,它将要发送的数据以Http2.0数据帧的形式交给Http2Writer,具体过程在2、发送RequestBody中介绍。
FramingSource,它接收Http2Reader传递的数据帧,并交付Response,具体过程在4、接收ResponseBody中介绍。
CallServerInterceptor实现了Http的通信过程,其主要分为如下4步:
1、发送RequestHeader;2、发送RequestBody;3接收ResponseHeader;4、接收ResponseBody。
接下来从代码角度分析以上4个步骤(以Http2.0为例)
代码分析:
1、发送RequestHeader
CallServerInterceptor的intercept代码如下:
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.exchange!!
val request = realChain.request
val requestBody = request.body
val sentRequestMillis = System.currentTimeMillis()
//发送请求头
exchange.writeRequestHeaders(request)
var invokeStartEvent = true
var responseBuilder: Response.Builder? = null
......
return response
}
OkHttp会调用writeRequestHeaders方法,发送请求头,其代码如下:
fun writeRequestHeaders(request: Request) {
try {
eventListener.requestHeadersStart(call)
codec.writeRequestHeaders(request)
eventListener.requestHeadersEnd(call, request)
} catch (e: IOException) {
eventListener.requestFailed(call, e)
trackFailure(e)
throw e
}
}
此步会调用Http2ExchangeCodec的writeRequestHeaders方法,其代码如下:
override fun writeRequestHeaders(request: Request) {
if (stream != null) return
val hasRequestBody = request.body != null
val requestHeaders = http2HeadersList(request)
//此方法作用:1、新建Http2Stream,其负责发送和接收服务器的数据
//2、发送请求头
stream = http2Connection.newStream(requestHeaders, hasRequestBody)
// We may have been asked to cancel while creating the new stream and sending the request
// headers, but there was still no stream to close.
if (canceled) {
stream!!.closeLater(ErrorCode.CANCEL)
throw IOException("Canceled")
}
stream!!.readTimeout().timeout(chain.readTimeoutMillis.toLong(), TimeUnit.MILLISECONDS)
stream!!.writeTimeout().timeout(chain.writeTimeoutMillis.toLong(), TimeUnit.MILLISECONDS)
}
接下来会调用Http2Connection的newStream方法创建一个Http2Stream,以发送和接收数据,并发送请求头。newStream方法的代码如下:
fun newStream(
requestHeaders: List<Header>,
out: Boolean
): Http2Stream {
//调用重载方法,注意此方法的第一个参数为0
return newStream(0, requestHeaders, out)
}
@Throws(IOException::class)
private fun newStream(
associatedStreamId: Int,
requestHeaders: List<Header>,
out: Boolean
): Http2Stream {
val outFinished = !out
val inFinished = false
val flushHeaders: Boolean
val stream: Http2Stream
val streamId: Int
//此同步块使用writer作为锁,保证了某一时刻,只有一个线程能发送请求头。请求头会被封装成数据帧发送,而发送数据帧不是一个“原子”操作,其有2步,第一步先发送帧头,第二步发送帧体。因此需要锁来保证这2步可以一起执行。
//Http2.0存在复用连接的情况,即某一时刻,可能有多个线程发送请求头,因此,在此处需要确保线程安全。
//同时确保streamId的唯一性
synchronized(writer) {
synchronized(this) {
if (nextStreamId > Int.MAX_VALUE / 2) {
shutdown(REFUSED_STREAM)
}
if (isShutdown) {
throw ConnectionShutdownException()
}
//区别不同的Http请求,因为Http2.0会复用连接,即使用同一个连接,发送多个Http请求的数据
streamId = nextStreamId
nextStreamId += 2
//创建Http2Stream
stream = Http2Stream(streamId, this, outFinished, inFinished, null)
flushHeaders = !out ||
writeBytesTotal >= writeBytesMaximum ||
stream.writeBytesTotal >= stream.writeBytesMaximum
if (stream.isOpen) {
//记录创建的stream
streams[streamId] = stream
}
}
//此形参的值为0,验证为true,发送请求头
if (associatedStreamId == 0) {
writer.headers(outFinished, streamId, requestHeaders)
} else {
require(!client) { "client streams shouldn't have associated stream IDs" }
// HTTP/2 has a PUSH_PROMISE frame.
writer.pushPromise(associatedStreamId, streamId, requestHeaders)
}
}
if (flushHeaders) {
writer.flush()
}
return stream
}
在Http2Stream创建完成后,接下来会调用header方法,发送请求头,其代码如下:
fun headers(
outFinished: Boolean,
streamId: Int,
headerBlock: List<Header>
) {
if (closed) throw IOException("closed")
//对请求头进行压缩,以减少发送数据的大小
hpackWriter.writeHeaders(headerBlock)
val byteCount = hpackBuffer.size
val length = minOf(maxFrameSize.toLong(), byteCount)
var flags = if (byteCount == length) FLAG_END_HEADERS else 0
if (outFinished) flags = flags or FLAG_END_STREAM
//根据Http2.0协议要先发送一个标识,以表示要发送数据的类型。这里表示发送一个请求头
frameHeader(
streamId = streamId,
length = length.toInt(),
type = TYPE_HEADERS,
flags = flags
)
//将header的真实数据发送给服务器,sink封装了socket的输出流
sink.write(hpackBuffer, length)
if (byteCount > length) writeContinuationFrames(streamId, byteCount - length)
}
这样,请求头的发送流程就结束了,接下发送请求体
2、发送RequestBody
override fun intercept(chain: Interceptor.Chain): Response {
......
//1、发送请求头
exchange.writeRequestHeaders(request)
//2、请求体不为空,则发送请求体
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
//检查是否需要 服务器先返回100状态码,而后在决定是否发送请求体
......
//不需要服务器返回100状态码
if (responseBuilder == null) {
//是否是全双工发送请求体(一边发生请求体,一边接受服务器数据)
if (requestBody.isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
exchange.flushRequest()
val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
requestBody.writeTo(bufferedRequestBody)
} else {
//将Http2Stream中的FramingSink进行封装为bufferedRequestBody
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
//将请求体发送给服务器
requestBody.writeTo(bufferedRequestBody)
bufferedRequestBody.close()
}
}
......
}
OKHttP会调用createRequestBody方法对数据发送器FramingSink进行封装,然后调用RequestBody的writeTo方法发送请求体,createRequestBody方法代码如下:
fun createRequestBody(request: Request, duplex: Boolean): Sink {
this.isDuplex = duplex
val contentLength = request.body!!.contentLength()
eventListener.requestBodyStart(call)
//获取FramingSink
val rawRequestBody = codec.createRequestBody(request, contentLength)
//将FramingSink封装到RequestBodySink
return RequestBodySink(rawRequestBody, contentLength)
}
override fun createRequestBody(request: Request, contentLength: Long): Sink {
//Http2Stream中的FramingSink
return stream!!.getSink()
}
以上为将FramingSink封装到RequestBodySink,接下来,会调用RequestBody的writeTo方法发送真正的请求体数据,此方法会去调用RequestBodySink的write方法,其代码如下:
private inner class RequestBodySink(
delegate: Sink,
/** The exact number of bytes to be written, or -1L if that is unknown. */
private val contentLength: Long
) : ForwardingSink(delegate) {
......
@Throws(IOException::class)
override fun write(source: Buffer, byteCount: Long) {
......
try {
//发送请求体
super.write(source, byteCount)
this.bytesReceived += byteCount
} catch (e: IOException) {
throw complete(e)
}
}
可以看出,此方法会调用ForWardingSInk的write方法,而在这个方法中,又回去调用delegate(FramingSink)的write方法,代码如下:
override fun write(source: Buffer, byteCount: Long) = delegate.write(source, byteCount)
由此可知,其最后会调用FramingSink的write方法,此方法的代码如下:
override fun write(source: Buffer, byteCount: Long) {
this@Http2Stream.assertThreadDoesntHoldLock()
//先将数据写到sendBuffer中
sendBuffer.write(source, byteCount)
while (sendBuffer.size >= EMIT_BUFFER_SIZE) {
//发送数据到服务器
emitFrame(false)
}
}
接下来,FramingSink会先将请求体写到sendBuffer中,然后调用emitFrame方法发送请求头,其代码如下:
private fun emitFrame(outFinishedOnLastFrame: Boolean) {
val toWrite: Long
val outFinished: Boolean
synchronized(this@Http2Stream) {
writeTimeout.enter()
try {
//检查是否发送结束,服务器是否关闭、已发送的数据是否超过可发送的最大数据(窗口)
while (writeBytesTotal >= writeBytesMaximum &&
!finished &&
!closed &&
errorCode == null) {
waitForIo() // Wait until we receive a WINDOW_UPDATE for this stream.
}
} finally {
writeTimeout.exitAndThrowIfTimedOut()
}
//计算可以发送多少数据
toWrite = minOf(writeBytesMaximum - writeBytesTotal, sendBuffer.size)
writeBytesTotal += toWrite
outFinished = outFinishedOnLastFrame && toWrite == sendBuffer.size && errorCode == null
}
writeTimeout.enter()
try {
//发送数据
connection.writeData(id, outFinished, sendBuffer, toWrite)
} finally {
writeTimeout.exitAndThrowIfTimedOut()
}
}
此过程会先对发送数据的大小,连接是否关闭进行检查,然后,调用writeData方法进行数据的发送,代码如下:
fun writeData(
streamId: Int,
outFinished: Boolean,
buffer: Buffer?,
byteCount: Long
) {
//检查是否可以发送数据(已发送数据大小是否超过窗口大小)
var byteCount = byteCount
while (byteCount > 0L) {
var toWrite: Int
synchronized(this@Http2Connection) {
try {
while (writeBytesTotal >= writeBytesMaximum) {
......
this@Http2Connection.wait() // Wait until we receive a WINDOW_UPDATE.
}
} catch (e: InterruptedException) {
Thread.currentThread().interrupt() // Retain interrupted status.
throw InterruptedIOException()
}
//计算可以发送数据的大小
toWrite = minOf(byteCount, writeBytesMaximum - writeBytesTotal).toInt()
toWrite = minOf(toWrite, writer.maxDataLength())
writeBytesTotal += toWrite.toLong()
}
byteCount -= toWrite.toLong()
//调用Http2Writer的data方法发送数据
writer.data(outFinished && byteCount == 0L, streamId, buffer, toWrite)
}
}
此过程会再次计算可发送数据的大小,然后,调用Http2Writer的data方法发送数据,代码如下:
fun data(outFinished: Boolean, streamId: Int, source: Buffer?, byteCount: Int) {
if (closed) throw IOException("closed")
var flags = FLAG_NONE
if (outFinished) flags = flags or FLAG_END_STREAM
//以数据帧的形式发送数据
dataFrame(streamId, flags, source, byteCount)
}
@Throws(IOException::class)
fun dataFrame(streamId: Int, flags: Int, buffer: Buffer?, byteCount: Int) {
//发送帧头
frameHeader(
streamId = streamId,
length = byteCount,
type = TYPE_DATA,
flags = flags
)
//发送帧体
if (byteCount > 0) {
sink.write(buffer!!, byteCount.toLong())
}
}
至此,请求体的发送流程就完成了。
3、接收ResponseHeader
override fun intercept(chain: Interceptor.Chain): Response {
......
//1、发送请求头
exchange.writeRequestHeaders(request)
//2、发送请求体
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
......
//3、接收响应头
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
exchange.responseHeadersStart()
invokeStartEvent = false
}
}
var response = responseBuilder
.request(request)
.handshake(exchange.connection.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
......
}
OkHttp会调用readResponseHeaders方法,以阻塞的方式读取响应头,然后,将响应头封装到ResponseBuilder中,readResponseHeaders方法代码如下:
fun readResponseHeaders(expectContinue: Boolean): Response.Builder? {
try {
val result = codec.readResponseHeaders(expectContinue)
result?.initExchange(this)
return result
} catch (e: IOException) {
eventListener.responseFailed(call, e)
trackFailure(e)
throw e
}
}
在此方法中,会调用Http2ExchangeCodec的readResponseHeaders方法接收响应头,方法代码如下:
override fun readResponseHeaders(expectContinue: Boolean): Response.Builder? {
val headers = stream!!.takeHeaders()
val responseBuilder = readHttp2HeadersList(headers, protocol)
return if (expectContinue && responseBuilder.code == HTTP_CONTINUE) {
null
} else {
responseBuilder
}
}
此方法会调用Http2Stream的takeHeaders方法接收服务端发送的响应头,此接收方法会阻塞线程,直到接收到响应头。然后,调用readHttpHeaderList方法,利用相应头创建一个ResponseBuilder(大体过程为,添加响应头,然后新建一个ResponseBuilder),在此就不对此方法展开分析。主要分析,响应头的获取过程,takeHeader方法的代码如下:
@Synchronized @Throws(IOException::class)
fun takeHeaders(): Headers {
readTimeout.enter()
try {
while (headersQueue.isEmpty() && errorCode == null) {
waitForIo()
}
}
......
}
在此方法中,循环检测headerQueue是否为null,当headerQueue不为null时,就表示接收到了响应头。(此headersQueue存在于Http2Stream中的)。可以看到此方法是一个同步方法,锁为Http2Stream对象。可以看出此方法类似“生产者消费者”模型中的消费者。生产者其实在上一篇文章的文末出现了,它是Http2Connection中的一个读取服务端数据的线程,在这里进行详细讲解。代码如下:
inner class ReaderRunnable internal constructor(
internal val reader: Http2Reader
) : Http2Reader.Handler, () -> Unit {
//这里实现了Handler接口,Handler接口的作用为处理接收到数据帧,后面会用到。
override fun invoke() {
var connectionErrorCode = ErrorCode.INTERNAL_ERROR
var streamErrorCode = ErrorCode.INTERNAL_ERROR
var errorException: IOException? = null
try {
reader.readConnectionPreface(this)
//读取服务端数据
while (reader.nextFrame(false, this)) {
}
......
}
}
此线程中,存在一个while循环,它会调用Http2Reader的nextFrame方法循环读取服务端的数据,其代码如下:
fun nextFrame(requireSettings: Boolean, handler: Handler): Boolean {
try {
source.require(9) // Frame header size.
} catch (e: EOFException) {
return false // This might be a normal socket close.
}
//读取帧头
val length = source.readMedium()
if (length > INITIAL_MAX_FRAME_SIZE) {
throw IOException("FRAME_SIZE_ERROR: $length")
}
val type = source.readByte() and 0xff
val flags = source.readByte() and 0xff
val streamId = source.readInt() and 0x7fffffff // Ignore reserved bit.
if (logger.isLoggable(FINE)) logger.fine(frameLog(true, streamId, length, type, flags))
if (requireSettings && type != TYPE_SETTINGS) {
throw IOException("Expected a SETTINGS frame but was ${formattedType(type)}")
}
//根据帧头的类型处理帧体
when (type) {
TYPE_DATA -> readData(handler, length, flags, streamId)
TYPE_HEADERS -> readHeaders(handler, length, flags, streamId)
TYPE_PRIORITY -> readPriority(handler, length, flags, streamId)
TYPE_RST_STREAM -> readRstStream(handler, length, flags, streamId)
TYPE_SETTINGS -> readSettings(handler, length, flags, streamId)
TYPE_PUSH_PROMISE -> readPushPromise(handler, length, flags, streamId)
TYPE_PING -> readPing(handler, length, flags, streamId)
TYPE_GOAWAY -> readGoAway(handler, length, flags, streamId)
TYPE_WINDOW_UPDATE -> readWindowUpdate(handler, length, flags, streamId)
else -> source.skip(length.toLong()) // Implementations MUST discard frames of unknown types.
}
return true
}
在此方法中,会读取服务端发送的数据帧,首先,会读取帧头,提取出帧头中的数据类型和streamId,然后,根据帧的类型,调用不同的方法处理帧中的真正数据。在这里,我们主要分析”“TYPE_HEADERS”响应头类型的数据,若接收到的是响应头数据,会调用readHeaders方法进行处理,代码如下:
private fun readHeaders(handler: Handler, length: Int, flags: Int, streamId: Int) {
if (streamId == 0) throw IOException("PROTOCOL_ERROR: TYPE_HEADERS streamId == 0")
//读取响应头
val headerBlock = readHeaderBlock(headerBlockLength, padding, flags, streamId)
//处理响应头
handler.headers(endStream, streamId, -1, headerBlock)
}
此方法首先会调用readHeaderBlock方法从数据帧中读取响应头,具体读取过程不再继续分析,然后调用handler的headers方法去处理响应头数据。这里采用handler来处理数据,这样的方式可以降低代码的耦合度。此handler对象其实就是之前的ReaderRunnable。headers方法的代码如下:
override fun headers(
inFinished: Boolean,
streamId: Int,
associatedStreamId: Int,
headerBlock: List<Header>
) {
......
val stream: Http2Stream?
synchronized(this@Http2Connection) {
stream = getStream(streamId)
if (stream == null) {
......
}
}
// Update an existing stream.
stream!!.receiveHeaders(headerBlock.toHeaders(), inFinished)
}
在此方法中,首先,会根据streamId获取对应的Http2Stream,然后,调用Http2Stream的receiveHeaders方法接收响应头,其代码如下:
fun receiveHeaders(headers: Headers, inFinished: Boolean) {
this@Http2Stream.assertThreadDoesntHoldLock()
val open: Boolean
synchronized(this) {
if (!hasResponseHeaders || !inFinished) {
hasResponseHeaders = true
//添加响应头到headsQueue中
headersQueue += headers
} else {
this.source.trailers = headers
}
if (inFinished) {
this.source.finished = true
}
open = isOpen
//唤醒等待响应头的线程
notifyAll()
}
......
}
此方法首先,将得到的响应头添加到headersQueue中,然后,调用notifyAll方法唤醒正在等待响应头的线程,这里,就与之前的从headersQueue中读取响应头的代码对应上了。
4、接收ResponseBody
override fun intercept(chain: Interceptor.Chain): Response {
....
//1、发送请求头
exchange.writeRequestHeaders(request)
....
//2、发送请求体
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
......
//3、接收响应头
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
exchange.responseHeadersStart()
invokeStartEvent = false
}
}
var response = responseBuilder
.request(request)
.handshake(exchange.connection.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
......
response = if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response.newBuilder()
.body(EMPTY_RESPONSE)
.build()
} else {
//4、接收响应体
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
}
......
return response
}
OkHttp会调用openResponseBody方法来接收响应体,其代码如下:
fun openResponseBody(response: Response): ResponseBody {
try {
val contentType = response.header("Content-Type")
val contentLength = codec.reportedContentLength(response)
//获取Http2Stream中的FramingSource
val rawSource = codec.openResponseBodySource(response)
//将FramingSource封装到RealResponseBody中
val source = ResponseBodySource(rawSource, contentLength)
return RealResponseBody(contentType, contentLength, source.buffer())
} catch (e: IOException) {
eventListener.responseFailed(call, e)
trackFailure(e)
throw e
}
}
在此方法中,首先,获取Http2Stream中的FramingSource,FramingSource是用来读取服务器的数据帧的。然后,将FramingSource封装到RealResponseBody中,这样,我们在读取数据时,其实最终会调用FramingSource的read方法。read方法代码如下:
override fun read(sink: Buffer, byteCount: Long): Long {
require(byteCount >= 0L) { "byteCount < 0: $byteCount" }
while (true) {
var tryAgain = false
var readBytesDelivered = -1L
var errorExceptionToDeliver: IOException? = null
// 1. Decide what to do in a synchronized block.
synchronized(this@Http2Stream) {
readTimeout.enter()
try {
if (errorCode != null) {
// Prepare to deliver an error.
errorExceptionToDeliver = errorException ?: StreamResetException(errorCode!!)
}
if (closed) {
throw IOException("stream closed")
} else if (readBuffer.size > 0L) {
// 读取接收到的数据
readBytesDelivered = readBuffer.read(sink, minOf(byteCount, readBuffer.size))
readBytesTotal += readBytesDelivered
......
} else if (!finished && errorExceptionToDeliver == null) {
// 目前暂无数据可以读取,进行睡眠
waitForIo()
tryAgain = true
}
} finally {
readTimeout.exitAndThrowIfTimedOut()
}
}
// 2. Do it outside of the synchronized block and timeout.
// 因为无数据造成睡眠,现在因为有了数据被唤醒,因此继续读取数据
if (tryAgain) {
continue
}
......
return -1L // This source is exhausted.
}
}
在介绍此段代码之前,先介绍FramingSource中的2个类变量receiveBuffer和readbuffer,readBuffer用来接收到的数据,read方法读取的就是readbuffer中的数据;receiveBuffer只能由Http2Reader方法访问,接收的也是服务器发送来的数据,而且receiveBuffer会在合适的时间,将它自己的数据转存到readBuffer中。这样设置的好处是可以加快读取效率,即用户在读取已接收的数据readbuffer时,okhttp也可保存服务器传输来的数据receiveBuffer。
此方法为一个“消费者”,首先,检测readBuffer中是否有数据可以读取,若有则读取,若无,则进行睡眠,得到新数据的到来。在上一节,提到了ReaderRunnable,它会循环读取服务器发送的数据帧,并根据数据帧的类型进行不同的处理。此对象就可以看作是一个“生产者"。在此,接收的是响应体,因此会调用ReaderRunnable的data方法,其代码如下:
override fun data(
inFinished: Boolean,
streamId: Int,
source: BufferedSource,
length: Int
) {
......
//处理响应体数据
dataStream.receiveData(source, length)
if (inFinished) {
dataStream.receiveHeaders(EMPTY_HEADERS, true)
}
}
在此方法中,会继续调用receiveData以处理响应体数据,receiveData方法代码如下:
fun receiveData(source: BufferedSource, length: Int) {
this@Http2Stream.assertThreadDoesntHoldLock()
//调用FramingSource的receive方法
this.source.receive(source, length.toLong())
}
在此方法中,会继续调用FramingSource的receive方法,其代码如下:
internal fun receive(source: BufferedSource, byteCount: Long) {
this@Http2Stream.assertThreadDoesntHoldLock()
var byteCount = byteCount
while (byteCount > 0L) {
......
// 将服务器发送的数据读取到receiveBuffer
val read = source.read(receiveBuffer, byteCount)
if (read == -1L) throw EOFException()
byteCount -= read
var bytesDiscarded = 0L
synchronized(this@Http2Stream) {
if (closed) {
bytesDiscarded = receiveBuffer.size
receiveBuffer.clear()
} else {
//将receiveBuffer中的数据转移到readBuffer,并唤醒因receiveBuffer为空而等待的线程
val wasEmpty = readBuffer.size == 0L
readBuffer.writeAll(receiveBuffer)
if (wasEmpty) {
this@Http2Stream.notifyAll()
}
}
}
if (bytesDiscarded > 0L) {
updateConnectionFlowControl(bytesDiscarded)
}
}
}
可以看出,此方法首先,会将服务器发送的数据读取到receiveBuffer,然后,将receivBuffer中的数据再次存放到readBuffer中,并唤醒之前的“消费者”线程。
总体来说,读取响应体的过程如下图所示:
响应体由FramingSource从ReaderBuffer中读取,而ReaderBuffer中的数据来自ReceiveBuffer,ReceiveBuffer中的数据由网络线程循环读取服务器发送来的数据填充。