因此,我正在构建一个基于AsynchronousSocketChannel类的小型客户端< - >服务器通信应用程序。 我设法使一切正常工作:服务器运行,客户端能够连接,数据包正在发送/接收都很好。 至少在我尝试一个接一个地发送一堆数据包之前(比如3个数据包),起初我遇到了一个WritePendingException,我能够在稍微搜索一下之后修复它,但数据包仍然没有正确发送。 从我的调试看起来似乎服务器尝试发送3个数据包,它成功发送所有3个,但客户端只接收前2个,我似乎无法理解问题出在哪里,并且在控制台上根本没有错误,如果需要进一步调试帮我问一下:
创建数据包时,它们会被添加到_sendQueue中,如下所示:
_sendQueue.add(packet);
_sendQueue是ByteBuffers的ConcurrentLinkedQueue(它是我的数据包)。 然后通过以下方法发送数据包:
public final void executeWriteTask()
{
if (!_sendQueue.isEmpty())
{
_writeLock.lock();
if (!_pendingWrite)
{
_pendingWrite = true;
ThreadPool.execute(() ->
{
final PacketWriter packet = _sendQueue.poll();
final ByteBuffer duplicate = packet.getBuffer().duplicate();
System.out.println("Sending packet opcode: " + duplicate.getInt());
_channel.write(packet.getBuffer(), this, _writeHandler);
});
}
_writeLock.unlock();
}
}
在写入每个数据包之后,将再次为队列中的下一个数据包调用该方法,因此基本上所有3个数据包都被发送,这就是我的println显示的内容:
Sending packet opcode: 0
Sending packet opcode: 1
Sending packet opcode: 1
哪个好,但在客户端:
Received packet opcode: 0
Received packet opcode: 1
我尝试了很多东西,比如尝试在3秒后再次手动调用读取但是没有待接收的数据包,我也尝试在3秒后从服务器发送第3个数据包并且它有效,但是那个&#39 ;不是我想要的,只是检查问题是否确实来自我试图立即发送3个数据包的事实,我发现它是。 那么第三个数据包去哪了?我想不出更深入地调试它的方法......任何帮助都会受到赞赏。
注意我确实希望自己构建它,所以不要向我推荐任何预先制作的通信代码。
答案 0 :(得分:0)
嗯,它仍然没有直接回答我的问题,但它似乎解决了这个问题。 我想有一些防止数据包泛滥的机制,所以我决定不再一个接一个地发送数据包,而是将它们分批编写为1个数据包然后作为一个整体发送,如下所示:
public final void executeWriteTask()
{
if (!_sendQueue.isEmpty())
{
_writeLock.lock();
if (!_pendingWrite)
{
_pendingWrite = true;
ThreadPool.execute(() ->
{
final Queue<PacketWriter> copy = new ConcurrentLinkedQueue<>();
while (!_sendQueue.isEmpty())
copy.add(_sendQueue.poll());
int bytes = 0;
for (final PacketWriter packet : copy)
bytes += packet.getBuffer().limit();
final ByteBuffer toSend = ByteBuffer.allocateDirect(bytes);
for (final PacketWriter packet : copy)
toSend.put(packet.getBuffer());
toSend.flip();
_channel.write(toSend, this, _writeHandler);
});
}
_writeLock.unlock();
}
}
然后在客户端:
@Override
public void readPacket()
{
final ByteBuffer buffer = getReader().getBuffer();
buffer.flip();
while (buffer.hasRemaining())
{
final int opCode = getReader().readInt();
final PacketInfo inf = PacketInfo.values()[opCode];
final IIncomingPacket<GameClient> packet = inf.newIncomingPacket();
packet.read(this, getReader());
if (inf.isAuthedState() == isAuthed())
packet.run(this);
}
buffer.clear();
getChannel().read(buffer, this, getReadHandler());
}