首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有InputStream.available()的Java

带有InputStream.available()的Java
EN

Stack Overflow用户
提问于 2015-05-31 09:49:32
回答 1查看 356关注 0票数 0

日安。

我正在使用NIO多路复用,我不想在我的应用程序中分配额外的缓冲区,直到我确定在套接字中有足够的字节来读取整个应用程序包。每个应用程序包包含4个字节的数据包长度(报头)和以下字节的数据包主体。我想读取4字节的数据包长度,如果它们是可用的,然后跟随字节的数据包体,如果它们是可用的。所以,代码可以是这样的:

代码语言:javascript
复制
private final ByteBuffer READ_BUFFER = ByteBuffer.wrap(new byte[READ_BUFFER_SIZE]);
...
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();

while (selectedKeys.hasNext())
{
    SelectionKey key = selectedKeys.next();
    selectedKeys.remove();

    Connection con = (Connection) key.attachment();

    switch (key.readyOps())
    {
        case SelectionKey.OP_ACCEPT:
            acceptConnection(key);
            break;
        case SelectionKey.OP_READ:
            readPacket(key, con);    //**
    }
}
...
private final void readPacket(final SelectionKey key, final Connection con)
{   
    READ_BUFFER.clear();
    int result = -2;

    try
    {
        result = con.read(READ_BUFFER);
    }
    catch (IOException e) {}

    //* packet processing goes here
}

在*我们可以获得:

  1. 少于4个字节来读取标头;
  2. 头的字节数为4字节,而数据包正文的字节数不足
  3. 足够的字节来读取N个数据包(报头+正文),但部分(N+1)数据包

在任何一种情况下,我都必须将读取的数据存储在附加的ByteBuffer中,因为READ_BUFFER将用于**中的下一个连接。

我想做的是:

代码语言:javascript
复制
public class Connection
{
    private final ByteChannel byteChannel;
    private final InputStream in;
    private int lastPacketSize = -1;

    Connection(final Socket socket)
    {
        byteChannel = socket.getChannel();
        in = socket.getInputStream();
    }

    int read(final ByteBuffer buf) throws IOException
    {
        return byteChannel.read(buf);
    }

    int available()
    {
        return in.available();
    }

    void setLastPacketSize(int size)
    {
        lastPacketSize = size;
    }

    int getLastPacketSize()
    {
        return lastPacketSize;
    }
}

private final IntBuffer HEADER_BUFFER = IntBuffer.wrap(new int[1]);
private final void readPacket(final SelectionKey key, final Connection con)
{
    int packetSize = con.getLastPacketSize();
    if (packetSize < 0)
    {
        if (con.available() < 4) return;

        int result = -2;
        HEADER_BUFFER.clear();
        try
        {
            result = con.read(HEADER_BUFFER);
        }
        catch (IOException e) {}

        if (result != 4)
        {
            closeConnection(key);
            return;
        }

        packetSize = HEADER_BUFFER.get();
        con.setLastPacketSize(packetSize);
    }

    if (con.available() < packetSize) return;

    result = -2;

    READ_BUFFER.clear();
    READ_BUFFER.limit(packetSize);
    try
    {
        result = con.read(READ_BUFFER);
    }
    catch (IOException e) {}

    if (result != packetSize)
    {
        closeConnection(key);
        return;
    }
    con.setLastPacketSize(-1);

    //packet processing goes here
}

我已经发现,在Linux上,在遮罩套接字的InputStream中使用ioctl(fd、FIONREAD、字节)。在这个场景中,我可以依赖con.available()吗?或者它可能失败?如果失败了,原因是什么,以及如何改进这段代码以克服这些原因?

EN

回答 1

Stack Overflow用户

发布于 2015-05-31 11:15:01

如果使用非阻塞模式,则根本不能使用InputStream。你不可能运行这段代码。

你想做的事没有多大意义。每次OP_READ触发时,只要阅读一遍,直到您有足够的数据处理为止。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30556047

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档