前言:
前段时间有朋友叫我帮封装下socket,闲来无事就顺带的做了,顺便充实自己,再就是怕忘记所以记录下。
写的不好或哪里可以完善的请多多指出,毕竟第一次写,自己文笔不好还是有自知之明的。^^
一、socket是什么?
网上介绍socket的文章一大堆,我就不废那功夫了(主要懒^^),有需要的自行网上查找就好。
代码整体是用kotlin写的,毕竟官方也推荐嘛。当然Java也可以调用并不影响使用。以下内容只有客户端代码,基于调试助手测试。socket整体的收发代码都写在了service中。
二、使用步骤
1.activity调用
代码如下(示例):
class ServiceActivity: Activity() {
lateinit var myBinder: SocketService.MyBinder
lateinit var socketService: SocketService
private val connect = object : ServiceConnection {
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
myBinder = p1 as SocketService.MyBinder
socketService = myBinder.getService()
}
override fun onServiceDisconnected(p0: ComponentName?) {}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent(this, SocketService::class.java)
startService(intent)
bindService(intent, connect, Context.BIND_AUTO_CREATE)
socketService.sendMessage("11")
}
}
代码看起来还是很简单的。依次启动service、绑定service。这里采用binder对象的方式实现service与activity之间的通信,并实例化socketService,之后就可收发信息。
2.SocketService的创建
代码如下(示例):
class SocketService : Service() {
val mBinder = MyBinder()
var isReconnect: Boolean = true
companion object {
lateinit var mThreadPool: ExecutorService
lateinit var socket: Socket
lateinit var outputStream: OutputStream
lateinit var inputStream: InputStream
lateinit var isr: InputStreamReader
lateinit var br: BufferedReader
var ip = "192.168.3.33"
var port = 8000
}
class MyBinder : Binder() {
fun getService(): SocketService {
return SocketService()
}
}
override fun onBind(p0: Intent?): IBinder {
return mBinder
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
initConnect(ip, port)
return super.onStartCommand(intent, flags, startId)
}
fun initConnect(ip: String, port: Int) {
mThreadPool = Executors.newCachedThreadPool()
mThreadPool.execute(object : Thread() {
override fun run() {
try {
Log.d("service", "开始连接")
socket = Socket(ip, port)
Log.d("service", socket.isConnected.toString())
} catch (e: Exception) {
Log.w("service", e.toString())
}
}
})
mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE)
mHandler.postDelayed(reciveBeatRunnable, RECIVE_BEAT_RATE)
}
fun sendMessage(msg: String) {
mThreadPool.execute(object : Thread() {
override fun run() {
try {
outputStream = socket.getOutputStream()
outputStream.write(msg.toByteArray())
outputStream.flush()
} catch (e: Exception) {
Log.w("service", e.toString())
}
}
})
}
val RECIVE_BEAT_RATE: Long = 1 * 1000
val HEART_BEAT_RATE: Long = 2 * 1000
var mHandler: Handler = Handler()
var reciveBeatRunnable: Runnable = object : Runnable {
override fun run() {
mThreadPool.execute(object : Thread() {
override fun run() {
try {
inputStream = socket.getInputStream()
isr = InputStreamReader(inputStream)
br = BufferedReader(isr)
Log.d("service", br.read().toString())
} catch (e: Exception) {
Log.w("service", e.toString())
}
}
})
mHandler.postDelayed(this, RECIVE_BEAT_RATE)
}
}
var heartBeatRunnable: Runnable = object : Runnable {
override fun run() {
Log.d("service", "心跳包检测socket连接状态")
mThreadPool.execute(object : Thread() {
override fun run() {
try {
outputStream = socket.getOutputStream()
outputStream.write("test".toByteArray())
outputStream.flush()
} catch (e: Exception) {
Log.d("service", "开始重连")
reconnectSocket()
}
}
})
mHandler.postDelayed(this, HEART_BEAT_RATE)
}
}
fun reconnectSocket() {
mHandler.removeCallbacks(heartBeatRunnable)
mHandler.removeCallbacks(reciveBeatRunnable)
outputStream.close()
inputStream.close()
isr.close()
br.close()
socket.close()
mThreadPool.shutdown()
if (isReconnect) {
initConnect(ip, port)
}
}
override fun onDestroy() {
super.onDestroy()
isReconnect = false
outputStream.close()
br.close()
socket.close()
mThreadPool.shutdown()
}
}
该处采用ExecutorService创建线程池进行Socket、OutputStream、InputStream、InputStreamReader、BufferedReader的实例化。采用向服务端不断地发送数据来检测连接是否正常,并每隔一秒回检测服务端是否向客户端发送数据。使用时需修改对应的ip地址及端口号。
注:该程序运行时必须确保服务端是开启状态,以及客户端与服务端在同一局域网下,否则会报初始化失败异常
总结
文章自我感觉写的不怎么样,第一次写写的不好下次努力。有不懂的或者优化完善的建议欢迎提出,大家一起进步^^。
|