Feature Request: udp server with netty: create a channel for each remote address #344

Open
rzorzorzo opened this Issue May 19, 2012 · 18 comments

Comments

Projects
None yet
9 participants
@trustin

This comment has been minimized.

Show comment Hide comment
@trustin

trustin May 21, 2012

Member

Hi Ron,

How would you determine the life cycle of the channel? UDP has no notion of opening and closing a connection. MINA mimics a TCP-ish connection by triggering the disconnect event when no packet is received from the remote address for a while. In Netty, I can essentially do the same:

  1. channelConnected() when the first packet from a peer
  2. channelDisconnected() when your handler calls disconnect() or close() explicitly or the connection is idle for pretty long time such as 5 minutes.

If a user wants complete control over the life cycle of the channel, idleness timeout could be set to a very large value and he or she could call disconnect() or close() (if forgot, screwed :-)).

WDYT?

Member

trustin commented May 21, 2012

Hi Ron,

How would you determine the life cycle of the channel? UDP has no notion of opening and closing a connection. MINA mimics a TCP-ish connection by triggering the disconnect event when no packet is received from the remote address for a while. In Netty, I can essentially do the same:

  1. channelConnected() when the first packet from a peer
  2. channelDisconnected() when your handler calls disconnect() or close() explicitly or the connection is idle for pretty long time such as 5 minutes.

If a user wants complete control over the life cycle of the channel, idleness timeout could be set to a very large value and he or she could call disconnect() or close() (if forgot, screwed :-)).

WDYT?

@rzorzorzo

This comment has been minimized.

Show comment Hide comment
@rzorzorzo

rzorzorzo May 22, 2012

Hello Trustin,

yes to both. The timeout should be a factory option. maybe we should have 2 parameters: read-idle and write-idle.

-- Ron

Hello Trustin,

yes to both. The timeout should be a factory option. maybe we should have 2 parameters: read-idle and write-idle.

-- Ron

@rzorzorzo

This comment has been minimized.

Show comment Hide comment
@rzorzorzo

rzorzorzo May 27, 2012

Trustin,

looking a bit more into udp i found a test (in german, use google translate)

http://blog.wlami.com/index.php/2011/06/udp-pakete-in-java-20-mal-schneller-verschicken/

stating that the following code:

