试图填充缓冲区,同时缓冲区写入通道
我试图做一个简单的网络客户端。客户端应该能够写入一个队列(缓冲区),第二个线程应该把这个缓冲区写入服务器。试图填充缓冲区,同时缓冲区写入通道
我用java.nio
试了一下,并用静态ByteBuffer
创建了Thread
。 ByteBuffer
正用于Thread
的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”(以及它的实际读,写):
class PacketReader implements Runnable
{
public static ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
[...]
public void run()
{
while (true) {
[...]
if (selKey.isValid() && selKey.isWritable())
{
SocketChannel sChannel = (SocketChannel)selKey.channel();
//synchronized (PacketReader.writeBuffer)
//{
if(PacketReader.writeBuffer.hasRemaining())
{
PacketReader.writeBuffer.flip();
int numBytesWritten = sChannel.write(PacketReader.writeBuffer);
PacketReader.writeBuffer.flip();
}
//}
}
[...]
任何想法如何创建这样一个缓冲的写入系统?我认为这是一个常见问题,但我不知道要搜索什么。所有的NIO教程似乎认为缓冲区在通道循环中被填满。
最后我试图有一个程序,其中网络组件启动一次,并在我的程序中,我只是想使用一些静态发送方法发送数据包,而不考虑队列处理或等待队列。
是否有可能在某个地方的教程?大多数游戏应该使用类似的概念,但是我找不到任何带有NIO实现的开源简单java游戏(我将使用它用于android,所以我在没有框架的情况下使用它)
不直接回答你的问题,但你应该考虑使用现有的NIO框架来使这更容易。 Netty和灰熊是很受欢迎的例子。我会个人使用Netty,而不是使用NIO从头开始编写自己的服务器。
你可能也可以看看Netty如何处理对缓冲区的读/写,因为我假设他们已经优化了它们的实现。
您可能会尝试保留要写入的缓冲区的队列(例如,ConcurrentLinkedQueue
),而不是放入要发送到通道的同一缓冲区中。
要排队的东西发送:
ByteBuffer buff = /* get buffer to write in */;
buff.put("KeKe".getBytes());
queue.add(buff);
然后在你的选择循环,当信道是可写的:
for(ByteBuffer buff = queue.poll(); buff != null; buff = queue.poll()) {
sChannel.write(buff);
/* maybe recycle buff */
}
您可能还需要设置/通道上删除写兴趣取决于队列是否为空。
谢谢罗素:)我用你的例子来申请我的应用程序。我仍然有关于你的解决方案的一些问题:这不意味着我正在创建大量的缓冲区(对于每个数据包发送?)?这可能会导致Android设备上的资源问题?或者我一直在考虑将byte []数组放入队列并通过ByteArrayOutputStream创建字节数组。所以这里的问题是:ByteArrayOutputStream vs ByteBuffer,Android设备最适合什么? – 2012-01-10 15:10:07
NIO的重点在于您不需要单独的线程。做填充的线程也应该写。
对不起,我完全不明白。我正在做一个小型的Android游戏 - 根据你我应该做的全部填充和写入渲染线程中的东西?在图形和逻辑部分之前?但是如果从套接字发送或读取花费很多时间呢?我将不得不等待渲染,因此游戏会变得缓慢......如果我的渲染耗时太长,我的阅读缓冲区是否有溢出的风险呢?或者更糟糕的是,我是否会丢失包裹? – 2012-01-10 14:53:52
@ Thom-我没有对渲染线程做任何说明。 – EJP 2012-02-04 09:13:22
谢谢您的建议。我一直在考虑像Kryonet或Pyronet这样的Lightwight框架,但是当我在Android上使用这个框架时,我认为直接编程对性能会更好。另一方面,我想学习NIO,那么为什么不折磨自己呢? :D – 2012-01-10 14:55:23