Android Socket通讯 之 心跳消息

简介: Android Socket通讯 之 心跳消息

前言


不知道大家国庆节过的咋样,有没有学习呢?我是闲着没事就写点东西,本文篇幅较短,只是实现了心跳消息的处理,下面进入正文。


正文


 先说说为什么要增加心跳消息,Socket在连接过程中会发生很多的意外,比如网络问题、连接不上、ip地址不对、异常断连,而心跳消息说白了就是通过指定时间去收发消息,通过收发消息就能知道连接双方处于什么状态。知道是什么状态就知道该怎么处理。


一、状态判断


在开始写之前我们需要先知道状态有哪些,直接在IOException中进行处理。


      catch (e: IOException) {
                e.printStackTrace()
                when (e) {
                    is SocketTimeoutException -> {
                        Log.e(TAG, "连接超时,正在重连")
                    }
                    is NoRouteToHostException -> {
                        Log.e(TAG, "该地址不存在,请检查")
                    }
                    is ConnectException -> {
                        Log.e(TAG, "连接异常或被拒绝,请检查")
                    }
                    is SocketException -> {
                        when (e.message) {
                            "Already connected" -> Log.e(TAG, "连接异常或被拒绝,请检查")
                            "Socket closed" -> Log.e(TAG, "连接已关闭")
                        }
                    }
                }
            }


这里就可以直接做处理,我打印了日志,你可以在连接过程中,进行测试,这段代码添加的位置如下图所示:


62d767dae2bc461dab43e4f585f4ddf0.png


这个代码对于服务端和客户端都一样。


二、心跳消息发送


 心跳消息需要在什么时候发送呢?在客户端连接了服务端之后,由客户端发起心跳消


  private const val HEART_SPACETIME = 3 * 1000
    private val mHandler: Handler = Handler()


这里定义了一个心跳间隔时间,也就是说,3秒发送一次心跳,下面写一个发送心跳的方法。


  private val mHeartRunnable = Runnable { sendHeartbeat() }
    /**
     * 发送心跳消息
     */
    private fun sendHeartbeat() {
        if (clientThreadPool == null) {
            clientThreadPool = Executors.newSingleThreadExecutor()
        }
        val msg = "洞幺洞幺,呼叫洞拐,听到请回答,听到请回答,Over!"
        clientThreadPool?.execute {
            if (socket == null) {
                mCallback.otherMsg("客户端还未连接")
                return@execute
            }
            if (socket!!.isClosed) {
                mCallback.otherMsg("Socket已关闭")
                return@execute
            }
            outputStream = socket?.getOutputStream()
            try {
                outputStream?.write(msg.toByteArray())
                outputStream?.flush()
                //发送成功以后,重新建立一个心跳消息
                mHandler.postDelayed(mHeartRunnable, HEART_SPACETIME.toLong())
                Log.i(TAG, msg)
            } catch (e: IOException) {
                e.printStackTrace()
                mCallback.otherMsg("向服务端发送消息: $msg 失败")
            }
        }
    }


心跳消息中我定义了消息的内容,服务端收到这个内容就表示为心跳消息,这个消息内容还是有待商榷的,先实现功能就行,在这里发送消息之后,进行延时发送下一次心跳消息,这里打印了发送的心跳消息了,因为是连接到服务端之后就开始发送,所以还需要在connectServer()函数中处理,增加代码如下图所示:


a06ccbec6bfc4c0fb4d0e44383ddb4ed.png


最后就是处理服务端回复的服务端消息,修改ClientThread中的代码如下图所示:


dd91be4a91014ee2bfd913a527976c88.png


 这里判断一下服务端回复的内容是什么,如果是我们想要的内容就表明这是一个心跳消息,则只打印就行了,不需要回调的页面上进行显示,这里的内容因为你可能也会在输入框输入,所以会存在问题。


三、心跳消息回复


 当服务端收到客户端发送的心跳时就要回复消息给客户端,这样客户端就知道服务端一直都在,服务端的代码就相对来说简单很多了,在SocketServer中增加一个函数,代码如下:


  fun replyHeartbeat() {
        if (serverThreadPool == null) {
            serverThreadPool = Executors.newCachedThreadPool()
        }
        val msg = "洞拐收到,洞拐收到,Over!"
        serverThreadPool?.execute {
            if (socket == null) {
                mCallback.otherMsg("客户端还未连接")
                return@execute
            }
            if (socket!!.isClosed) {
                mCallback.otherMsg("Socket已关闭")
                return@execute
            }
            outputStream = socket!!.getOutputStream()
            try {
                outputStream.write(msg.toByteArray())
                outputStream.flush()
            } catch (e: IOException) {
                e.printStackTrace()
                mCallback.otherMsg("向客户端发送消息: $msg 失败")
            }
        }
    }


在什么时候调用它呢?当然是在收到客户端发送消息的时候调用,只不过和客户端收到服务端消息一样,同样需要判断一下才行,如下图所示:


459f3fdbffd746e9b6924eda3798fa26.png


 代码是不是很简单呢?其他的地方都不需要怎么去改动了,运行一下,让你的客户端连接这个服务端,然后看控制台的日志打印,如下图所示:


60f12bfe3dc64aa48b21cd7c66fe5eeb.png


四、源码


如果你觉得代码对你有帮助的话,不妨Fork或者Star一下~


相关文章
|
7月前
|
安全 网络协议 网络安全
http https socket通讯详解?
http https socket通讯详解?
|
7天前
|
XML Java Android开发
Android Studio开发之使用内容组件Content获取通讯信息讲解及实战(附源码 包括添加手机联系人和发短信)
Android Studio开发之使用内容组件Content获取通讯信息讲解及实战(附源码 包括添加手机联系人和发短信)
131 0
|
7天前
|
算法 Linux 调度
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
57 1
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
|
10月前
|
移动开发 监控 网络协议
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
|
缓存 监控 Linux
Android C++系列:Linux Socket编程(四)多路IO转接服务器
select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开 的文件描述符个数并不能改变select监听文件个数
95 0
|
网络协议 Linux API
Android C++ 系列:Linux Socket 编程(三)CS 模型示例
服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于 监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服 务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK 段,服务器收到后从accept()返回。
127 0
|
网络协议 Unix Linux
Android C++ 系列:Linux Socket 编程(二)网络套接字函数
socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描 述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调 用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为 SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表 示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。
159 0
|
网络协议 Unix Linux
Android C++ 系列:Linux Socket 编程(一)预备知识
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运 行,可以调用以下库函数做网络字节序和主机字节序的转换。
172 0
|
测试技术 数据处理 数据库
Android Modbus 通讯实现
Android Modbus 通讯实现
429 0
Android Modbus 通讯实现
|
Java Android开发
Android studio怎样修改 包名和AppId,android 加入AIDL进行底层通讯
Android studio怎样修改 包名和AppId,android 加入AIDL进行底层通讯
610 1
Android studio怎样修改 包名和AppId,android 加入AIDL进行底层通讯