OkHttpClient
引入 implementation ‘com.squareup.okhttp3:okhttp:4.11.0’
普通的 OkHttpClient
private fun buildOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder().readTimeout(20L, TimeUnit.SECONDS)
.writeTimeout(20L, TimeUnit.SECONDS)
.connectTimeout(15L, TimeUnit.SECONDS)
.pingInterval(20L, TimeUnit.SECONDS).build()
}
SSLOkHttpClient
private fun buildSSLOkHttpClient(): OkHttpClient {
val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
)
trustManagerFactory.init(null as KeyStore?)
val trustManagers: Array<TrustManager> = trustManagerFactory.getTrustManagers()
check(!(trustManagers.size != 1 || trustManagers[0] !is X509TrustManager)) {
("Unexpected default trust managers:"
+ trustManagers.contentToString())
}
val trustManager: X509TrustManager = trustManagers[0] as X509TrustManager
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate?>? {
return arrayOfNulls<X509Certificate>(0)
}
override fun checkClientTrusted(
certs: Array<X509Certificate?>?,
authType: String?
) {
}
override fun checkServerTrusted(
certs: Array<X509Certificate?>?,
authType: String?
) {
}
})
val sslContext: SSLContext = SSLContext.getInstance("TLS")
sslContext.init(null, trustAllCerts, SecureRandom())
val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
return OkHttpClient.Builder().connectTimeout(15L, TimeUnit.SECONDS)
.readTimeout(20L, TimeUnit.SECONDS)
.writeTimeout(20L, TimeUnit.SECONDS)
.pingInterval(20L, TimeUnit.SECONDS)
.sslSocketFactory(sslSocketFactory, trustManager)
.hostnameVerifier { hostname: String?, session: SSLSession? ->
true
}
.build()
}
建立链接
fun connect(url: String?) {
Log.i(TAG, "connect: socket to $url")
android.util.Log.i(TAG, "connect: socket to $url")
// val okHttpClient: OkHttpClient = buildOkHttpClient()
// buildSSLOkHttpClient() 有ssl的
val okHttpClient: OkHttpClient = buildSSLOkHttpClient()
val request = Request.Builder()
.header("Content-type", "application/x-www-form-urlencoded")
.url(url ?: "")
.build()
mWebSocket = okHttpClient.newWebSocket(request, object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
Log.d(TAG, "open")
isClosed = false
mSocketListener?.onOpen(webSocket, response)
}
override fun onMessage(webSocket: WebSocket, text: String) {
Log.d(
TAG,
"webSocket 收到消息 onMessage= 长度 ${text.length} 内容:\n 收到text=$text"
)
val bestResult = MessageUtils.fromJson(text, BestResult::class.java)
if (bestResult != null) {
if (bestResult.mid.isNullOrEmpty()) {
Log.d(TAG, " receive empty mid message")
} else {
val funcId = dispatchMidFuncIdMap[bestResult.mid]
if (funcId != null && funcId.isNotEmpty()) {
bestResult.responseToFuncId(funcId)
Log.i(
TAG,
"onMessage funcId mid=${bestResult.mid}, funcId=${bestResult.funcId},,sid=${bestResult.sid}"
)
mSocketListener?.afterReceiveMsg(bestResult, funcId)
} else {
Log.d(
TAG,
"onMessage funcId not found mid=${bestResult.mid}, funcId=${bestResult.funcId},sid=${bestResult.sid}"
)
//收到别的命令
if (!bestResult.sid.isNullOrEmpty()) {
bestResult.funcId = bestResult.sid
}
mSocketListener?.afterReceiveMsg(bestResult, bestResult.funcId)
}
dispatchMidFuncIdMap.remove(bestResult.mid)
disposeCheckTask(bestResult.mid)
}
} else {
Log.e(TAG, "解析 bestResult 异常 $text")
}
}
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
super.onClosing(webSocket, code, reason)
Log.w(TAG, "onClosing")
mSocketListener?.onClosing(webSocket, code, reason)
}
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
super.onClosed(webSocket, code, reason)
Log.w(TAG, "onClosed")
isClosed = true
mSocketListener?.onClosed(webSocket, code, reason)
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
super.onFailure(webSocket, t, response)
Log.e(TAG, "onFailure: response=$response ", t)
mSocketListener?.onFailure(webSocket, t, response)
}
})
}
断开链接
fun disconnect(): Boolean {
dispatchMidFuncIdMap.clear()
checkMidDisposable.forEach {
it.value.dispose()
}
checkMidDisposable.clear()
return mWebSocket?.close(1000, "正常关闭") ?: false
}
发送数据
@Synchronized
fun sendData(bestBean: BestParam): Boolean {
/**
* 1. 存放 mid 和 funcid 到 map
* 2. 将 参数 进行加密转换
* 3. 发送
*/
dispatchMidFuncIdMap[bestBean.mid] = bestBean.sid
dispatchMidBestBeanMap[bestBean.mid] = bestBean
val message = MessageUtils.toJson(bestBean)
Log.d(
TAG,
"待发送数据 size = ${dispatchMidFuncIdMap.size} map= [$dispatchMidFuncIdMap ]"
)
if (message.length > 1000) {
Log.i(
TAG,
"待发送数据 message = ${message.subSequence(0, 999)}"
)
} else {
Log.i(
TAG,
"待发送数据 message = $message"
)
}
//todo: 加密流程
val isSending = mWebSocket?.send(message) ?: false
if (isSending) {
mSocketListener?.onData(false, message.length)
} else {
mSocketListener?.onData(false, 0) //发送失败
}
Log.i(TAG, "sendData: socket 是否已经发送数据 $isSending, ${bestBean.sid}")
if (isSending && !noSendingCheckFunId.contains(bestBean.sid)) {
//?秒之后还未回复,重新发送,有在发送,才检查,如果是心跳信息,则无需检查
checkMidAfter(DEFAULT_RESEND_AFTER, bestBean.mid)
} else {
removeMid(bestBean.mid) //socket连接有问题,无法发送
}
return isSending
}