文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

用OkHttp实现WebSocket长连接

2024-12-03 10:14

关注

今天给大家带来一篇老文章,介绍WebSocket,大家可以了解了解。

前言

最近老板又来新需求了,要做一个物联网相关的app,其中有个需求是客户端需要收发服务器不定期发出的消息。

内心OS:

开淦!

WebSocket介绍

先简单介绍下WebSocket。我们都知道Http是处于应用层的一个通信协议,但是只支持单向主动通信,做不到服务器主动向客户端推送消息。而且Http是无状态的,即每次通信都没有关联性,导致跟服务器关系不紧密。

为了解决和服务器长时间通信的痛点呢,HTML5规范引出了WebSocket协议(知道这名字咋来的吧,人家HTML5规范引出的,随爸姓),是一种建立在TCP协议基础上的全双工通信的协议。他跟Http同属于应用层协议,下层还是需要通过TCP建立连接。

但是,WebSocket在TCP连接建立后,还要通过Http进行一次握手,也就是通过Http发送一条GET请求消息给服务器,告诉服务器我要建立WebSocket连接了,你准备好哦,具体做法就是在头部信息中添加相关参数。然后服务器响应我知道了,并且将连接协议改成WebSocket,开始建立长连接。

这里贴上请求头和响应头信息,从网上找了一张图:

3851594110877_.pic.jpg

 

简单说明下参数:

OkHttp实现

