2016-09-12 24 views
0

因此,我正在构建基于AsynchronousSocketChannel类的小型客户机< - >服务器通信应用程序。 我设法让一切正常:服务器运行,客户端能够连接,数据包发送/接收都很好。 这是至少直到我试图发送一堆包一个接一个(让我们说3个数据包),首先我运行一个WritePendingException,我可以修复后,稍稍搜索一下,但数据包仍未发送正常。 从我的调试,似乎服务器试图发送3个数据包,它成功发送所有3,但客户端只接收第一个2,我似乎无法理解问题在哪里,并没有任何错误在控制台上,如果进一步调试需要帮助我只是问:只使用异步套接字发送3个数据包中的2个

在创建数据包,它们被添加到_sendQueue像这样:

_sendQueue.add(packet); 

_sendQueue是字节缓冲区的的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个数据包,我发现它是。 那么第三个包在哪里?我想不出更深入的调试方法...任何帮助将不胜感激。

注意我确实希望自己构建它,所以不要向我建议任何预制的通信代码。

+0

数据包一直在网络上丢失,例如通常非常非常小的缓冲区可以填满,然后分组丢弃。这就是为什么建立TCP以提供可靠通信的原因。 –

+0

对不起,但我很确定我的通信基于TCP,因为它基于java的AsynchronousSocketChannel –

+0

TCP将保证段交付,并且它要求重新发送缺失的段。你将得到一切与TCP。 –

回答

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()); 
} 
相关问题