HarmonyOS 鸿蒙Next网络协议WebSocket
HarmonyOS 鸿蒙Next网络协议WebSocket
Websocket
-
消息推送常见方式:轮询,长轮询,SSE,Websocket
-
轮询:指定间隔时间向服务器发送HTTP请求 缺点:存在延迟,服务器压力大
-
长轮询:发出异步请求,服务器接到请求后,会阻塞请求,直到有数据或者超时才返回
-
SSE(server-sent-event):前端发出请求,服务器给前端打开单向通道,响应返回数据流,然后实时向前端传输数据,直到通道关闭
-
Websocket:是一种基于TCP连接上进行全双工通信的协议
-
http是规定了客户端(如浏览器)与服务器之间传输数据的格式和通信方式 websocket也是一种规定了客户端和服务器传输数据格式和通信方式的协议
- 全双工: 允许数据在两个方向上同时传输
- 半双工:允许数据在两个方向上传输,但是一个时间段内只允许一个方向上传输
当浏览器向服务器发送请求以切换到 WebSocket 连接时,这个过程通常称为 WebSocket 握手。这个握手过程是基于 HTTP 协议的,因为 WebSocket 需要使用 HTTP 请求来启动连接。
以下是 WebSocket 握手的基本步骤:
- 客户端发起请求:浏览器通过发送一个特殊的 HTTP 请求到服务器来开始 WebSocket 握手。这个请求包含了
Upgrade
头部,表明客户端希望将连接从 HTTP 升级到 WebSocket。例如:
GET /websocket HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
- 服务器响应:如果服务器同意升级连接,它会发送一个 HTTP 响应,状态码为 101(Switching Protocols),表明它同意进行协议升级。这个响应也包含了一些额外的头部,如
Upgrade
和Connection
,以及Sec-WebSocket-Accept
,后者是服务器对客户端Sec-WebSocket-Key
的回应。例如:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
-
连接建立:一旦客户端收到服务器的 101 响应,WebSocket 连接就正式建立。之后,所有的数据传输都将通过 WebSocket 协议进行,而不是 HTTP。
-
数据传输:在 WebSocket 连接建立后,服务器和客户端之间将使用 WebSocket 协议进行全双工通信。这意味着双方可以同时发送和接收数据,而不受 HTTP 请求-响应模型的限制。
总结来说,虽然 WebSocket 握手开始于一个 HTTP 请求,但一旦握手完成,所有的通信都将通过 WebSocket 协议进行,而不是 HTTP。这种设计允许 WebSocket 利用现有的 HTTP 端口(通常是 80 或 443)来建立连接,从而更容易地通过防火墙和代理服务器。
基本用法:
- 添加依赖:
implementation(libs.okhttp)
- 创建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}")
}
}
- 创建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
}
心跳的作用:
-
- 定期发送PING帧,防止中间设备误杀连接
-
- 快速感知服务器或者是网络故障,如果 PING 未立即(毫秒级延迟)收到 PONG 响应,客户端能 秒级感知 并触发重连,而非一直等待。
-
- 通过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
:服务端不可用(如负载过高)
更多关于HarmonyOS 鸿蒙Next网络协议WebSocket的实战教程也可以访问 https://www.itying.com/category-93-b0.html
鸿蒙Next的WebSocket实现基于标准RFC 6455协议,提供全双工通信能力。开发者可使用@ohos.net.socket
模块创建WebSocket连接,主要接口包括:
createWebSocket()
初始化连接对象connect()
建立服务器连接send()
发送文本/二进制数据- 通过
on('message')
等事件监听器处理数据
典型代码结构:
import webSocket from '@ohos.net.socket';
let ws = webSocket.createWebSocket();
ws.on('open', () => {
ws.send("Hello Server");
});
ws.connect('ws://example.com');
支持TLS加密连接,需配置extraOptions
中的安全参数。连接状态通过readyState
属性获取。
更多关于HarmonyOS 鸿蒙Next网络协议WebSocket的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中使用WebSocket需要注意以下几点:
-
连接建立流程与标准WebSocket一致,都是通过HTTP 101协议切换完成握手
-
推荐使用okhttp库实现WebSocket客户端,其API与Android保持兼容
-
心跳机制配置建议:
- 设置pingInterval为30秒左右
- 确保接收pong超时时间大于心跳间隔
- 可通过OkHttpClient.Builder配置超时参数
-
连接状态管理要点:
- 实现自动重连机制
- 正确处理各种关闭状态码(1000/1001/1006等)
- 使用Handler确保回调在主线程执行
-
性能优化建议:
- 合理设置各超时参数
- 实现消息队列避免频繁发送
- 注意资源释放防止内存泄漏
WebSocket在HarmonyOS Next中的API使用与Android基本一致,开发者可以平滑迁移现有代码。