聊聊OkHttp实现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 是真正意义上的全双工模式,也就是我们俗称的「长连接」。当完成握手连接后,客户端和服务端均可以主动的发起请求,回复响应,并且两边的传输都是相互独立的。

2.2 WebSocket 的特点

WebSocket 的数据传输,是基于 TCP 协议,但是在传输之前,还有一个握手的过程,双方确认过眼神,才能够正式的传输数据。

WebSocket 的握手过程,符合其 “Web” 的特性,是利用 HTTP 本身的 “协议升级” 来实现。

在建立连接前,客户端还需要知道服务端的地址,WebSocket 并没有另辟蹊径,而是沿用了 HTTP 的 URL 格式,但协议标识符变成了 “ws” 或者 “wss”,分别表示明文和加密的 WebSocket 协议,这一点和 HTTP 与 HTTPS 的关系类似。

以下是一些 WebSocket 的 URL 例子:

ws://cxmydev.com/some/path

ws://cxmydev.com:8080/some/path

wss://cxmydev.com:443?uid=xxx

而在连接建立后,WebSocket 采用二进制帧的形式传输数据,其中常用的包括用于数据传输的数据帧 MESSAGE 以及 3 个控制帧:

  • PING:主动保活的 PING 帧;

  • PONG:收到 PING 帧后回复;

  • CLOSE:主动关闭 WebSocket 连接;

更多 WebSocket 的协议细节,可以参考《WebSocket Protocol 规范》,具体细节,有机会为什么再开单篇文章讲解。

了解这些基本知识,我们基本上就可以把 WebSocket 使用起来,并且不会掉到坑里。

我们再小结一下 WebSocket 的特性:

  1. WebSocket 建立在 TCP 协议之上,对服务器端友好;

  2. 默认端口采用 80 或 443,握手阶段采用 HTTP 协议,不容易被防火墙屏蔽,能够通过各种 HTTP 代理服务器;

  3. 传输数据相比 HTTP 轻量,少了 HTTP Header,性能开销更小,通信更高效;

  4. 通过 MESSAGE 帧发送数据,可以发送文本或者二进制数据,如果数据过大,会被分为多个 MESSAGE 帧发送;

  5. WebSocket 沿用 HTTP 的 URL,协议标识符是 “ws” 或 “wss”。

那接下来我们就看看如何利用 OkHttp 使用 WebSocket。

三、WebSocket之OkHttp


3.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:// h o s t N a m e : {hostName}: hostName:{port}”

val request = Request.Builder()

.url(webSocketUrl)

.build()

httpClient.newWebSocket(request, object:WebSocketListener(){

// …

})

}

我想熟悉 OkHttp 的朋友,对上面这段代码不会有疑问,只是 URL 换成了 “ws” 协议标识符。另外,还需要配置 pingInterval(),这个细节后文会讲解。

调用 newWebSocket() 后,就会开始 WebSocket 连接,但是核心操作都在 WebSocketListener 这个抽象类中。

3.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 通信了。

3.3 Mock WebSocket

有时候为了方便我们测试,OkHttp 还提供了扩展的 MockWebSocket 服务,来模拟服务端。

Mock 需要添加额外的 Gradle 引用,最好和 OkHttp 版本保持一致:

api ‘com.squareup.okhttp3:okhttp:3.9.1’

api ‘com.squareup.okhttp3:mockwebserver:3.9.1’

Mock WebServer 的使用也非常简单,只需要利用 MockWebSocket 类即可。

var mMockWebSocket: MockWebServer? = null

