Websocket
1.消息推送常见方式:轮询,长轮询,SSE,Websocket
** 轮询:指定间隔时间向服务器发送HTTP请求 **** **缺点:存在延迟,服务器压力大
** **长轮询:发出异步请求,服务器接到请求后,会阻塞请求,直到有数据或者超时才返回
** ****SSE(server-sent-event)**:基于HTTP协议,前端通过一个特殊的请求(EventSource)连接到服务器。,服务器给前端打开单向通道(只能由服务器返回前端),响应返回数据流,然后实时向前端传输数据,直到通道关闭
Websocket:是一种基于TCP连接上进行全双工通信的协议
http(超文本传输协议)是规定了客户端(如浏览器)与服务器之间传输数据的格式和通信方式 websocket也是一种规定了客户端和服务器传输数据格式和通信方式的协议,都位于OSI模型的第七层应用层
TCP协议(传输控制协议)(Transmission Control Protocol)是传输层协议,位于OSI模型的第四层。
** 全双工: 允许数据在两个方向上同时传输 **** **半双工:允许数据在两个方向上传输,但是一个时间段内只允许一个方向上传输
当浏览器向服务器发送请求以切换到 WebSocket 连接时,这个过程通常称为 WebSocket 握手。这个握手过程是基于 HTTP 协议的,因为 WebSocket 需要使用 HTTP 请求来启动连接。
以下是 WebSocket 握手的基本步骤:
- 客户端发起请求:浏览器通过发送一个特殊的 HTTP 请求到服务器来开始 WebSocket 握手。这个请求包含了
Upgrade 头部,表明客户端希望将连接从 HTTP 升级到 WebSocket。例如: - 服务器响应:如果服务器同意升级连接,它会发送一个 HTTP 响应,状态码为 101(Switching Protocols),表明它同意进行协议升级。这个响应也包含了一些额外的头部,如
Upgrade 和 Connection,以及 Sec-WebSocket-Accept,后者是服务器对客户端 Sec-WebSocket-Key 的回应。例如: - 连接建立:一旦客户端收到服务器的 101 响应,WebSocket 连接就正式建立。之后,所有的数据传输都将通过 WebSocket 协议进行,而不是 HTTP。
- 数据传输:在 WebSocket 连接建立后,服务器和客户端之间将使用 WebSocket 协议进行全双工通信。这意味着双方可以同时发送和接收数据,而不受 HTTP 请求-响应模型的限制。
总结来说,虽然 WebSocket 握手开始于一个 HTTP 请求,但一旦握手完成,所有的通信都将通过 WebSocket 协议进行,而不是 HTTP。这种设计允许 WebSocket 利用现有的 HTTP 端口(通常是 80 或 443)来建立连接,从而更容易地通过防火墙和代理服务器。
基本用法:
1.添加依赖:
2.创建WebSocket监听器继承自WebSocketListener,重写四个方法
3.创建WebSocket
心跳的作用:
** 1.定期发送PING帧,防止中间设备误杀连接 **** 2.快速感知服务器或者是网络故障,如果 PING 未立即(毫秒级延迟)收到 PONG 响应,客户端能 秒级感知 并触发重连,而非一直等待。 **** **3.通过PING维持连接活跃,避免服务器主动关闭空闲连接。
设置心跳间隔一般小于接收Pong超时时间:(如果接收Pong超时为20s,间隔为30s)** ** t=0s:建立了连接 ** t=30s:发送第一次ping,启动超时计时器 ** **t=31s:接收到pong,超时计时器重置(到51s超时)也就是说如果31s到51s之间没有任何数据传输就会超时,而下一次发送ping是在t=60s,所有导致了超时**
writeTimeout:用于设置写操作的超时时间,防止发送数据时长时间阻塞。(sent) callTimeout:用于远程过程调用,设置等待服务器响应的最大时间。 readTimeout:用于设置从连接中读取数据的超时时间,确保在一定时间内接收到数据。 connectTimeout:用于设置建立连接的超时时间,确保在一定时间内连接成功。
代码实现:
** **private val handler=Handler(Looper.getMainLooper())
**这行代码创建了一个 **Handler 实例,并将其与主线程(UI 线程)关联起来。Looper.getMainLooper() 方法返回应用程序的主线程的 Looper 实例。通过传递这个 Looper 给 Handler 构造函数,您确保了 Handler 将在主线程上执行其 Runnable 任务。
Handler 类用于在指定的线程上执行任务,通常是在主线程(UI 线程)上。Handler 提供了一种方式来处理线程间的通信,特别是当需要在主线程上执行任务时。
状态码
1000:正常关闭(如页面导航离开) 1001:服务端主动断开(如维护重启) 1006:异常断开(常见于网络问题) 1012:服务端不可用(如负载过高)
Websocket
1.消息推送常见方式:轮询,长轮询,SSE,Websocket
** 轮询:指定间隔时间向服务器发送HTTP请求 **** **缺点:存在延迟,服务器压力大
** **长轮询:发出异步请求,服务器接到请求后,会阻塞请求,直到有数据或者超时才返回
** ****SSE(server-sent-event)**:基于HTTP协议,前端通过一个特殊的请求(
EventSource)连接到服务器。,服务器给前端打开单向通道(只能由服务器返回前端),响应返回数据流,然后实时向前端传输数据,直到通道关闭Websocket:是一种基于TCP连接上进行全双工通信的协议
http(超文本传输协议)是规定了客户端(如浏览器)与服务器之间传输数据的格式和通信方式 websocket也是一种规定了客户端和服务器传输数据格式和通信方式的协议,都位于OSI模型的第七层应用层
TCP协议(传输控制协议)(Transmission Control Protocol)是传输层协议,位于OSI模型的第四层。
** 全双工: 允许数据在两个方向上同时传输 **** **半双工:允许数据在两个方向上传输,但是一个时间段内只允许一个方向上传输
当浏览器向服务器发送请求以切换到 WebSocket 连接时,这个过程通常称为 WebSocket 握手。这个握手过程是基于 HTTP 协议的,因为 WebSocket 需要使用 HTTP 请求来启动连接。
以下是 WebSocket 握手的基本步骤:
Upgrade头部,表明客户端希望将连接从 HTTP 升级到 WebSocket。例如:Upgrade和Connection,以及Sec-WebSocket-Accept,后者是服务器对客户端Sec-WebSocket-Key的回应。例如:总结来说,虽然 WebSocket 握手开始于一个 HTTP 请求,但一旦握手完成,所有的通信都将通过 WebSocket 协议进行,而不是 HTTP。这种设计允许 WebSocket 利用现有的 HTTP 端口(通常是 80 或 443)来建立连接,从而更容易地通过防火墙和代理服务器。
基本用法:
1.添加依赖:
2.创建WebSocket监听器继承自WebSocketListener,重写四个方法
class EchoWebSocketListener:WebSocketListener() { override fun onOpen(webSocket: WebSocket, response: Response) { Log.d("WS","连接已建立") webSocket.send("Hello World") } override fun onMessage(webSocket: WebSocket, text: String) { Log.d("WS","收到消息:$text") } override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { webSocket.close(1000,null) Log.d("WS"," 错误:$reason") } override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { Log.d("WS","错误:${t.message}") } }3.创建WebSocket
class MainActivity : AppCompatActivity() { private lateinit var webSocket:WebSocket override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() val binding= ActivityMainBinding.inflate(layoutInflater) binding.btn.setOnClickListener { startWebSocket() } } private fun startWebSocket(){ val client=OkHttpClient.Builder() .pingInterval(30, TimeUnit.SECONDS)//设置心跳间隔,并且用枚举类型指定单位为秒 .build() val request=Request.Builder() .url("ws://echo.websocket.org").build()//传入服务器(自动返回发送的信息)的地址 val listener=EchoWebSocketListener() webSocket=client.newWebSocket(request, listener)//发送握手请求,但是还未建立,完成握手后,会调用onOpen(),30秒后去发送第一个Ping }心跳的作用:
** 1.定期发送PING帧,防止中间设备误杀连接 **** 2.快速感知服务器或者是网络故障,如果 PING 未立即(毫秒级延迟)收到 PONG 响应,客户端能 秒级感知 并触发重连,而非一直等待。 **** **3.通过PING维持连接活跃,避免服务器主动关闭空闲连接。
设置心跳间隔一般小于接收Pong超时时间:(如果接收Pong超时为20s,间隔为30s)** ** t=0s:建立了连接 ** t=30s:发送第一次ping,启动超时计时器 ** **t=31s:接收到pong,超时计时器重置(到51s超时)也就是说如果31s到51s之间没有任何数据传输就会超时,而下一次发送ping是在t=60s,所有导致了超时**
writeTimeout:用于设置写操作的超时时间,防止发送数据时长时间阻塞。(sent)callTimeout:用于远程过程调用,设置等待服务器响应的最大时间。readTimeout:用于设置从连接中读取数据的超时时间,确保在一定时间内接收到数据。connectTimeout:用于设置建立连接的超时时间,确保在一定时间内连接成功。代码实现:
package com.example.websocket import android.nfc.Tag import android.os.Handler import android.os.Looper import android.util.Log import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import okhttp3.WebSocket import okhttp3.WebSocketListener import java.util.concurrent.TimeUnit class EchoWebSocketListener:WebSocketListener() { private var webSocket: WebSocket? = null private val handler=Handler(Looper.getMainLooper()) private val reconnectInterval=5000L private val maxReconnectAttempts=5 private var reconnectAttempts=0 override fun onOpen(webSocket: WebSocket, response: Response) { this.webSocket=webSocket Log.d("WS","连接已建立") webSocket.send("Hello World") } override fun onMessage(webSocket: WebSocket, text: String) { Log.d("WS","收到消息:$text") } override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { webSocket.close(code,reason) when(code){ 1000->Log.d("WS","正常关闭") else->{Log.d("Ws", reason) scheduleReconnect() } } Log.d("WS"," 错误:$reason") } override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { Log.d("WS","错误:${t.message}") scheduleReconnect() } private fun scheduleReconnect(){ if(reconnectAttempts>=maxReconnectAttempts){ Log.d("Ws","重连次数以达到上限") return } handler.postDelayed({ Log.d("WS","正在尝试重连...") webSocket?.cancel()// 取消旧连接 val client= OkHttpClient.Builder() .pingInterval(30, TimeUnit.SECONDS) .build() val request=Request.Builder() .url("ws://echo.websocket.org") .build() val newWebSocket=client.newWebSocket(request,this) webSocket=newWebSocket//把新的webSocket赋给webSocket },reconnectInterval) } }** **private val handler=Handler(Looper.getMainLooper())
**这行代码创建了一个 **
Handler实例,并将其与主线程(UI 线程)关联起来。Looper.getMainLooper()方法返回应用程序的主线程的Looper实例。通过传递这个Looper给Handler构造函数,您确保了Handler将在主线程上执行其Runnable任务。Handler类用于在指定的线程上执行任务,通常是在主线程(UI 线程)上。Handler提供了一种方式来处理线程间的通信,特别是当需要在主线程上执行任务时。状态码
1000:正常关闭(如页面导航离开)1001:服务端主动断开(如维护重启)1006:异常断开(常见于网络问题)1012:服务端不可用(如负载过高)