美好的一天。
我正在使用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
}
在*我们可以获得:
在3种情况中的任何一种情况下,我必须将readed数据存储在附加的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
}
我发现在引擎盖下Socket的InputStream在Linux上使用了ioctl(fd,FIONREAD,pbytes)。我可以在这种情况下依赖con.available(),否则会失败?如果它可能失败的原因是什么以及如何改进此代码以克服这些原因?
答案 0 :(得分:0)
如果您使用非阻止模式,则根本无法使用InputStream
。你不可能运行这段代码。
你要做的事情并没有多大意义。每次OP_READ触发时都要读取,直到有足够的数据要处理。