iXô
iXô

Reputation: 1181

Cannot reply in netty using udp socket

I would like to use netty to create a udp server that reply back.

The old code was in c and used this kind of code :

sockHndl = socket(AF_INET,SOCK_DGRAM,0);
sockConf.sin_family = AF_INET;
sockConf.sin_addr.s_addr = INADDR_ANY;
sockConf.sin_port = htons(33333);

bind(sockHndl, (struct sockaddr*)&sockConf, sizeof(sockConf));

// in a thread
recvfrom(sockHndl, buffer, 1515, 0, (struct sockaddr*)&sockConf, &s);

// process any recevied data
....

// reply
sendto(sockHndl, buffer, strlen(buffer), 0, (struct sockaddr*)&sockConf, sizeof(sockConf));

This code works, but I have to re-implement it in java using netty.

Using netty in tcp is not a problem, but replying with netty to the client is a problem for me, if I want to write on the channel, it failed with a java.nio.channels.NotYetConnectedException.

Maybe this is linked to this issue on netty, but I don't know how I can reproduce the c behaviour in my code.

final Bootstrap b = new Bootstrap();

b.group(comIOEventLoop).channel(NioDatagramChannel.class).handler(new ChannelInitializer<NioDatagramChannel>()
{
    protected void initChannel(NioDatagramChannel ch) throws Exception
    {
        final ChannelPipeline p = ch.pipeline();
        p.addLast("SITCDecoder", new SITCDecoder());
        p.addLast("SITCEncoder", new SITCEncoder());
        p.addLast("SITCHandler", new SimpleChannelInboundHandler<ITCUdpRequest>()
        {
            protected void channelRead0(ChannelHandlerContext ctx, ITCUdpRequest msg) throws Exception
            {
                // here ctx.channel().remoteAddress() == null !
                switch(msg.getType())
                {
                    case GET_PARAMS_0:
                        send(ctx.channel(), new ITCUdpResponse(-80, -20));
                        break;
                }
            }

            public void send(final Channel channel, final ITCUdpResponse data)
            {
                if(data == null)
                {
                    LOGGER.error("data == null !!!");
                }

                channel.writeAndFlush(data).addListener(new GenericFutureListener<Future<Void>>()
                {
                    public void operationComplete(final Future<Void> future) throws Exception
                    {
                        if(future.isDone() && future.isSuccess())
                        {
                            LOGGER.debug("OK");
                        }
                        else
                        {
                            LOGGER.error("error " + future.isDone() + " - " + future.isSuccess());
                            if(!future.isSuccess())
                            {
                                future.cause().printStackTrace();
                            }
                        }
                    }
                });
            }
        });
    }
});

channel = b.bind(port).sync().channel();
channel.closeFuture().await();

How can I reply to the client ?

Thanks.

Extra edit :

Decoder code :

    public class SITCDecoder extends SimpleChannelInboundHandler<DatagramPacket>
{
    private static final Logger LOGGER              = LoggerFactory.getLogger(SITCDecoder.class);

    private static final String MSG_DD_HEADER       = "SITCDDVAL:";
    private static final int    MSG_DD_HEADER_SIZE  = MSG_DD_HEADER.length();

    protected void channelRead0(final ChannelHandlerContext ctx, final DatagramPacket msg) throws Exception
    {
        final ByteBuf data = (ByteBuf) msg.content();

        if(data != null)
        {
            // we must be able to read at last <code>MSG_HEADER_SIZE</code> Bytes
            if(data.readableBytes() < MSG_DD_HEADER_SIZE)
            {
                LOGGER.error("Not enought data");
                return;
            }

            if(!data.readBytes(MSG_DD_HEADER_SIZE).toString(StandardCharsets.ISO_8859_1).equals(MSG_DD_HEADER))
            {
                LOGGER.error("Header not found");
            }

            final String payload = data.readBytes(data.readableBytes()).toString(StandardCharsets.ISO_8859_1);

            final RecyclableArrayList out = RecyclableArrayList.newInstance();
            out.add(new ITCUdpRequest(payload));

            final int size = out.size();

            for(int i = 0; i < size; i++)
            {
                ctx.fireChannelRead(out.get(i));
            }
            out.recycle();
        }
        else
        {
            ctx.fireChannelRead(msg);
        }
    }
}

Encoder code :

public class SITCEncoder extends MessageToByteEncoder<ITCUdpResponse>
{
    private static final String MSG_RP_HEADER   = "SITCRPVAL:";
    private static final char   MSG_RP_FOOTER   = '*';
    private static final char   VAL_PREFIX      = '[';
    private static final char   VAL_SUFFIX      = ']';

    protected void encode(final ChannelHandlerContext ctx, final ITCUdpResponse msg, final ByteBuf out) throws Exception
    {
        final StringBuilder str = new StringBuilder();
        str.append(MSG_RP_HEADER);

        for(final Object val : msg.getParams())
        {
            str.append(VAL_PREFIX).append(val).append(VAL_SUFFIX);
        }

        str.append(MSG_RP_FOOTER);

        out.ensureWritable(str.length());

        out.writeBytes(str.toString().getBytes());
    }
}

Upvotes: 0

Views: 1188

Answers (1)

iX&#244;
iX&#244;

Reputation: 1181

Ok, so after reading so suggestions that stackoverflow gave me for my question, I have switched from Nio* to Oio* (like said here) and everything works as expected without changing anything.

Thansk.

PS: why Oio works where Nio don't ?

Upvotes: 0

Related Questions