安卓Kotlin 简易带缓冲Socket 客户端(Client)

如果实现progress接口,还可以做到进度显示

Client.kt

本客户端在实现缓冲时还用到了安卓Kotlin 简易 ByteArray 先入先出(FIFO)队列

//Fumiama 20210601
//Client.kt
import android.util.Log
import java.io.*
import java.lang.Thread.sleep
import java.net.Socket

class Client(private val ip: String, private val port: Int) {
    //普通数据交互接口
    private var sc: Socket? = null

    //普通交互流
    private var dout: OutputStream? = null
    private var din: InputStream? = null

    //已连接标记
    private val isConnect get() = sc != null && din != null && dout != null

    /**
     * 初始化普通交互连接
     */
    fun initConnect(depth: Int = 0): Boolean{
        if(depth > 3) Log.d("MyC", "connect server failed after $depth tries")
        else try {
            sc = Socket(ip, port) //通过socket连接服务器
            din = sc?.getInputStream()  //获取输入流并转换为StreamReader,约定编码格式
            dout = sc?.getOutputStream()    //获取输出流
            sc?.soTimeout = 10000  //设置连接超时限制
            return if (isConnect) {
                Log.d("MyC", "connect server successful")
                true
            } else {
                Log.d("MyC", "connect server failed, now retry...")
                initConnect(depth + 1)
            }
        } catch (e: IOException) {      //获取输入输出流是可能报IOException的,所以必须try-catch
            e.printStackTrace()
        }
        return false
    }

    /**
     * 发送数据至服务器
     * @param message 要发送至服务器的字符串
     */
    fun sendMessage(message: String?): Boolean = sendMessage(message?.toByteArray())

    fun sendMessage(message: ByteArray?): Boolean {
        try {
            if (isConnect) {
                if (message != null) {        //判断输出流或者消息是否为空,为空的话会产生null pointer错误
                    dout?.write(message)
                    dout?.flush()
                    Log.d("MyC", "Send msg: ${message.decodeToString()}")
                    return true
                } else Log.d("MyC", "The message to be sent is empty")
                Log.d("MyC", "send message succeed")
            } else Log.d("MyC", "send message failed: no connect")
        } catch (e: IOException) {
            Log.d("MyC", "send message failed: crash")
            e.printStackTrace()
        }
        return false
    }

    fun read(): Char? = din?.read()?.toChar()

    private var buffer = ByteArrayQueue()
    private val receiveBuffer = ByteArray(65536)

    fun receiveRawMessage(totalSize: Int, setProgress: Boolean = false) : ByteArray {
        if(totalSize == buffer.size) return buffer.popAll()
        else {
            try {
                if (isConnect) {
                    Log.d("MyC", "开始接收服务端信息")
                    while(totalSize > buffer.size) {
                        val count = din?.read(receiveBuffer)?:0
                        if(count > 0) {
                            buffer += receiveBuffer.copyOfRange(0, count)
                            Log.d("MyC", "reply length:$count")
                            if(setProgress && totalSize > 0) progress?.notify(100 * buffer.size / totalSize)
                        } else sleep(10)
                    }
                } else Log.d("MyC", "no connect to receive message")
            } catch (e: IOException) {
                Log.d("MyC", "receive message failed")
                e.printStackTrace()
            }
            return if(totalSize > 0) buffer.pop(totalSize)?:byteArrayOf() else buffer.popAll()
        }
    }

    fun receiveMessage(totalSize: Int) = receiveRawMessage(totalSize).decodeToString()

    /**
     * 关闭连接
     */
    fun closeConnect() = try {
            din?.close()
            dout?.close()
            sc?.close()
            sc = null
            din = null
            dout = null
            true
        } catch (e: IOException) {
            e.printStackTrace()
            false
        }

    var progress: Progress? = null

    interface Progress {
        fun notify(progressPercentage: Int)
    }
}

示例代码

val client = Client("127.0.0.1", 80)
client.initConnect()
client.sendMessage("hello")		//发送字符串,也可重载为发送ByteArray
client.receiveRawMessage(4)		//阻塞接收4字节数据后返回ByteArray
client.receiveMessage(4)		//阻塞接收4字节数据后返回UTF8编码的字符串
client.read()					//阻塞接收一个char
client.closeConnect()			//关闭连接
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值