日安。
我正在使用NIO多路复用,我不想在我的应用程序中分配额外的缓冲区,直到我确定在套接字中有足够的字节来读取整个应用程序包。每个应用程序包包含4个字节的数据包长度(报头)和以下字节的数据包主体。我想读取4字节的数据包长度,如果它们是可用的,然后跟随字节的数据包体,如果它们是可用的。所以,代码可以是这样的:
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
}在*我们可以获得:
在任何一种情况下,我都必须将读取的数据存储在附加的ByteBuffer中,因为READ_BUFFER将用于**中的下一个连接。
我想做的是:
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()吗?或者它可能失败?如果失败了,原因是什么,以及如何改进这段代码以克服这些原因?
发布于 2015-05-31 11:15:01
如果使用非阻塞模式,则根本不能使用InputStream。你不可能运行这段代码。
你想做的事没有多大意义。每次OP_READ触发时,只要阅读一遍,直到您有足够的数据处理为止。
https://stackoverflow.com/questions/30556047
复制相似问题