Android websocket

71 阅读3分钟

WebSocket 是一个网络通信协议,它提供了一个全双工通信渠道,通过一个单一的长期连接允许服务器主动向客户端发送数据。这项技术是 HTML5 的一部分,意在被整合到所有现代浏览器中。WebSocket 协议在2008年被提出,并在2011年成为国际标准。

WebSocket 的主要特点包括:

  1. 全双工通信:在WebSocket连接中,客户端和服务器都可以在任何时候发送数据,不需要等待对方的指令。这类似于电话通话,双方可以同时说话。
  2. 持久连接:一旦WebSocket连接建立,它会保持开放状态,直到客户端或服务器决定关闭连接。
  3. 实时性:由于WebSocket提供了实时的双向通信能力,它非常适合需要快速响应的应用,如在线游戏、实时聊天应用和股票交易更新。
  4. 基于TCP:WebSocket 连接是基于TCP协议的,握手可靠,提供了可靠的数据传输服务。
  5. 头部开销小:与HTTP相比,WebSocket的数据传输头部开销较小,这使得它在传输大量数据时更加高效。
  6. 跨域通信:WebSocket 默认支持跨域通信,但也可以设置跨域策略。

WebSocket 的使用场景:

  • 聊天应用:如即时通讯软件,需要实时显示消息。
  • 游戏:多人在线游戏需要实时的数据交换。
  • 股票行情:实时更新股票价格和市场动态。
  • 协作工具:如实时代码编辑器或文档编辑工具。
  • 物联网(IoT) :设备与服务器之间的实时数据交换。

WebSocket 的基本概念:

  • 握手:在WebSocket通信开始之前,客户端和服务器通过HTTP请求进行握手。如果服务器支持WebSocket,它将响应一个Upgrade头部,然后将TCP连接升级到WebSocket连接。
  • :WebSocket 数据传输是通过帧进行的,每个帧可以包含一个或多个消息。
  • 关闭连接:WebSocket 连接可以通过发送一个关闭帧来关闭,这是一个有秩序的过程,双方都有机会发送最后一个消息并清理资源。

okhttps 框架实现 Android Websocket

ok.zhxu.cn/v4/websocke…



class WebSocketUtils {

    private var webSocket: WebSocket? = null
    private lateinit var client: OkHttpClient

    companion object {
        val instance: WebSocketUtils by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { WebSocketUtils() }
    }

    fun init() {

        client = OkHttpClient()
//        val token: String =
//            GlobalApp.instance.companyInfoBean?.access_token
//                ?: ""//SharedPreferencesUtil.getInfo(SharedPreferencesUtil.TOKEN)
        val request: Request = Request.Builder().url(WSS_DOMAIN).build()
//-   WebSocket 通过 `ws://`(非加密)或 `wss://`(加密)协议标识符进行通信,服务器网址就是 URL。
//-   WebSocket API 相对简单,例如在客户端使用 `new WebSocket('ws://localhost:8080')` 即可创建一个新的连接
        webSocket = client.newWebSocket(request, object : WebSocketListener() {
            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                super.onMessage(webSocket, bytes)
                LogUtils.d("----websocket----onMessage $bytes")
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                super.onMessage(webSocket, text)
                LogUtils.d("----websocket----onMessage str $text")
            }

            override fun onOpen(webSocket: WebSocket, response: Response) {
                super.onOpen(webSocket, response)
                LogUtils.d("----websocket----onOpen response $response")
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                super.onFailure(webSocket, t, response)
                LogUtils.d("----websocket----onFailure response ${t.message}")
            }

            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosed(webSocket, code, reason)
                LogUtils.d("----websocket----onClosed reason $reason code $code")
            }

            override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosing(webSocket, code, reason)
                LogUtils.d("----websocket----onClosing reason $reason code $code")
            }
        })
    }

    fun connect() {
    //封装成 stomp 协议的格式进行通讯
        val token: String =
            GlobalApp.instance.companyInfoBean?.access_token ?: ""
        webSocket?.apply {
            val pingSecs = 2
            val pongSecs = 2
            val cHeaders: MutableList<Header> = ArrayList()
            cHeaders.add(Header(Header.VERSION, "1.1"))
            cHeaders.add(
                Header(
                    Header.HEART_BEAT,
                    (pingSecs * 1000).toString() + "," + pongSecs * 1000
                )
            )
            cHeaders.add(Header(DZ_AUTH, "$BEARER $token"))
            val msg = MsgCodecImpl().encode(Message(Commands.CONNECT, cHeaders, null))
            LogUtils.e(msg)
            send(msg)
        }
    }

    fun sendByteString(msg: ByteString) {
        webSocket?.apply {
            send(msg)
        }
    }

    fun close(code: Int = 0, reson: String) {
        webSocket?.apply {
            close(code, reson)
        }
    }

    fun subMessage(userId:String) {
        webSocket?.apply {
            val isAutoAck = true
            val headers: MutableList<Header> = java.util.ArrayList()
            headers.add(Header(Header.ID, UUID.randomUUID().toString()))
            headers.add(Header(Header.DESTINATION, "/user/$userId/queue/message"))
            val ackNotAdded = true
//            if (this.headers != null) {
//                for (header in this.headers) {
//                    if (Header.ACK == header.key) {
//                        ackNotAdded = false
//                    }
//                    val key = header.key
//                    if (Header.ID != key && Header.DESTINATION != key) {
//                        headers.add(header)
//                    }
//                }
//            }
            if (ackNotAdded) {
                headers.add(
                    Header(
                        Header.ACK,
                        if (isAutoAck) Stomp.AUTO_ACK else Stomp.CLIENT_ACK
                    )
                )
            }

            val msg = MsgCodecImpl().encode(Message(Commands.SUBSCRIBE, headers, null))
            LogUtils.e(msg)
            send(msg)


//            val headers1: MutableList<Header> = java.util.ArrayList()
//            headers1.add(Header(Header.ID, UUID.randomUUID().toString()))
//            headers1.add(Header(Header.DESTINATION, "/user/$userId/queue/workMobile"))

//            val msg1 = MsgCodecImpl().encode(Message(Commands.SUBSCRIBE, headers1, null))
//            LogUtils.e(msg1)
//            send(msg1)
        }

    }
}