雨露均沾的OkHttp—WebSocket长连接(源码篇)

前言

雨露均沾的OkHttp—WebSocket长连接(使用篇)
雨露均沾的OkHttp—WebSocket长连接(源码篇)

上期我们熟悉了OkHttp中实现WebSocket长连接的接入,并且可以通过OkHttp官方的MockWebSocket服务来模拟服务端,实现整个流程。

今天我们就来说下具体OkHttp中是怎么实现这些功能的呢?相信看过这篇文章你也能深刻了解WebSocket这个协议。

使用回顾

简单贴下WebSocket使用方法,方便下面解析:

       //初始化
        mClient = new OkHttpClient.Builder()
                .pingInterval(10, TimeUnit.SECONDS)
                .build();
        Request request = new Request.Builder()
                .url(mWbSocketUrl)
                .build();
        mWebSocket = mClient.newWebSocket(request, new WsListener());
        
        //收到消息回调
        @Override
        public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
   
            super.onMessage(webSocket, text);
            Log.e(TAG,"收到消息!");
            onWSDataChanged(DATE_NORMAL, text);
        }        
        
        //发送消息
        mWebSocket.send(message);
        
        //主动关闭连接
        mWebSocket.close(code, reason);

源码解析

WebSocket整个流程无非三个功能:连接,接收消息,发送消息。下面我们就从这三个方面分析下具体是怎么实现的。

连接

通过上面的代码我们得知,WebSocket连接是通过newWebSocket方法。直接点进去看这个方法:

  override fun newWebSocket(request: Request, listener: WebSocketListener): WebSocket {
   
    val webSocket = RealWebSocket(
        taskRunner = TaskRunner.INSTANCE,
        originalRequest = request,
        listener = listener,
        random = Random(),
        pingIntervalMillis = pingIntervalMillis.toLong(),
        extensions = null, // Always null for clients.
        minimumDeflateSize = minWebSocketMessageToCompress
    )
    webSocket.connect(this)
    return webSocket
  }

这里做了两件事:

  • 初始化RealWebSocket,主要是设置了一些参数(比如pingIntervalMillis心跳包时间间隔,还有监听事件之类的)
  • connect方法进行WebSocket连接

继续查看connect方法:

connect(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")
        .header("Sec-WebSocket-Extensions", "permessage-deflate")
        .build()
    call = RealCall(webSocketClient, request, forWebSocket = true)
    call!!.enqueue(object : Callback {
   
      override fun onResponse(call: Call, response: Response) {
   
        
        //得到数据流
        val streams: Streams
        try {
   
          checkUpgradeSuccess(response, exchange)
          streams = exchange!!.newWebSocketStreams()
        } 
        
        //***
        // Process all web socket messages.
        try {
   
          val name = "$okHttpName WebSocket ${
     request.url.redact()}"
          initReaderAndWriter(name, streams)
          listener.onOpen(this@RealWebSocket, response)
          loopReader()
        } catch (e: Exception) {
   
          failWebSocket(e, null)
        }
      }
    })
  }

上一篇使用篇文章中说过,Websocket连接需要一次Http协议的握手,然后才能把协议升级成WebSocket。所以这段代码就体现出这个功能了。

首先就new了一个用来进行Http连接的request,其中Header的参数就表示我要进行WebSocket连接了,参数解析如下:

  • Connection:Upgrade,表示客户端要连接升级
  • Upgrade:websocket, 表示客户端要升级建立Websocket连接
  • Sec-Websocket-Key:key, 这个key是随机生成的,服务器会通过这个参数验证该请求是否有效
  • Sec-WebSocket-Version:13, websocket使用的版本,一般就是13
  • Sec-webSocket-Extension:permessage-deflate,客户端指定的一些扩展协议,比如这里permessage-deflate就是WebSocket的一种压缩协议。

Header设置好之后,就调用了callenqueue方法,这个方法大家应该都很熟悉吧,OkHttp里面对于Http请求的异步请求就是这个方法。
至此,握手结束,服务器返回响应码101,表示协议升级。

然后我们继续看看获取服务器响应之后又做了什么?
在发送Http请求成功之后,onResponse响应方法里面主要表现为四个处理逻辑:

  • Http流转换成WebSocket流,得到Streams对象,这个流后面会转化成输入流和输出流,也就是进行发送和读取的操作流
  • listener.onOpen(this@RealWebSocket, response),回调了接口WebSocketListeneronOpen方法,告诉用户WebSocket已经连接
  • initReaderAndWriter(name, streams)
  • loopReader()

前两个逻辑还是比较好理解,主要是后两个方法,我们分别解析下。
首先看initReaderAndWriter方法。

initReaderAndWriter(初始化输入流输出流)
  //RealWebSocket.kt

  @Throws(IOException::class)
  fun initReaderAndWriter(name: String, streams: Streams) {
   
    val extensions = this.extensions!!
    synchronized(this) {
   
      //***
      
      //写数据,发送数据的工具类
      this.writer = WebSocketWriter()
      
      //设置心跳包事件
      if (pingIntervalMillis != 0L) {
   
        val pingIntervalNanos = MILLISECONDS.toNanos(pingIntervalMillis)
        taskQueue.schedule("
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值