添加OkHttp依赖

  1. implementation("com.squareup.okhttp3:okhttp:4.7.2"

实现代码

首先是初始化OkHttpClient和WebSocket实例:

  1.  
  2. public void init() { 
  3.     mWbSocketUrl = "ws://echo.websocket.org"
  4.     mClient = new OkHttpClient.Builder() 
  5.             .pingInterval(10, TimeUnit.SECONDS) 
  6.             .build(); 
  7.     Request request = new Request.Builder() 
  8.             .url(mWbSocketUrl) 
  9.             .build(); 
  10.     mWebSocket = mClient.newWebSocket(request, new WsListener()); 

这里主要是配置了OkHttp的一些参数,以及WebSocket的连接地址。其中newWebSocket方法就是进行WebSocket的初始化和连接。

这里要注意的点是pingInterval方法的配置,这个方法主要是用来设置WebSocket连接的保活。相信做过长连接的同学都知道,一个长连接一般要隔几秒发送一条消息告诉服务器我在线,而服务器也会回复一个消息表示收到了,这样就确认了连接正常,客户端和服务器端都在线。

如果服务器没有按时收到这个消息那么服务器可能就会主动关闭这个连接,节约资源。客户端没有正常收到这个返回的消息,也会做一些类似重连的操作,所以这个保活消息非常重要。

我们称这个消息叫作心跳包,一般用PING,PONG表示,像乒乓球一样,一来一回。所以这里的pingInterval就是设置心跳包发送的间隔时间,设置了这个方法之后,OkHttp就会自动帮我们发送心跳包事件,也就是ping包。当间隔时间到了,没有收到pong包的话,监听事件中的onFailure方法就会被调用,此时我们就可以进行重连。

但是由于实际业务需求不一样,以及okhttp中心跳包事件给予我们权限较少,所以我们也可以自己完成心跳包事件,即在WebSocket连接成功之后,开始定时发送ping包,在下一次发送ping包之前检查上一个pong包是否收到,如果没收到,就视为异常,开始重连。感兴趣的同学可以看看文末的相关源码。

建立连接后,我们就可以正常发送和读取消息了,也就是在上文WsListener监听事件中表现:

  1. //监听事件,用于收消息,监听连接的状态 
  2. class WsListener extends WebSocketListener { 
  3.     @Override 
  4.     public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { 
  5.         super.onClosed(webSocket, code, reason); 
  6.     } 
  7.  
  8.     @Override 
  9.     public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { 
  10.         super.onClosing(webSocket, code, reason); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) { 
  15.         super.onFailure(webSocket, t, response); 
  16.     } 
  17.  
  18.     @Override 
  19.     public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { 
  20.         super.onMessage(webSocket, text); 
  21.         Log.e(TAG, "客户端收到消息:" + text); 
  22.         onWSDataChanged(DATE_NORMAL, text); 
  23.        //测试发消息 
  24.         webSocket.send("我是客户端,你好啊"); 
  25.     } 
  26.  
  27.     @Override 
  28.     public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) { 
  29.         super.onMessage(webSocket, bytes); 
  30.     } 
  31.  
  32.     @Override 
  33.     public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { 
  34.         super.onOpen(webSocket, response); 
  35.         Log.e(TAG,"连接成功!"); 
  36.     } 
  37.  
  38.  
  39. //发送String消息 
  40. public void send(final String message) { 
  41.     if (mWebSocket != null) { 
  42.         mWebSocket.send(message); 
  43.     } 
  44.  
  45.  
  46. public void send(final ByteString message) { 
  47.     if (mWebSocket != null) { 
  48.         mWebSocket.send(message); 
  49.     } 
  50. }     
  51.  
  52. //主动断开连接 
  53. public void disconnect(int code, String reason) { 
  54.     if (mWebSocket != null
  55.         mWebSocket.close(code, reason); 

这里要注意,回调的方法都是在子线程回调的,如果需要更新UI,需要切换到主线程。

基本操作就这么多,还是很简单的吧,初始化Websocket——连接——连接成功——收发消息。

其中WebSocket类是一个操作接口,主要提供了以下几个方法

如果有同学想测试下WebSocket的功能但是又没有实际的服务器,怎么办呢?其实OkHttp官方有一个MockWebSocket服务,可以用来模拟服务端,下面我们一起试一下:

模拟服务器

首先集成MockWebSocket服务库:

  1. implementation 'com.squareup.okhttp3:mockwebserver:4.7.2' 

然后就可以新建MockWebServer,并加入MockResponse作为接收消息的响应。

  1. MockWebServer mMockWebServer = new MockWebServer(); 
  2.   MockResponse response = new MockResponse() 
  3.           .withWebSocketUpgrade(new WebSocketListener() { 
  4.               @Override 
  5.               public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) { 
  6.                   super.onOpen(webSocket, response); 
  7.                   //有客户端连接时回调 
  8.                   Log.e(TAG, "服务器收到客户端连接成功回调:"); 
  9.                   mWebSocket = webSocket; 
  10.                   mWebSocket.send("我是服务器,你好呀"); 
  11.               } 
  12.  
  13.               @Override 
  14.               public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) { 
  15.                   super.onMessage(webSocket, text); 
  16.  
  17.                   Log.e(TAG, "服务器收到消息:" + text); 
  18.               } 
  19.  
  20.               @Override 
  21.               public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { 
  22.                   super.onClosed(webSocket, code, reason); 
  23.                   Log.e(TAG, "onClosed:"); 
  24.               } 
  25.           }); 
  26.  
  27.   mMockWebServer.enqueue(response); 

这里服务器端在收到客户端连接成功消息后,给客户端发送了一条消息。要注意的是这段代码要在子线程执行,因为主线程不能进行网络操作。

然后就可以去初始化Websocket客户端了:

  1. //获取连接url,初始化websocket客户端 
  2. String websocketUrl = "ws://" + mMockWebServer.getHostName() + ":" + mMockWebServer.getPort() + "/"
  3. WSManager.getInstance().init(websocketUrl); 

ok,运行项目

//运行结果 E/jimu: mWbSocketUrl=ws://localhost:38355/ E/jimu: 服务器收到客户端连接成功回调: E/jimu: 连接成功! E/jimu: 客户端收到消息:我是服务器,你好呀 E/jimu: 服务器收到消息:我是客户端,你好啊

参考

https://github.com/square/okhttp

本文转载自微信公众号「码上积木,可以通过以下二维码关注。转载本文请联系码上积木公众号。

 

来源:码上积木内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