无法使用udp socket在netty中回复

时间:2015-03-03 17:00:32

标签: java udp netty

我想使用netty创建一个回复的udp服务器。

旧代码在c中并使用了这种代码:

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));

此代码有效,但我必须使用netty在java中重新实现它。

在tcp中使用netty不是问题,但使用netty回复客户端对我来说是一个问题,如果我想在频道上写字,它会失败java.nio.channels.NotYetConnectedException

也许这与issue on netty有关,但我不知道如何在我的代码中重现c行为。

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();

我如何回复到客户端?

感谢。

额外编辑:

解码器代码:

    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);
        }
    }
}

编码器代码:

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());
    }
}

1 个答案:

答案 0 :(得分:0)

好的,所以在阅读了stackoverflow给我提出问题的建议之后,我已经从Nio *切换到了Oio *(就像所说的here)并且一切都按预期工作而没有改变任何东西。

Thansk。

PS:为什么Oio在Nio不在的地方工作?