您的位置:首页 > 理论基础 > 计算机网络

使用netty进行客户端网络编程及断线重连功能实现

2017-01-09 21:42 961 查看
       不管做哪个方向开发,都会有那么一两个牛B闪闪的库,可以极大的方便开发,比如java网络编程中的netty库。无论客户端还是服务端网络编程,netty基本都是首选网络库,健壮、高效、稳定,并且已经得到很多商业项目验证。
       当用netty进行客户端网络编程时,与服务端建立连接并完成数据编码、解码、通信是最基础功能,考虑程序的健壮性,则断线重连是必不可少的一个功能点。netty源码的example文件夹中uptime目录中有相关示例demo,但是总觉得该样例代码封装的不够好,于是决定自己动手重新写一个,如果有更优雅的断线重连实现方法,希望大家将链接留言发我。下面是主体代码,Handler部分就不分享了。

public class BaseClient implements Runnable {

private static Logger LOGGER = LoggerTools.getInstance(BaseClient.class);

private String host_;
private int port_;
private int reConnectCount_ = 0;
private ClientHandler clientHandler_;
private OnMessageListener messageListener_;
private OnStartupListener startupListener_;
private volatile boolean isChannelPrepared_;

private final static int MAX_MESSAGE_LENGTH = 8192;

public BaseClient(String host, int port, OnMessageListener messageListener, OnStartupListener startupListener) {
host_ = host;
port_ = port;
messageListener_ = messageListener;
startupListener_ = startupListener;
}

@Override
public void run() {
connect(host_, port_);
}

// 发送消息
public void sendMessage(String msg, ResultListener<String> listener) {
if (isChannelPrepared_) {
clientHandler_.sendMessage(msg, listener);
} else {
listener.onFailure(msg);
LOGGER.error("连接还未建立, 无法发送数据...");
}
}

// 建立连接
private void connect(String host, int port) {
EventLoopGroup group = new NioEventLoopGroup();

try {
Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.TCP_NODELAY, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();

p.addLast(new LengthFieldBasedFrameDecoder(MAX_MESSAGE_LENGTH, 0, 4, 0 ,4));
p.addLast(new LengthFieldPrepender(4));
p.addLast(new StringDecoder(CharsetUtil.UTF_8));
p.addLast(new StringEncoder(CharsetUtil.UTF_8));

clientHandler_ = new ClientHandler(messageListener_);
p.addLast(clientHandler_);
}
});

ChannelFuture f = b.connect(host, port).sync();
f.addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
if (future.isSuccess()) {
reConnectCount_ = 0;
isChannelPrepared_ = true;
startupListener_.onCompletion(true);
LOGGER.info("与服务器{}:{}连接建立成功...", host_, port_);
} else {
isChannelPrepared_ = false;
startupListener_.onCompletion(false);
LOGGER.info("与服务器{}:{}连接建立失败...", host_, port_);
}
}
});

f.channel().closeFuture().sync();
} catch (Exception e) {
isChannelPrepared_ = false;
LOGGER.error("与服务器{}:{}连接出现异常...", host_, port_);
} finally {
isChannelPrepared_ = false;
group.shutdownGracefully();
reConnect(host, port);
}
}

// 断线重连
private void reConnect(String host, int port) {
// fixme: 重连显式退出?
try {
isChannelPrepared_ = false;
int delay = ++reConnectCount_ * 5;
reConnectCount_ = reConnectCount_ > 23 ? 23 : reConnectCount_;
LOGGER.error("与服务器{}:{}连接已断开, {}秒后重连...", host, port, delay);

Thread.sleep(delay * 1000);
connect(host, port);
} catch (Exception e) {
e.printStackTrace();
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