DatagramSocket s = new DatagramSocket();
s.connect(InetAddress.getLocalHost(), 1337);
for (int i = 0; i < 10000; i++) {
byte[] content = new Long(System.currentTimeMillis()).toString().getBytes();
DatagramPacket packet = new DatagramPacket(content, content.length);
s.send(packet);

is 20x faster than

DatagramSocket sock = new DatagramSocket();
for (int i = 0; i < 1000; i++) {
byte[] content = new Long(System.currentTimeMillis()).toString().getBytes();
DatagramPacket packet = new DatagramPacket(content, content.length, InetAddress.getLocalHost(), 1337);
sock.send(packet);
}

For Oio netty is currently using the slower variant. The first variant, eg a per client socket, requires a per client channel.
This is similar to TCP where a per client socket is stored in the channel.

Therefore mimic of TCP connection will also have a significant performance advantage.

I do not know how this is for Nio, but I suppose it should be similar.

-- Ron

Trustin,

looking a bit more into udp i found a test (in german, use google translate)

http://blog.wlami.com/index.php/2011/06/udp-pakete-in-java-20-mal-schneller-verschicken/

stating that the following code:

DatagramSocket s = new DatagramSocket();
s.connect(InetAddress.getLocalHost(), 1337);
for (int i = 0; i < 10000; i++) {
byte[] content = new Long(System.currentTimeMillis()).toString().getBytes();
DatagramPacket packet = new DatagramPacket(content, content.length);
s.send(packet);

is 20x faster than

DatagramSocket sock = new DatagramSocket();
for (int i = 0; i < 1000; i++) {
byte[] content = new Long(System.currentTimeMillis()).toString().getBytes();
DatagramPacket packet = new DatagramPacket(content, content.length, InetAddress.getLocalHost(), 1337);
sock.send(packet);
}

For Oio netty is currently using the slower variant. The first variant, eg a per client socket, requires a per client channel.
This is similar to TCP where a per client socket is stored in the channel.

Therefore mimic of TCP connection will also have a significant performance advantage.

I do not know how this is for Nio, but I suppose it should be similar.

-- Ron

@trustin

This comment has been minimized.

Show comment Hide comment
@trustin

trustin May 27, 2012

Member

Netty does both. If you have a connected datagram channel and did not
specify a remote address in your Channel.write() call, it will go the
former route. Please let me know if this is not working as intended.

Member

trustin commented May 27, 2012

Netty does both. If you have a connected datagram channel and did not
specify a remote address in your Channel.write() call, it will go the
former route. Please let me know if this is not working as intended.

@gsimard

This comment has been minimized.

Show comment Hide comment
@gsimard

gsimard Nov 19, 2012

Trustin, regarding your previous post about an UDP packet generating a channelConnected event, is this a feature implemented as of now ? I too would like a single channel for each remote address, this would make it easier to handle multiple stateful connections.

gsimard commented Nov 19, 2012

Trustin, regarding your previous post about an UDP packet generating a channelConnected event, is this a feature implemented as of now ? I too would like a single channel for each remote address, this would make it easier to handle multiple stateful connections.

@igreenfield

This comment has been minimized.

Show comment Hide comment
@igreenfield

igreenfield Oct 27, 2013

What the status of this?

What the status of this?

@trustin

This comment has been minimized.

Show comment Hide comment
@trustin

trustin Nov 2, 2013

Member

It's unimplemented. Please feel free to volunteer.

Member

trustin commented Nov 2, 2013

It's unimplemented. Please feel free to volunteer.

@igreenfield

This comment has been minimized.

Show comment Hide comment
@igreenfield

igreenfield Nov 3, 2013

I will be glad to implement it.

I will be glad to implement it.

@normanmaurer

This comment has been minimized.

Show comment Hide comment
@normanmaurer

normanmaurer Nov 3, 2013

Member

@igreenfield feel free to open a pull-req once you have it done... thanks!

Member

normanmaurer commented Nov 3, 2013

@igreenfield feel free to open a pull-req once you have it done... thanks!

@igreenfield

This comment has been minimized.

Show comment Hide comment
@igreenfield

igreenfield Nov 3, 2013

@normanmaurer could you let me the point where the channel creation happen?

@normanmaurer could you let me the point where the channel creation happen?

@Scottmitch Scottmitch added the feature label Sep 23, 2014

@Scottmitch Scottmitch modified the milestones: 5.0.0.Alpha3, 5.0.0.Alpha2 Sep 23, 2014

@mikomarrache

This comment has been minimized.

Show comment Hide comment
@mikomarrache

mikomarrache Dec 20, 2015

Hi,

Any news regarding this feature?

Thanks!

Hi,

Any news regarding this feature?

Thanks!

@igreenfield

This comment has been minimized.

Show comment Hide comment
@igreenfield

igreenfield Dec 21, 2015

Didn't have time to finish it.

Didn't have time to finish it.

@trustin trustin modified the milestone: 5.0.0.Alpha3 Mar 7, 2016

@Underbalanced

This comment has been minimized.

Show comment Hide comment
@Underbalanced

Underbalanced Jul 23, 2016

@igreenfield do you have any work completed that one of us can pick up and finish?

@igreenfield do you have any work completed that one of us can pick up and finish?

@Shevchik

This comment has been minimized.

Show comment Hide comment
@Shevchik

Shevchik Aug 3, 2016

I wrote something almost like that. Not sure that i got how netty works internally right, but this code works, so you can use it to code something better.
(This code is for netty 4.0)

https://github.com/Shevchik/UdpServerSocketChannel

Shevchik commented Aug 3, 2016

I wrote something almost like that. Not sure that i got how netty works internally right, but this code works, so you can use it to code something better.
(This code is for netty 4.0)

https://github.com/Shevchik/UdpServerSocketChannel

@Underbalanced

This comment has been minimized.

Show comment Hide comment
@Underbalanced

Underbalanced Aug 3, 2016

I have a system written as well but its tied to a TCP server. Its to case specific to be ready here. Basically the TCP Client connects and on success starts a UDP server. The TCP Server starts a UDP Server when the TCP Server starts. When the server receives a client connection it sets up a Nio or Epoll DatagramChannel and attaches it to the same event loop of the servers TCP Connection. The client sends a session id in the udp packet, I use a variant length compression on the ID, this way the server can identity which session to use for handling the data. When the server writes UDP it does not send an ID because it writes to the Clients unique DatagramChannel.

The following code is in the works. The first three classes are the UDP Channel stuff, the last two are implementations of a session and the extension of that session which also has the UDP channel in it. Its a incomplete class missing methods and correct modifiers. I use a multiple connection system for my game. Secure TCP, Unsecure TCP, UDP with security as an option through my implementations. This was all to give an idea of how I have implemented a UDP Channel system for the below question.

Generic Wrapped Channel
Datagram Wrapped Channel
Client NioDatagram Wrapped Channel

AbstractNettySession
Actual Session which extends the above class and uses the NioDatagramChannel

Question/Though:

  1. I do not see a reason this would really have an application to have a channel per UDP client without a TCP connection? Do we think it’s easy and worth it to decouple TCP from UDP?

Underbalanced commented Aug 3, 2016

I have a system written as well but its tied to a TCP server. Its to case specific to be ready here. Basically the TCP Client connects and on success starts a UDP server. The TCP Server starts a UDP Server when the TCP Server starts. When the server receives a client connection it sets up a Nio or Epoll DatagramChannel and attaches it to the same event loop of the servers TCP Connection. The client sends a session id in the udp packet, I use a variant length compression on the ID, this way the server can identity which session to use for handling the data. When the server writes UDP it does not send an ID because it writes to the Clients unique DatagramChannel.

The following code is in the works. The first three classes are the UDP Channel stuff, the last two are implementations of a session and the extension of that session which also has the UDP channel in it. Its a incomplete class missing methods and correct modifiers. I use a multiple connection system for my game. Secure TCP, Unsecure TCP, UDP with security as an option through my implementations. This was all to give an idea of how I have implemented a UDP Channel system for the below question.

Generic Wrapped Channel
Datagram Wrapped Channel
Client NioDatagram Wrapped Channel

AbstractNettySession
Actual Session which extends the above class and uses the NioDatagramChannel

Question/Though:

  1. I do not see a reason this would really have an application to have a channel per UDP client without a TCP connection? Do we think it’s easy and worth it to decouple TCP from UDP?
@Shevchik

This comment has been minimized.

Show comment Hide comment
@Shevchik

Shevchik Aug 3, 2016

There are many protocols that work using udp, but has transmission control and network connect/disconnect packets, such as RakNet for example.
And implementing it using only 1 channel for everything becomes a pain in the ass.

Shevchik commented Aug 3, 2016

There are many protocols that work using udp, but has transmission control and network connect/disconnect packets, such as RakNet for example.
And implementing it using only 1 channel for everything becomes a pain in the ass.

@Underbalanced

This comment has been minimized.

Show comment Hide comment
@Underbalanced

Underbalanced Jan 15, 2017

@trustin @normanmaurer I think this issue would be best resolved by adding a simple UDP Channel Factory that you would pair with a existing TCP server. UDP Factory will take a new tcp channel and return a UDP channel using the same resources. This would allow persons to be able to seamlessly use UDP or TCP with their own further implementation. They would still have to have a UDP server on the other end. If warranted perhaps I could also create a TCP Client/UDP server and TCP Client/UDP Server container later.

I will first make and then PR a UDP Channel Factory.

Underbalanced commented Jan 15, 2017

@trustin @normanmaurer I think this issue would be best resolved by adding a simple UDP Channel Factory that you would pair with a existing TCP server. UDP Factory will take a new tcp channel and return a UDP channel using the same resources. This would allow persons to be able to seamlessly use UDP or TCP with their own further implementation. They would still have to have a UDP server on the other end. If warranted perhaps I could also create a TCP Client/UDP server and TCP Client/UDP Server container later.

I will first make and then PR a UDP Channel Factory.

@Underbalanced

This comment has been minimized.

Show comment Hide comment
@Underbalanced

Underbalanced Jan 15, 2017

Something like this?

package com.freeuniversegames.general.general_eight.netty.channels;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.socket.oio.OioDatagramChannel;
import io.netty.channel.socket.oio.OioSocketChannel;

import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;


/**
 * This Factory will take an existing Channel or ChannelHandlerContext and build a UDP channel and allow
 * a person to have a UDP channel per TCP channel.
 * 
 * These UDP channels can be written to similar to TCP channels with handlers or not. Once the buffer
 * reaches the end of the channel the ByteBuf will be written to a Datagram Packet. 
 *
 * These channels are compatible with Channel Group use, but need to be closed specially since they are 
 * disconnected from normal TCP handling. In this class we add the option of auto closing the UDP channel 
 * based on the TCP channel. 
 * 
 * A UDP server must exist on the other end and it is up to the implementer on how to sort packets written.
 *
 */
public class UdpChannelFactory {
    
    private Class<? extends DatagramChannel> getChannelType(Channel channel) throws UnsupportedChannel {
        if(channel instanceof NioSocketChannel){
            return NioDatagramChannel.class;
        } else if (channel instanceof EpollSocketChannel) {
            return EpollDatagramChannel.class;
        } else if (channel instanceof OioSocketChannel){
            return OioDatagramChannel.class;
        } else {
            throw new UnsupportedChannel(String.valueOf(channel.getClass()));
        }
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), port, true);
    }

    public ChannelFuture getAndConnect(Channel channel, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, port, true);
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, port, true);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, parameterTypes, args, port, true);
    }
    
    public ChannelFuture getAndConnect(ChannelHandlerContext ctx) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), true);
    }

    public ChannelFuture getAndConnect(Channel channel) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, true);
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, true);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, parameterTypes, args, true);
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
         return getAndConnect(ctx.channel(), port, autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel).channel().connect(new InetSocketAddress(((InetSocketAddress) channel.remoteAddress()).getAddress(), port));
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, port, autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel, parameterTypes, args).channel().connect((new InetSocketAddress(((InetSocketAddress) channel.remoteAddress()).getAddress(), port)));
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel).channel().connect(channel.remoteAddress());
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel, parameterTypes, args).channel().connect(channel.remoteAddress());
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }
    
    public ChannelFuture get(ChannelHandlerContext ctx) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return get(ctx.channel());
    }
    
    public ChannelFuture get(Channel channel) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return channel.eventLoop().register(getChannelType(channel).getDeclaredConstructor().newInstance());
    }
    
    public ChannelFuture get(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return get(ctx.channel(), parameterTypes, args);
    }
    
    public ChannelFuture get(Channel channel, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return channel.eventLoop().register(getChannelType(channel).getDeclaredConstructor(parameterTypes).newInstance(args));
    }
    
    public ChannelFuture dispose(Channel channel){
        return channel.deregister().channel().close();
    }
}

