如何让Netty管理任意客户端连接而非服务端连接?

最近在做一个项目,网址见:http://git.oschina.net/qiangzigege/MySQL-Binlog

要解决的一个问题就是:假如我想发起一个连接去连接mysql,成功后,如何让这个连接比较顺畅的纳入到netty的管理范围呢?

---不多说,上代码!

1)NettyQueue.java---存放连接队列

public class NettyQueue {

// poll: 若队列为空,返回null。

// remove:若队列为空,抛出NoSuchElementException异常。

// take:若队列为空,发生阻塞,等待有元素。

 

// put---无空间会等待

// add--- 满时,立即返回,会抛出异常

// offer---满时,立即返回,不抛异常

// private static final Logger logger =

// LoggerFactory.getLogger(MonitorQueue.class);

private static final Logger logger = LogManager.getLogger(NettyQueue.class);

public static BlockingQueue<Connection> objectQueue = new LinkedBlockingQueue<Connection>();

 

public static void addObject(Connection obj) {

objectQueue.offer(obj);

new Thread(new Runnable() {// 启动一个线程去触发...

@Override

public void run() {

// TODO Auto-generated method stub

MyProperties p = MyProperties.getInstance();

if (null != p) {// 连接本机的netty服务器

String ip = "127.0.0.1";

int port = p.getNetty_port();

if (null != ip && port >= 0) {

Socket socket = null;

try {

socket = new Socket();

System.out.println("ip: " + ip + " port:" + port);

socket.connect(new InetSocketAddress(ipport), 6 * 1000);// 还是给一个连接超时6秒

TimeUtils.sleepSeconds(6);// 睡眠6秒再退出,足够的时间给netty处理连接了

catch (Exception e) {

LoggerUtils.error(loggere.toString());

finally {

if (null != socket) {// 主动关闭连接

try {

socket.close();

catch (IOException e) {

}

}

// try...catch...finally结束

// if结束

}

}

}).start();

 

};

 

public static Connection getObject() {

return objectQueue.poll();

}

 

}


2)谁往里面放连接呢?

大体的代码是:

// 4)尝试创建连接conn

Connection conn = null;

int lastIndex = taskPath.lastIndexOf("/");

String target = taskPath.substring(lastIndex + 1);

String[] elements = target.split(":");

String ip = elements[0];

int port = Integer.valueOf(elements[1]);

try {

LoggerUtils.debug(logger"target machine:" + ip + ":" + port);

conn = ConnectionFactory.makeObject(ip, port, taskData, currentPath, binlogPositionPath, fn, fp);

catch (Exception e) {

LoggerUtils.debug(loggere.toString());

conn = null;

}

// conn = null;

if (null != conn) {// 创建成功

LoggerUtils.debug(logger"create socket succeed: " + conn.getSocketChannel());

NettyQueue.addObject(conn);

}


public static Connection makeObject(String ipint port, String data, String runningPath, String binlogPositionPath,

String initialFilenamelong initialPosition) {

Connection myConn = null;

 

if (null != ip && port >= 0) {

try {

// 在这里创建具体的对象,注意这里的用法

SocketAddress sAddress = new InetSocketAddress(ipport);

SocketChannel sChannel = SocketChannel.open(sAddress);

sChannel.configureBlocking(false);// 非阻塞

myConn = new Connection(sChannel,

ConnectionAttributes.parse(data).setIpPort(ipport).setRunningZKPath(runningPath)

.setBinlogPositionZKPath(binlogPositionPath)

.setClientId(Long.parseLong(ip.replaceAll(".""") + port))

.updateBinlogNameAndPosition(initialFilenameinitialPosition));

catch (Exception e) {

LoggerUtils.error(loggere.toString());

}

}

 

// 无论如何,都返回连接,失敗則返回null

return myConn;

}




3)谁负责取出来呢?

注意我们在第一部分是触发了一个连接本地127.0.0.1的一个连接,这个实际是连接本地的Netty服务器。

需要知道Netty如何启动的

EventLoopGroup workerGroup = new NioEventLoopGroup(worker);

try {

ServerBootstrap b = new ServerBootstrap();

b.group(bossGroupworkerGroup).channel(MyNioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG, 2048).childHandler(new ChildChannelHandler());

// 绑定端口,同步等待成功

ChannelFuture f = b.bind(port).sync();

// 等待服务端监听端口关闭

LoggerUtils.info(logger"netty server start ok.");

f.channel().closeFuture().sync();

重点就在MyNioServerSocketChannel.class

public class MyNioServerSocketChannel extends NioServerSocketChannel {

private static final Logger logger = LogManager.getLogger(MyNioServerSocketChannel.class);

 

// 继承已经有的类,用于干预连接

@Override

protected int doReadMessages(List<Object> bufthrows Exception {

// logger.debug("\ndoReadMessages(...) enter....\n触发了新的连接...开始准备2阶段提取");

// logger.debug("buf :" + buf);

// LoggerUtils.debug(logger, new Exception().toString());

// 原始部分,直接关闭

try {

SocketChannel tempCh = javaChannel().accept();

tempCh.close();

catch (Exception e) {

 

}

 

// 移花接木

Connection connection = NettyQueue.getObject();

try {

if (connection != null) {

MyNioSocketChannel channel = new MyNioSocketChannel(thisconnection.getSocketChannel(),

connection.getAttributes());

buf.add(channel);

LoggerUtils.debug(logger"db conn is as follows: " + connection.getSocketChannel());

// logger.debug("buf :" + buf);

return 1;

}

catch (Throwable t) {

LoggerUtils.info(logger"Failed to create a new channel from an accepted socket." + t);

try {

connection.close();

catch (Throwable t2) {

LoggerUtils.info(logger"Failed to close a socket." + t2);

}

}

 

return 0;

 

}

}

所以,到这里应该就知道了,用了一种诱骗式的方法,

巧妙的绕过了Netty的平常只接收主动连接自己的服务端socket的限制

使得任意客户端连接都可以纳入netty的管理范围

同时对netty框架本身不构成任何入侵性。

转载于:https://my.oschina.net/qiangzigege/blog/632501

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过创建多个`Bootstrap`实例来实现一个客户端同时连接多个服务端,并通过`Channel`的`attr`属性来区分不同的连接。 具体实现步骤如下: 1. 创建多个`Bootstrap`实例,每个实例都对应一个服务端连接; 2. 为每个`Bootstrap`实例设置相应的`EventLoopGroup`和`ChannelHandler`; 3. 调用每个`Bootstrap`实例的`connect()`方法来建立连接; 4. 在`ChannelInitializer`的`initChannel()`方法中,为每个`Channel`设置`attr`属性,用于区分不同的连接; 5. 在`ChannelHandler`中,可以通过`ctx.channel().attr(key).get()`方法获取当前`Channel`的`key`属性值,从而区分不同的连接。 示例代码: ```java // 创建两个 Bootstrap 实例,每个实例都对应一个服务端连接 Bootstrap b1 = new Bootstrap(); Bootstrap b2 = new Bootstrap(); // 设置第一个 Bootstrap 的 EventLoopGroup 和 ChannelHandler b1.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.attr(AttributeKey.valueOf("server")).set("server1"); ch.pipeline().addLast(new MyClientHandler()); } }); // 设置第二个 Bootstrap 的 EventLoopGroup 和 ChannelHandler b2.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.attr(AttributeKey.valueOf("server")).set("server2"); ch.pipeline().addLast(new MyClientHandler()); } }); // 分别调用 connect() 方法建立连接 ChannelFuture f1 = b1.connect("127.0.0.1", 8080).sync(); ChannelFuture f2 = b2.connect("127.0.0.1", 8081).sync(); // 在 MyClientHandler 中通过 ctx.channel().attr("server").get() 获取当前连接的服务器名称 public class MyClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { String server = (String) ctx.channel().attr(AttributeKey.valueOf("server")).get(); System.out.println("Connected to " + server); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值