实现WebSocket通信客户端原理
override fun newWebSocket(request: Request, listener: WebSocketListener): WebSocket {
val webSocket = RealWebSocket(request, listener, Random(), pingIntervalMillis.toLong())
// 使用HTTP协议连接
webSocket.connect(this)
return webSocket
}
fun connect(client: OkHttpClient) {
val webSocketClient = client.newBuilder()
.eventListener(EventListener.NONE)
.protocols(ONLY_HTTP1)
.build()
val request = originalRequest.newBuilder()
.header("Upgrade", "websocket")
.header("Connection", "Upgrade")
.header("Sec-WebSocket-Key", key)
.header("Sec-WebSocket-Version", "13")
.build()
call = RealCall.newRealCall(webSocketClient, request, forWebSocket = true)
call!!.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
val exchange = response.exchange
val streams: Streams
try {
// 检查WebSocket是否创建成功
checkUpgradeSuccess(response, exchange)
// 创建WebSocket流
streams = exchange!!.newWebSocketStreams()
} catch (e: IOException) {
exchange?.webSocketUpgradeFailed()
failWebSocket(e, response)
response.closeQuietly()
return
}
// 处理所有Web套接字消息。
try {
val name = "OkHttp WebSocket ${request.url.redact()}"
// 初始化
initReaderAndWriter(name, streams)
// 实现WebSocketListener开始操作
listener.onOpen(this@RealWebSocket, response)
// 异步循环读取响应
loopReader()
} catch (e: Exception) {
failWebSocket(e, null)
}
}
override fun onFailure(call: Call, e: IOException) {
failWebSocket(e, null)
}
})
}
fun initReaderAndWriter(name: String, streams: Streams) {
synchronized(this) {
this.streams = streams
this.writer = WebSocketWriter(streams.client, streams.sink, random)
this.executor = ScheduledThreadPoolExecutor(1, threadFactory(name, false))
if (pingIntervalMillis != 0L) {
executor!!.scheduleAtFixedRate(
PingRunnable(), pingIntervalMillis, pingIntervalMillis, MILLISECONDS)
}
if (messageAndCloseQueue.isNotEmpty()) {
runWriter() // 连接后发送异步消息
}
}
reader = WebSocketReader(streams.client, streams.source, this)
}
fun loopReader() {
while (receivedCloseCode == -1) {
// 多次调用onRead*方法
reader!!.processNextFrame()
}
}
fun processNextFrame() {
readHeader()
if (isControlFrame) {
readControlFrame()
} else {
// 执行WebSocketListener的onRead方法
readMessageFrame()
}
}
@Synchronized private fun send(data: ByteString, formatOpcode: Int): Boolean {
// 在我们失败或排队关闭帧后不要发送新帧。
if (failed || enqueuedClose) return false
// 如果此帧溢出缓冲区,请拒绝它并关闭Web套接字。
if (queueSize + data.size > MAX_QUEUE_SIZE) {
close(CLOSE_CLIENT_GOING_AWAY, null)
return false
}
// 将消息帧排入队列。
queueSize += data.size.toLong()
messageAndCloseQueue.add(Message(formatOpcode, data))
runWriter() // // 连接后发送异步消息
return true
}
private fun runWriter() {
assert(Thread.holdsLock(this))
// 只有一个线程的循环任务线程池
executor?.execute(writerRunnable)
}
总结
OkHttp的WebSocket实现是将请求和响应分别放在了一个异步线程中,下一个请求不需要等待上一个响应返回就可以发送,请求是通过只有一个线程的循环任务线程池发送的,响应在Http异步请求的线程中获取。