NIO缓冲区和通道

时间:2018-09-29 13:50:40

标签: java networking nio

我正在基于NIO的TCP网络系统上工作。 这是标准数据包的样子:

public final class KeepAlivePacket implements Packet {
    private static final ByteBuffer BUF = ByteBuffer.allocate(8);

    private long ping;

    @Override
    public void write(SocketChannel channel) {
        BUF.clear();
        BUF.putLong(System.nanoTime());
        BUF.flip();

        try {
            channel.write(BUF);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void read(SocketChannel channel) {
        BUF.rewind();

        try {
            channel.read(BUF);
        } catch (IOException e) {
            e.printStackTrace();
        }

        BUF.rewind();

        this.ping = TimeUnit.MILLISECONDS.convert(System.nanoTime() - BUF.getLong(), TimeUnit.NANOSECONDS);
    }

    public long getPing() {
        return this.ping;
    }
}

这是我用来发送和接收数据包的代码:

private final ByteBuffer writeBuffer = ByteBuffer.allocate(1);
private final ByteBuffer readBuffer = ByteBuffer.allocate(1);

public void send(Packet packet, SocketChannel channel) {
    Class<? extends Packet> packetType = packet.getClass();
    byte id = PacketRegistry.INSTANCE.getId(packetType);

    this.writeBuffer.clear();

    if (id != -1) {
        this.writeBuffer.put(id);
        this.writeBuffer.flip();

        try {
            channel.write(this.writeBuffer);
        } catch (IOException e) {
            e.printStackTrace();

            return;
        }

        packet.write(channel);

        for (ChannelOutboundHandler handler : this.outboundHandlers) {
            handler.packetSent(channel, packet);
        }
    }
}

public boolean receive(SocketChannel channel) {
    this.readBuffer.rewind();

    int bytesRead;

    try {
        bytesRead = channel.read(this.readBuffer);
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }

    if (bytesRead < 0) {
        return false;
    }

    if (bytesRead == 0) {
        return true;
    }

    this.readBuffer.rewind();

    byte identifier = this.readBuffer.get(0);

    if (PacketRegistry.INSTANCE.has(identifier)) {
        Class<? extends Packet> packetType = PacketRegistry.INSTANCE.getType(identifier);
        Packet packet;

        try {
            packet = this.instantiationStrategy.instantiate(packetType, channel);
        } catch (InstantiationException e) {
            e.printStackTrace();

            return true;
        }

        packet.read(channel);

        for (ChannelInboundHandler handler : this.inboundHandlers) {
            handler.packetReceived(channel, packet);
        }
    }

    return true;
}

基本上,每个数据包都有自己的ByteBuffer,并在SocketChannel上写入/读取它。如上面的代码所示,每个数据包都有自己的字节标识符。测试时,我意识到有些问题,例如某些数据包未正确接收。

一种可能是,当数据包在通道上读/写时,剩余一些字节。有什么想法吗?

0 个答案:

没有答案