fun mockWebSocket() {

if (mMockWebSocket != null) {

return

}

mMockWebSocket = MockWebServer()

mMockWebSocket?.enqueue(MockResponse().withWebSocketUpgrade(object : WebSocketListener() {

override fun onOpen(webSocket: WebSocket, response: Response) {

super.onOpen(webSocket, response)

// 有客户端连接时回调

}

override fun onMessage(webSocket: WebSocket, text: String) {

super.onMessage(webSocket, text)

// 收到新消息时回调

}

override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

最后

大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-gC1DWRY3-1712791918877)]

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用OkHttpWebSocket API来实现WebSocket通信。以下是一个示例代码: ``` OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("ws://echo.websocket.org") .build(); WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { // 连接成功 webSocket.send("Hello, WebSocket!"); } @Override public void onMessage(WebSocket webSocket, String text) { // 接收到消息 System.out.println("Received message: " + text); } @Override public void onClosed(WebSocket webSocket, int code, String reason) { // 连接关闭 System.out.println("Connection closed: " + reason); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { // 连接失败 t.printStackTrace(); } }); ``` 这个示例代码使用OkHttpClient创建一个WebSocket连接,连接到一个WebSocket服务器,然后发送一条消息。当接收到消息时,会打印出消息内容。当连接关闭时,会打印出关闭原因。如果连接失败,会打印出异常信息。 ### 回答2: OkHttp是Android平台上一个强大的HTTP通信库,它也支持WebSocket协议。使用OkHttp实现WebSocket连接需要以下步骤: 1. 导入OkHttp库:在`build.gradle`文件中添加OkHttp的依赖: ``` implementation 'com.squareup.okhttp3:okhttp:4.9.1' ``` 2. 创建OkHttpClient实例:使用OkHttpClient类创建一个实例,该实例用于发送WebSocket请求: ```java OkHttpClient client = new OkHttpClient(); ``` 3. 创建WebSocket对象:使用OkHttpClient的`newWebSocket()`方法创建WebSocket对象,并实现WebSocket监听器的回调方法: ```java Request request = new Request.Builder().url("ws://echo.websocket.org").build(); WebSocket ws = client.newWebSocket(request, new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { // WebSocket连接成功 } @Override public void onMessage(WebSocket webSocket, String text) { // 接收到WebSocket服务器发送的消息 } @Override public void onClosing(WebSocket webSocket, int code, String reason) { // WebSocket正在关闭 } @Override public void onClosed(WebSocket webSocket, int code, String reason) { // WebSocket已关闭 } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { // WebSocket连接失败 } }); ``` 4. 发送消息:通过WebSocket对象的`send()`方法向服务器发送消息: ```java ws.send("Hello, WebSocket Server!"); ``` 5. 断开连接:通过WebSocket对象的`close()`方法关闭WebSocket连接: ```java ws.close(1000, "Goodbye"); ``` 以上就是使用OkHttp实现WebSocket的简单代码示例。可以根据需要对WebSocket监听器的回调方法进行具体实现,并根据具体的WebSocket服务器地址进行修改。以上代码可以在Android平台上使用OkHttp实现WebSocket通信。 ### 回答3: 下面是用300字中文回答使用OkHttp实现WebSocket的代码: 首先,我们需要在项目的build.gradle文件中添加OkHttp库的依赖: ``` dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.0' } ``` 然后,在你的代码中创建一个WebSocket实例,并设置监听器处理WebSocket连接的回调: ``` import okhttp3.*; public class WebSocketExample { public static void main(String[] args) { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("ws://your-websocket-url") // 替换成实际的WebSocket服务器地址 .build(); WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, Response response) { // WebSocket连接成功时触发 System.out.println("WebSocket连接成功"); } @Override public void onMessage(WebSocket webSocket, String text) { // 接收到服务器发送的消息时触发 System.out.println("接收到消息:" + text); } @Override public void onClosed(WebSocket webSocket, int code, String reason) { // WebSocket连接关闭时触发 System.out.println("WebSocket连接关闭"); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { // WebSocket连接失败时触发 System.out.println("WebSocket连接失败"); } }); // 发送消息给服务器 webSocket.send("Hello, Server!"); // 关闭WebSocket连接 webSocket.close(1000, "Goodbye, Server!"); } } ``` 在以上代码中,我们创建了一个OkHttpClient对象,然后使用WebSocketListener类实现WebSocket连接的回调函数。在这些回调函数中,我们可以处理WebSocket连接的各个状态变化,如连接成功、接收到消息、连接关闭等。我们还可以使用WebSocket对象的send方法发送消息给服务器,使用close方法关闭WebSocket连接。 此外,需要注意替换代码中的"ws://your-websocket-url"为实际的WebSocket服务器地址。 请注意,以上代码仅为示例,实际应用中可能涉及更多的逻辑和错误处理。详细的使用方法可以参考OkHttp官方文档。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值