使用Kotlin+Netty Android客户端连接
由于Kotlin也是新的语言,在2017年中下才和Android完全融合
在这里我只写了Netty客户端连接服务器的部分代码,如果想要更多代码可以下方留言
我这个是实用在真实项目中的代码,由于我自己也遇到了很多问题,所以就想分享出来给大家,谢谢
首先在代码中解决了两个重大问题
- 1.Netty Client启动的时候需要重连
- 2.在程序运行中连接断掉需要重连。
其他的都不说了直接上代码
package com.ftrd.flashlight.nettys
import com.ftrd.flashlight.FileKt.DelegatesExt
import com.ftrd.flashlight.FileKt.FinalValue;
import com.ftrd.flashlight.FileKt.LogUtils;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener
import java.util.concurrent.TimeUnit
/**
* @author: Jeff <15899859876@qq.com>
* @date: 2018-02-05 16:54
* @description: netty连接类
* 1.Netty Client启动的时候需要重连
* 2.在程序运行中连接断掉需要重连。
* 使用object关键字替代class关键字就可以声明一个单例对象
*/
object NettyConnect {
//companion静态声类声名对象,相当于static关键
//companion object { // 自定义委托实现单例,只能修改这个值一次.
//如果要发送数据直接调用NettyConnect.channel?.writeAndFlush(""); 或着 导包直接使用channel.writeAndFlush("")
var channel: Channel by DelegatesExt.notNullSingleValue<Channel>();
/* NioEventLoopGroup可以理解为一个线程池,内部维护了一组线程,
每个线程负责处理多个Channel上的事件,而一个Channel只对应于一个线程,这样可以回避多线程下的数据同步问题。*/
private var eventLoopGroup: NioEventLoopGroup? = null;
/* Bootstrap是开发netty客户端的基础,通过Bootstrap的connect方法来连接服务器端。该方法返回的也是ChannelFuture,
通过这个我们可以判断客户端是否连接成功,*/
private var bootstrap: Bootstrap? = null;
//使用Thread线程进行异步连接
private var mThread: Thread? = null;
//ChannelFuture的作用是用来保存Channel异步操作的结果。
private var future: ChannelFuture? = null;
//保存连接成功或着失败
private var onDestrYN: Boolean = false;
// }
//创建连接方法,如果要调用连接,直接调用此方法即可
fun reConnect() = try {
mThread = object : Thread("NettyConnect.reConnect") {
override fun run() {
// super.run();
LogUtils.d("NettyConnect",
"正在连接服务器 ipStr=${FinalValue.COMMAND_IP},portInt=${FinalValue.COMMAND_PORT}");
eventLoopGroup = NioEventLoopGroup();
bootstrap = Bootstrap()
bootstrap!!.channel(NioSocketChannel::class.java)
.group(eventLoopGroup)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000 * 10)//设置连接超时时间
.option(ChannelOption.SO_KEEPALIVE, true)
//.remoteAddress(host, port)
.handler(object : ChannelInitializer<SocketChannel>() {
@kotlin.jvm.Throws(java.lang.Exception::class)
override fun initChannel(ch: SocketChannel) {
var pipeline: ChannelPipeline = ch.pipeline();
//使用pipeline.addLast()添加,Decoder、Encode和Handler对象
}
})
//ChannelFuture的作用是用来保存Channel异步操作的结果。
//不使用监听
// val future: ChannelFuture = bootstrap!!.connect(FinalValue.COMMAND_IP,FinalValue.COMMAND_PORT).sync();
//使用监听,监听是否连接或是断开
// val future: ChannelFuture = bootstrap!!.connect(FinalValue.COMMAND_IP,FinalValue.COMMAND_PORT);
//{addListener(GenericFutureListener)}的方式来获得通知,而非await()。使用sync异步执行
future = bootstrap!!.connect(FinalValue.COMMAND_IP, FinalValue.COMMAND_PORT).sync();
if (future?.isSuccess!!) {
//如果连接成功则保存ChannelFuture到Channel
channel = future!!.channel() as Channel
//channel = future!!.awaitUninterruptibly().channel()
onDestrYN=true;//连接成功
} else {
onDestrYN=false;//连接失败
while (onDestrYN){//连接失败一直进行连接,不管是什么原因都进行连接
LogUtils.d("NettyConnect", "连接失败再次连接")
//断开连接,重新进行连接
channel?.disconnect()
channel?.close()
future!!.channel().eventLoop().schedule(
{
//重新开新的线程进行连接
if (future?.isSuccess!!) {
//如果连接成功则保存ChannelFuture到Channel
channel = future!!.channel() as Channel
//channel = future!!.awaitUninterruptibly().channel()
onDestrYN=true;//连接成功
}
},
2,//2秒重新连接
TimeUnit.SECONDS);
}
}
}
}
mThread!!.start();
} catch (ex: Exception) {
LogUtils.d("NettyConnect", "连接服务器出现异常Exception=${ex.message}");
destroy();//出现异常结束资源
} finally {
LogUtils.d("NettyConnect", "连接关闭资源释放");
}
fun destroy() {
//结束线程
mThread?.interrupt();
mThread?.join();
mThread = null;
//ChannelFuture,结束监听
//future?.removeListener { }
future = null;
//结束连接
channel?.closeFuture();
channel?.flush();
channel?.close();
// channel = null;
// Bootstrap
bootstrap = null;
//结束线程池
eventLoopGroup?.shutdownGracefully();
eventLoopGroup = null;
}
}