/*
* Copyright 2008-2009 the original author or authors.
*
* Licensed 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 net.hasor.rsf.rpc.net;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import net.hasor.core.AppContext;
import net.hasor.core.future.BasicFuture;
import net.hasor.rsf.InterAddress;
import net.hasor.rsf.RsfEnvironment;
import net.hasor.rsf.domain.OptionInfo;
import net.hasor.rsf.domain.ProtocolStatus;
import net.hasor.rsf.domain.RsfException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
/**
* RPC协议连接器,负责创建某个特定RPC协议的网络事件。
* tips:传入的网络连接,交给{@link LinkPool}进行处理,{@link Connector}本身不维护任何连接。
* @version : 2017年01月16日
* @author 赵永春(zyc@hasor.net)
*/
@ChannelHandler.Sharable
public class Connector extends ChannelInboundHandlerAdapter implements ReceivedListener {
protected Logger logger = LoggerFactory.getLogger(getClass());
private final String protocol;
private final AppContext appContext;
private final InterAddress bindAddress;
private final InterAddress gatewayAddress;
private RsfChannel localListener;
private final LinkPool linkPool;
private final ReceivedListener receivedListener;
private final EventLoopGroup workLoopGroup;
private final ProtocolHandler handler;
public Connector(AppContext appContext, String protocol, InterAddress local, InterAddress gateway,//
final ReceivedListener receivedListener, LinkPool linkPool, EventLoopGroup workLoopGroup) throws ClassNotFoundException {
//
this.protocol = protocol;
this.appContext = appContext;
this.bindAddress = local;
this.gatewayAddress = gateway;
this.receivedListener = receivedListener;
this.linkPool = linkPool;
this.workLoopGroup = workLoopGroup;
//
RsfEnvironment env = this.appContext.getInstance(RsfEnvironment.class);
Map<String, String> protocolHandlerMapping = env.getSettings().getProtocolHandlerMapping();
String handlerName = protocolHandlerMapping.get(this.protocol);
Class<?> handlerType = appContext.getClassLoader().loadClass(handlerName);
this.handler = (ProtocolHandler) appContext.getInstance(handlerType);
}
@Override
public String toString() {
InterAddress local = this.gatewayAddress;
local = (local == null) ? this.bindAddress : local;
return "Connector{ protocol='" + protocol + "', bindAddress=" + local + '}';
}
//
//
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
this.exceptionCaught(ctx, null);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
String hostPort = converToHostProt(ctx);
if (cause == null) {
this.logger.warn("close socket=" + hostPort + " channel Inactive.");
} else {
this.logger.error("close socket=" + hostPort + " with error -> " + cause.getMessage(), cause);
}
this.linkPool.closeConnection(hostPort);
ctx.close();
}
/** 接收解析好的 RequestInfo、ResponseInfo 对象,并将它们转发到 {@link RsfChannel}接收事件中。 */
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof OptionInfo) {
String hostPort = converToHostProt(ctx);
BasicFuture<RsfChannel> channel = this.linkPool.findChannel(hostPort);
if (channel == null || !channel.isDone()) {
this.exceptionCaught(ctx, new RsfException(ProtocolStatus.NetworkError, "the " + hostPort + " connection is not in the pool."));
return;
}
RsfChannel rsfChannel = channel.get();
if (rsfChannel.getTarget() == null) {
this.exceptionCaught(ctx, new RsfException(ProtocolStatus.NetworkError, "the " + hostPort + " connection is not management."));
return;
}
//
rsfChannel.receivedData((OptionInfo) msg);
}
super.channelRead(ctx, msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
if (socketAddress == null) {
super.channelActive(ctx);
return;
}
String hostAddress = socketAddress.getAddress().getHostAddress();
int port = socketAddress.getPort();
String hostPort = hostAddress + ":" + port;
this.logger.info("connected form {}", hostPort);
//
InterAddress target = new InterAddress(this.protocol, hostAddress, port, "unknown");
BasicFuture<RsfChannel> future = this.linkPool.preConnection(hostPort);
RsfChannel rsfChannel = null;
if (future.isDone()) {
rsfChannel = future.get();
} else {
rsfChannel = new RsfChannel(this.protocol, target, ctx.channel(), LinkType.In);
future.completed(rsfChannel);
}
//
boolean accept = this.handler.acceptIn(this, rsfChannel);
if (accept) {
rsfChannel.addListener(this);
} else {
this.logger.warn("connection refused form {} ,", hostPort);
this.linkPool.closeConnection(hostPort);
ctx.close();
}
//
}
@Override
public void receivedMessage(RsfChannel rsfChannel, OptionInfo info) throws IOException {
if (!rsfChannel.isActive()) {
return;
}
this.receivedListener.receivedMessage(rsfChannel, info);
}
//
//
/** 监听的本地端口号 */
public InterAddress getBindAddress() {
return this.bindAddress;
}
/** 如果工作在内网,这里返回配置的外网映射地址 */
public InterAddress getGatewayAddress() {
return this.gatewayAddress;
}
//
//
/** 连接到远程机器 */
public void connectionTo(final InterAddress hostAddress, final BasicFuture<RsfChannel> result) {
//
//
Bootstrap boot = new Bootstrap();
boot.group(this.workLoopGroup);
boot.channel(NioSocketChannel.class);
boot.handler(new ChannelInitializer<SocketChannel>() {
public void initChannel(SocketChannel ch) throws Exception {
ChannelHandler[] handlerArrays = channelHandler();
ArrayList<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
handlers.addAll(Arrays.asList(handlerArrays)); // 编码解码器
handlers.add(Connector.this); // 转发RequestInfo、ResponseInfo到RSF
//
ch.pipeline().addLast(handlers.toArray(new ChannelHandler[handlers.size()]));
}
});
ChannelFuture future = configBoot(boot).connect(hostAddress.toSocketAddress());
//
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
future.channel().close();
logger.error("connect to {} error.", hostAddress, future.cause());
result.failed(future.cause());
} else {
Channel channel = future.channel();
logger.info("connect to {} Success.", hostAddress);
result.completed(new RsfChannel(protocol, bindAddress, channel, LinkType.Out));
}
}
});
}
/**
* 启动本地监听器
* @param listenLoopGroup 监听器线程组
*/
public void startListener(NioEventLoopGroup listenLoopGroup) {
//
ServerBootstrap boot = new ServerBootstrap();
boot.group(listenLoopGroup, this.workLoopGroup);
boot.channel(NioServerSocketChannel.class);
boot.childHandler(new ChannelInitializer<SocketChannel>() {
public void initChannel(SocketChannel ch) throws Exception {
ChannelHandler[] handlerArrays = channelHandler();
ArrayList<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
handlers.addAll(Arrays.asList(handlerArrays)); // 编码解码器
handlers.add(Connector.this); // 转发RequestInfo、ResponseInfo到RSF
//
ch.pipeline().addLast(handlers.toArray(new ChannelHandler[handlers.size()]));
}
});
boot.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
boot.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = configBoot(boot).bind(this.bindAddress.toSocketAddress());
//
final BasicFuture<RsfChannel> result = new BasicFuture<RsfChannel>();
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
future.channel().close();
result.failed(future.cause());
} else {
Channel channel = future.channel();
result.completed(new RsfChannel(protocol, bindAddress, channel, LinkType.Listener));
}
}
});
try {
this.localListener = result.get();
logger.info("rsf Server started at {}", this.bindAddress);
} catch (Exception e) {
logger.error("rsf start listener error: " + e.getMessage(), e);
throw new RsfException(ProtocolStatus.NetworkError, this.bindAddress.toString() + " -> " + e.getMessage());
}
//
}
private <T extends AbstractBootstrap<?, ?>> T configBoot(T boot) {
boot.option(ChannelOption.SO_KEEPALIVE, true);
// boot.option(ChannelOption.SO_BACKLOG, 128);
// boot.option(ChannelOption.SO_BACKLOG, 1024);
// boot.option(ChannelOption.SO_RCVBUF, 1024 * 256);
// boot.option(ChannelOption.SO_SNDBUF, 1024 * 256);
boot.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
return boot;
}
/**停止监听器*/
public void shutdown() {
this.localListener.close();
}
public void mappingTo(RsfChannel rsfChannel, InterAddress interAddress) {
rsfChannel.inverseMappingTo(interAddress);
this.linkPool.mappingTo(rsfChannel, interAddress.getHostPort());
}
//
private static String converToHostProt(ChannelHandlerContext ctx) {
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
return socketAddress.getAddress().getHostAddress() + ":" + socketAddress.getPort();
}
private ChannelHandler[] channelHandler() {
return this.handler.channelHandler(this, this.appContext);
}
}