Java tutorial
/* * Copyright 2015 The RPC Project * * The RPC Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package io.flood.rpc.network; import io.flood.common.utils.LogHelper; import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; public class ConnectorImpl extends AbstractSocketWapper implements Connector { private static final Logger LOG = LoggerFactory.getLogger(ConnectorImpl.class); private final Bootstrap boot = new Bootstrap(); private final AtomicBoolean isConnected = new AtomicBoolean(false); private final AtomicBoolean isInitiative = new AtomicBoolean(false); private final List<CompleteListener> listenerList = new ArrayList<CompleteListener>(); private Channel channel; private int id = -1; public ConnectorImpl(MessageDispatcher<NetPackage> messageDispatcher) { super(messageDispatcher); } public void addCompleteListener(CompleteListener listener) { listenerList.add(listener); } private synchronized void broadcastComplete(ChannelFuture future) { for (CompleteListener listener : listenerList) { listener.apply(future); } } public ChannelFuture connect(String address, int port, int retryTime) { boot.group(bossGroup).option(ChannelOption.TCP_NODELAY, true); boot.channel(NioSocketChannel.class); boot.handler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel ch) throws Exception { LinkedHashMap<String, ChannelHandler> handlers = getHandlers(); for (Map.Entry<String, ChannelHandler> entry : handlers.entrySet()) { ch.pipeline().addLast(entry.getKey(), entry.getValue()); } ch.pipeline().addLast("messageDecoder", new MessageDecoder()); ch.pipeline().addLast("messageEncoder", new MessageEncoder()); ch.pipeline().addLast("messageHandler", new MessageHandler(ConnectorImpl.this)); } }); return connect0(new InetSocketAddress(address, port), retryTime); } private ChannelFuture connect0(final SocketAddress address, final int retryTime) { id = SocketIdGenerator.nextId(); final ChannelFuture future = boot.connect(address); future.addListener(new GenericFutureListener<Future<? super Void>>() { public void operationComplete(io.netty.util.concurrent.Future<? super Void> completeFuture) throws Exception { broadcastComplete(future); if (completeFuture.isSuccess()) { channel = future.channel(); LOG.info(LogHelper.format(id, "connected to server ({}=>{})"), channel.localAddress(), channel.remoteAddress()); ConnectionManager.put(id, Connection.Type.Client, channel); future.channel().closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() { public void operationComplete(Future<? super Void> completeFuture) throws Exception { LOG.info( LogHelper.format(id, "connection closed ,after {} millisecond will be reconnect"), retryTime); if (!isInitiative.get()) { Thread.sleep(retryTime); connect0(address, retryTime); } } }); } else { LOG.info(LogHelper.format(id, "connet to server failed({})"), address); } } }); return future; } public void shutdown() { isInitiative.set(true); bossGroup.shutdownGracefully(); } public void writeAndFlush(Object object) throws IOException { if (channel == null || !channel.isActive()) { throw new IOException("not connected to server or not active!"); } channel.writeAndFlush(object); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { isConnected.set(true); } @Override public boolean isAlived() { return isConnected.get(); } }