Java 在缓冲区写入通道时尝试填充缓冲区

Java 在缓冲区写入通道时尝试填充缓冲区,java,buffer,nio,Java,Buffer,Nio,我正在尝试制作一个简单的网络客户端。客户端应该能够写入队列(缓冲区),第二个线程应该获取该缓冲区并将其写入服务器 我用java.nio尝试了它,并用一个静态ByteBuffer创建了一个线程。此ByteBuffer正在线程的while(true)中用于写入通道 在我的主循环中,我通过put()方法将一些字节放入静态缓冲区 在调试模式下,我挂起了通道写入线程,然后通过主程序循环填充了缓冲区(只需按“A”写入缓冲区) 在按下三到四个按钮后,我再次启动了通道写入线程,它工作得很好 但是当我尝试正常的程

我正在尝试制作一个简单的网络客户端。客户端应该能够写入队列(缓冲区),第二个线程应该获取该缓冲区并将其写入服务器

我用
java.nio
尝试了它,并用一个静态
ByteBuffer
创建了一个
线程。此
ByteBuffer
正在
线程的
while(true)
中用于写入通道

在我的主循环中,我通过
put()
方法将一些字节放入静态缓冲区

在调试模式下,我挂起了通道写入线程,然后通过主程序循环填充了缓冲区(只需按“A”写入缓冲区)

在按下三到四个按钮后,我再次启动了通道写入线程,它工作得很好

但是当我尝试正常的程序时,我在主循环线程中得到了一个缓冲区溢出错误。我相信我的程序试图在通道写入线程访问缓冲区时将数据放入缓冲区。我尝试在两个线程中的两个部分使用synchronized关键字,但没有帮助

主回路:

[...]
  if(Gdx.app.getInput().isKeyPressed(Input.Keys.A) && (now.getTime() - lastPush.getTime()) > 1000 )
      { 
          lastPush = now;
          //synchronized (PacketReader.writeBuffer) 
          //{
              PacketReader.writeBuffer.put(("KeKe").getBytes());
          //}
}
[...]
我的线程名为“PacketReader”(实际上是读写):

你知道如何创建这样一个缓冲写系统吗?我认为这是一个常见的问题,但我不知道该搜索什么。所有NIO教程似乎都认为缓冲区是在通道循环中填充的

最后,我尝试创建一个程序,该程序将网络组件启动一次,在我的程序中,我只想使用一些静态发送方法发送数据包,而不考虑队列处理或等待队列


有没有什么地方有教程?大多数游戏都应该使用类似的概念,但是我找不到任何带有NIO实现的简单的java游戏(我将使用Android,所以我尝试没有框架)

不是对你的问题的直接回答,但是你应该考虑使用现有的NIO框架来简化这一点。Netty和Grizzly是流行的例子。我会亲自使用Netty,而不是使用NIO从头开始编写自己的服务器


您可能还可以看看Netty是如何处理对缓冲区的读/写的,因为我假设它们已经优化了它们的实现。

您可以尝试保留一个缓冲区队列(例如,
ConcurrentLinkedQueue
)来进行写,而不是放入发送到通道的相同缓冲区中

要将要发送的内容排队,请执行以下操作:

ByteBuffer buff = /* get buffer to write in */;
buff.put("KeKe".getBytes());
queue.add(buff);
然后在select循环中,当通道可写时:

for(ByteBuffer buff = queue.poll(); buff != null; buff = queue.poll()) {
   sChannel.write(buff);
   /* maybe recycle buff */
}

根据队列是否为空,您可能还需要设置/删除通道上的写入兴趣。

NIO的全部要点是不需要单独的线程。填充的线程也应该进行写入。

对不起,我不完全理解这一点。我是为一款Android小游戏制作的——根据你的说法,我应该在渲染线程中完成所有的填充和编写工作?就在图形和逻辑部分之前?但是,如果从套接字发送或读取数据需要很多时间怎么办?我将不得不等待渲染,因此游戏将变得缓慢。。。如果渲染时间太长,我的读取缓冲区不会有溢出的风险吗?或者更糟的是,我会松开包装吗?谢谢你的建议。我一直在考虑像Kryonet或Pyronet这样的lightwight框架,但当我在Android上使用它时,我认为直接编程会更好地提高性能。另一方面,我想学习NIO,为什么不折磨自己呢谢谢你拉塞尔:)我用你的例子来申请。关于您的解决方案,我仍然有一些问题:这是否意味着我正在创建大量缓冲区(用于每个数据包发送?)?这会导致Android设备出现资源问题吗?或者,我一直在考虑将byte[]数组放入队列,并通过ByteArrayOutputStream创建字节数组。所以这里的问题是:ByteArrayOutputStream vs ByteBuffer,Android设备的最佳选择是什么?
for(ByteBuffer buff = queue.poll(); buff != null; buff = queue.poll()) {
   sChannel.write(buff);
   /* maybe recycle buff */
}