All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jizcode.netty.client.RtClient Maven / Gradle / Ivy

package jizcode.netty.client;

import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import jizcode.base.util.JsonUtils;
import jizcode.netty.contract.BufferSize;
import jizcode.netty.contract.RtDataFromClient;
import jizcode.netty.contract.RtDataFromServer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class RtClient {
	protected Log logger = LogFactory.getLog(this.getClass());
	private static RtClient s_netttyclient;

	public static RtClient getInstance() {
		if (s_netttyclient == null) {
			s_netttyclient = new RtClient();
		}
		return s_netttyclient;
	}

	private int port;
	private String host;
	private SocketChannel socketChannel;
	private Function resolveCallback;
	private Function connectCallback;
	private Boolean isReconnecting;

	private RtClient() {
		isReconnecting = false;
	}

	public Function getResolveCallback() {
		return this.resolveCallback;
	}

	/**
	 * connect to server
	 *
	 * @param host
	 * @param port
	 * @param connectCallback
	 * @param resolveCallback
	 */
	public void start(String host, int port, Function connectCallback,
					  Function resolveCallback) {
		if (socketChannel == null) {
			this.host = host;
			this.port = port;
			this.resolveCallback = resolveCallback;
			this.connectCallback = connectCallback;
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
					Bootstrap bootstrap = new Bootstrap();
					bootstrap.channel(NioSocketChannel.class)
							// 保持连接
							.option(ChannelOption.SO_KEEPALIVE, true)
							// 有数据立即发送
							.option(ChannelOption.TCP_NODELAY, true)
							// 绑定处理group
							.group(eventLoopGroup).remoteAddress(host, port)
							.handler(new ChannelInitializer() {
								@Override
								protected void initChannel(SocketChannel socketChannel) throws Exception {
									// 初始化编码器,解码器,处理器
									socketChannel.pipeline().addLast(new IdleStateHandler(0, 5, 0, TimeUnit.SECONDS),
											new RtIdleStateTrigger(), new LineBasedFrameDecoder(BufferSize.Default),
											new StringDecoder(Charset.forName("utf-8")), new RtClientHandler());
								}
							});
					// 进行连接
					ChannelFuture future;
					try {
						future = bootstrap.connect(host, port).sync();
						// 判断是否连接成功
						if (future.isSuccess()) {
							// 得到管道,便于通信
							socketChannel = (SocketChannel) future.channel();
							//logger.info("客户端开启成功...");
							connectCallback.apply(true);
						} else {
							//logger.info("客户端开启失败...");
							connectCallback.apply(false);
						}
						// 等待客户端链路关闭,就是由于这里会将线程阻塞,导致无法发送信息,所以我这里开了线程
						future.channel().closeFuture().sync();
						//logger.info("客户端退出...");
					} catch (Exception e) {
						connectCallback.apply(false);
						e.printStackTrace();
					} finally {
						// 优雅地退出,释放相关资源
						eventLoopGroup.shutdownGracefully();
					}
				}
			});

			thread.start();
		}
	}

	/**
	 * 5秒后启动重连
	 */
	public synchronized void reconnect() {
		if (isReconnecting == false) {
			isReconnecting = true;
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
					try {
						//logger.info("客户端5秒后重连...");
						Thread.sleep(5000);
						//logger.info("客户端开始重连...");
						Bootstrap bootstrap = new Bootstrap();
						bootstrap.channel(NioSocketChannel.class)
								// 保持连接
								.option(ChannelOption.SO_KEEPALIVE, true)
								// 有数据立即发送
								.option(ChannelOption.TCP_NODELAY, true)
								// 绑定处理group
								.group(eventLoopGroup).remoteAddress(host, port)
								.handler(new ChannelInitializer() {
									@Override
									protected void initChannel(SocketChannel socketChannel) throws Exception {
										// 初始化编码器,解码器,处理器
										socketChannel.pipeline().addLast(
												new IdleStateHandler(0, 5, 0, TimeUnit.SECONDS),
												new RtIdleStateTrigger(), new LineBasedFrameDecoder(BufferSize.Default),
												new StringDecoder(Charset.forName("utf-8")), new RtClientHandler());
									}
								});
						// 进行连接
						ChannelFuture future;
						future = bootstrap.connect(host, port).sync();
						// 判断是否连接成功
						if (future.isSuccess()) {
							// 得到管道,便于通信
							socketChannel = (SocketChannel) future.channel();
							connectCallback.apply(true);
							isReconnecting = false;
							//logger.info("客户端重连成功...");
						} else {
							connectCallback.apply(false);
							//logger.info("客户端重连失败...");
							isReconnecting = false;
							RtClient.getInstance().reconnect();
						}
						// 等待客户端链路关闭,就是由于这里会将线程阻塞,导致无法发送信息,所以我这里开了线程
						future.channel().closeFuture().sync();
						//logger.info("客户端退出...");
					} catch (Exception e) {
						e.printStackTrace();
						connectCallback.apply(false);
						isReconnecting = false;
						RtClient.getInstance().reconnect();
					} finally {
						// 优雅地退出,释放相关资源
						eventLoopGroup.shutdownGracefully();
						//logger.info("客户端重连失败,优雅地退出,释放相关资源...");
					}
				}
			});
			thread.start();
		}
	}

	public synchronized void request(RtDataFromClient data) {
		if (socketChannel != null) {
			String msg = JsonUtils.tryToJson(data);
			byte[] bytes = String.format("%s%s", msg, System.getProperty("line.separator")).getBytes();
			ByteBuf byteBuf = Unpooled.buffer(bytes.length);
			byteBuf.writeBytes(bytes);
			socketChannel.writeAndFlush(byteBuf);
			//logger.info("客户端发送消息:" + msg);
		} else {
			//logger.info("客户端发送消息: failure, channel is null");
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy