okhttp中websocket的使用


参考链接: https://www.cnblogs.com/plokmju/p/okhttp_weisocket.html

websocket是什么

一种客户端与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。
在这里插入图片描述

websocket能做什么

WebSocket 与 HTTP/2 一样,其实都是为了解决 HTTP/1.1 的一些缺陷而诞生的,而 WebSocket 针对的就是「请求-应答」这种"半双工"的模式的通信缺陷。

「请求-应答」是"半双工"的通信模式,数据的传输必须经过一次请求应答,这个完整的通信过程,通信的同一时刻数据只能在一个方向上传递。它最大的问题在于,HTTP 是一种被动的通信模式,服务端必须等待客户端请求才可以返回数据,无法主动向客户端发送数据。

这也导致在 WebSocket 出现之前,一些对实时性有要求的服务,通常是基于轮询(Polling)这种简单的模式来实现。轮询就是由客户端定时发起请求,如果服务端有需要传递的数据,可以借助这个请求去响应数据。

轮询的缺点也非常明显,大量空闲的时间,其实是在反复发送无效的请求,这显然是一种资源的损耗。

虽然在之后的 HTTP/2、HTTP/3 中,针对这种半双工的缺陷新增了 Stream、Server Push 等特性,但是「请求-应答」依然是 HTTP 协议主要的通信方式。

WebSocket 协议是由 HTML5 规范定义的,原本是为了浏览器而设计的,可以避免同源的限制,浏览器可以与任意服务端通信,现代浏览器基本上都已经支持 WebSocket。

虽然 WebSocket 原本是被定义在 HTML5 中,但它也适用于移动端,尽管移动端也可以直接通过 Socket 与服务端通信,但借助 WebSocket,可以利用 80(HTTP) 或 443(HTTPS)端口通信,有效的避免一些防火墙的拦截。
在这里插入图片描述
WebSocket 的特性:

  1. WebSocket 建立在 TCP 协议之上,对服务器端友好;
  2. 默认端口采用 80 或 443,握手阶段采用 HTTP 协议,不容易被防火墙屏蔽,能够通过各种 HTTP 代理服务器;;
  3. 传输数据相比 HTTP 更轻量,少了 HTTP Header,性能开销更小,通信更高效;
  4. 通过 MESSAGE 帧发送数据,可以发送文本或者二进制数据,如果数据过大,会被分为多个 MESSAGE 帧发送;
  5. WebSocket 沿用 HTTP 的 URL,协议标识符是 “ws” 或 “wss”。

WebSocket之OkHttp

1.建立 WebSocket 连接
借助 OkHttp 可以很轻易的实现 WebSocket,它的 OkHttpClient 中,提供了 newWebSocket() 方法,可以直接建立一个 WebSocket 连接并完成通信。

fun connectionWebSockt(hostName:String,port:Int){
  val httpClient = OkHttpClient.Builder()
      .pingInterval(40, TimeUnit.SECONDS) // 设置 PING 帧发送间隔
      .build()
  val webSocketUrl = "ws://${hostName}:${port}"
  val request = Request.Builder()
      .url(webSocketUrl)
      .build()
  httpClient.newWebSocket(request, object:WebSocketListener(){
    // ...
  })
}

2.使用 WebSocketListener
WebSocketListener 是一个抽象类,其中定义了比较多的方法,借助这些方法回调,就可以完成对 WebSocket 的所有操作。

var mWebSocket : WebSocket? = null
fun connectionWebSockt(hostName:String,port:Int){
  // ...
  httpClient.newWebSocket(request, object:WebSocketListener(){
    override fun onOpen(webSocket: WebSocket, response: Response) {
      super.onOpen(webSocket, response)
      // WebSocket 连接建立
      mWebSocket = webSocket
    }

    override fun onMessage(webSocket: WebSocket, text: String) {
      super.onMessage(webSocket, text)
      // 收到服务端发送来的 String 类型消息
    }

    override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
      super.onClosing(webSocket, code, reason)
      // 收到服务端发来的 CLOSE 帧消息,准备关闭连接
    }

    override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
      super.onClosed(webSocket, code, reason)
      // WebSocket 连接关闭
    }

    override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
      super.onFailure(webSocket, t, response)
      // 出错了
    }
  })
}

在 WebSocketListener 的所有方法回调中,都包含了 WebSocket 类型的对象,它就是当前建立的 WebSocket 连接实体,通过它就可以向服务端发送 WebSocket 消息。

如果需要在其他时机发送消息,可以在回调 onOpen() 这个建立连接完成的时机,保存 webSocket 对象,以备后续使用。

OkHttp 中的 WebSocket 本身是一个接口,它的实现类是 RealWebSocket,它定义了一些发送消息和关闭连接的方法:

send(text):发送 String 类型的消息;
send(bytes):发送二进制类型的消息;
close(code, reason):主动关闭 WebSocket 连接;
利用这些回调和 WebSocket 提供的方法,我们就可以完成 WebSocket 通信了。

WebSocket 保活

WebSocket 建立的连接就是我们所谓的长连接,每个连接对于服务器而言,都是资源。但服务器倾向于在一个连接长时间没有消息往来的时候,将其关闭。而 WebSocket 的保活,实际上就是定时向服务端发送一个空消息,来保证连接不会被服务端主动断开。
那么我们自己写个定时器,固定间隔向服务端 mWebSocket.send() 一个消息,就可以达到保活的目的,但这样发送的其实是 MESSAGE 帧数据,如果使用 WebSocket 还有更优雅的方式。
前文我们提到,WebSocket 采用二进制帧的形式传输数据,其中就包括了用于保活的 PING 帧,而 OkHttp 只需要简单的配置,就可以自动的间隔发送 PING 帧和数据。
我们只需要在构造 OkHttpClient 的时候,通过 pingInterval() 设置 PING 帧发送的时间间隔,它的默认值为 0,所以不设置不发送。

val httpClient = OkHttpClient.Builder()
      .pingInterval(40, TimeUnit.SECONDS) // 设置 PING 帧发送间隔
      .build()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值