Something like this?

package com.freeuniversegames.general.general_eight.netty.channels;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.socket.oio.OioDatagramChannel;
import io.netty.channel.socket.oio.OioSocketChannel;

import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;


/**
 * This Factory will take an existing Channel or ChannelHandlerContext and build a UDP channel and allow
 * a person to have a UDP channel per TCP channel.
 * 
 * These UDP channels can be written to similar to TCP channels with handlers or not. Once the buffer
 * reaches the end of the channel the ByteBuf will be written to a Datagram Packet. 
 *
 * These channels are compatible with Channel Group use, but need to be closed specially since they are 
 * disconnected from normal TCP handling. In this class we add the option of auto closing the UDP channel 
 * based on the TCP channel. 
 * 
 * A UDP server must exist on the other end and it is up to the implementer on how to sort packets written.
 *
 */
public class UdpChannelFactory {
    
    private Class<? extends DatagramChannel> getChannelType(Channel channel) throws UnsupportedChannel {
        if(channel instanceof NioSocketChannel){
            return NioDatagramChannel.class;
        } else if (channel instanceof EpollSocketChannel) {
            return EpollDatagramChannel.class;
        } else if (channel instanceof OioSocketChannel){
            return OioDatagramChannel.class;
        } else {
            throw new UnsupportedChannel(String.valueOf(channel.getClass()));
        }
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), port, true);
    }

    public ChannelFuture getAndConnect(Channel channel, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, port, true);
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, port, true);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args, int port) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, parameterTypes, args, port, true);
    }
    
    public ChannelFuture getAndConnect(ChannelHandlerContext ctx) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), true);
    }

    public ChannelFuture getAndConnect(Channel channel) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, true);
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, true);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(channel, parameterTypes, args, true);
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
         return getAndConnect(ctx.channel(), port, autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel).channel().connect(new InetSocketAddress(((InetSocketAddress) channel.remoteAddress()).getAddress(), port));
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, port, autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args, int port, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel, parameterTypes, args).channel().connect((new InetSocketAddress(((InetSocketAddress) channel.remoteAddress()).getAddress(), port)));
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel).channel().connect(channel.remoteAddress());
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }

    public ChannelFuture getAndConnect(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return getAndConnect(ctx.channel(), parameterTypes, args, autoClose);
    }

    public ChannelFuture getAndConnect(Channel channel, Class<?>[] parameterTypes, Object[] args, boolean autoClose) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        ChannelFuture connect = get(channel, parameterTypes, args).channel().connect(channel.remoteAddress());
        if(autoClose) channel.closeFuture().addListeners((ChannelFutureListener) future -> connect.channel().close());
        return connect;
    }
    
    public ChannelFuture get(ChannelHandlerContext ctx) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return get(ctx.channel());
    }
    
    public ChannelFuture get(Channel channel) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return channel.eventLoop().register(getChannelType(channel).getDeclaredConstructor().newInstance());
    }
    
    public ChannelFuture get(ChannelHandlerContext ctx, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return get(ctx.channel(), parameterTypes, args);
    }
    
    public ChannelFuture get(Channel channel, Class<?>[] parameterTypes, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, UnsupportedChannel {
        return channel.eventLoop().register(getChannelType(channel).getDeclaredConstructor(parameterTypes).newInstance(args));
    }
    
    public ChannelFuture dispose(Channel channel){
        return channel.deregister().channel().close();
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment