0

I am running a Netty server for an online game, however I am experiencing some weird behavior:

Randomly, the channel just stops being able to write from the server, ie the user is still connected and incoming data is received but outgoing data doesn't reach the client.

I have took the time to debug this and I discovered that channel.isWriteable() is returning false for connecting client with the problem.

Can anyone shine any light on why this might be happening?

What are the reasons for a channel not to become writeable anmore?

By the way, this also happens on a localhost connection too.

    public ChannelFuture write(Packet message) {
    ioWrite++;

    if (!channel.isConnected()) {
        System.err.println("Trying to write to bad channel");

        return null;
    }

    if (!channel.isWritable()) {
        System.err.println("Channel buffer is full?");
    }

    if ((channel != null) && channel.isConnected()) {
        return channel.write(message);
    }

    return null;
}

Encoder:

public class GameProtocolEncoder extends OneToOneEncoder {



private ChannelBuffer response;


protected Object encode(ChannelHandlerContext channelHandlerContext, Channel channel, Object o) throws Exception {
    Packet p = (Packet) o;

    try {
        byte[] data       = p.getData();
        int    dataLength = p.getLength();

        if (p.getLength() > 5000) {
            System.err.println("unable to write data chunk to large");

            return null;
        }

        if (!p.isBare()) {
            int siz = 0;

            siz      += (p.getSize() == Packet.Size.VariableShort)
                        ? 2
                        : 1;
            siz      += (p.getId() > 128)
                        ? 2
                        : 1;
            response = ChannelBuffers.buffer(siz + p.getLength());

            int id          = p.getId();

            if (id< 128) {
                response.writeByte(id);
            } else {
                response.writeByte((byte) ((id >> 8) + 128));
                response.writeByte((byte) (id & 0xFF));
            }

            if (p.getSize() != Packet.Size.Fixed) {    // variable length
                if (p.getSize() == Packet.Size.VariableByte) {
                    if (dataLength > 255) {            // trying to send more data then we can represent with 8 bits!
                        throw new IllegalArgumentException("Tried to send packet length " + dataLength
                                                           + " in 8 bits [pid=" + p.getId() + "]");
                    }

                    response.writeByte((byte) dataLength);
                } else if (p.getSize() == Packet.Size.VariableShort) {
                    if (dataLength > 5000) {
                        throw new IllegalArgumentException("Tried to send packet length to big: " + id);
                    }

                    response.writeShort((short) dataLength);
                }
            }
        } else {
            response = ChannelBuffers.buffer(dataLength);
        }

        response.writeBytes(p.getData());

        return response;
    } catch (Exception e) {
        Logger.err("Error handling message: " + p);
        Logger.err(e);
    }

    return null;
}
Enchanta Support
  • 199
  • 1
  • 2
  • 11
  • Look [here](http://stackoverflow.com/questions/15263180/client-channel-is-not-in-writable-statenio-netty) and [here](http://stackoverflow.com/questions/8985389/java-netty-load-testing-issues) for more information. – gknicker Jan 14 '15 at 20:56
  • I checked that, the only difference is is that the channel stays in the non-writeable state forever and doesn't get out of it. – Enchanta Support Jan 14 '15 at 21:21

2 Answers2

1

I think the problem is here that you not flush the Channel. Try to replace channel.write(...) with channel.writeAndFlush(...).

Norman Maurer
  • 23,104
  • 2
  • 33
  • 31
0

A channels stops being writeable when its socket send buffer fills up, which in turn happens when the sender outruns the receiver.

If it happens a lot you may want to look into speeding up your receiving code, but in general it can happen any time, and all you can do is defer the write until the channel becomes writeable again.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • So with the buffer been full up forever thats not normal behavior? This means that the receiving end isn't consuming the data at all? or does it mean i need to stop writing until it can consume the data, ie im just making it worse by continuing writing – Enchanta Support Jan 14 '15 at 21:25
  • It means the receiver has stopped consuming but still has the connection open. You can't continue writing. Once the buffer is full, `write()` returns zero. – user207421 Jan 14 '15 at 21:47
  • So would that just mean the only solution is to drop the connection? Also I tried to simulate this by not using read() on the receiving end so basically stopped it consuming and left it for 20 minutes and the server still remained in writeable state. – Enchanta Support Jan 14 '15 at 21:50
  • Something wrong with your code in that case. Post it. Edit it into your question. – user207421 Jan 14 '15 at 21:56
  • Hello, I have included the encoder and the method which writes the data and indicates the channel is not writeable – Enchanta Support Jan 14 '15 at 22:12