Попытка заполнить буфер во время записи буфера в канал - PullRequest
1 голос
/ 07 января 2012

Я пытаюсь сделать простой сетевой клиент. Клиент должен иметь возможность записи в очередь (буфер), а второй поток должен взять этот буфер и записать его на сервер.

Я попробовал это с java.nio и создал Thread со статическим ByteBuffer. Этот ByteBuffer используется в while(true) из Thread для записи в канал.

В моем главном цикле в какой-то момент я помещаю несколько байтов в статический буфер с помощью метода put().

В режиме отладки я приостановил поток записи канала, а затем заполнил буфер с помощью основного цикла программы (просто нажал «A» для записи в буфер).

После трех или четырех нажатий кнопок я снова запустил процесс записи канала, и он работал просто отлично.

Но когда я просто пытаюсь запустить программу, я получаю ошибку переполнения буфера в потоке основного цикла. Я полагаю, что моя программа пытается поместить данные в буфер, пока мой поток записи канала обращается к нему. Я пытался использовать синхронизированное ключевое слово вокруг обеих частей в обоих потоках, но это не помогло.

Основной цикл:

[...]
  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 считают, что буфер заполнен в цикле канала.

В конце я пытаюсь запустить программу, в которой сетевой компонент запускается один раз, и в моей программе я просто хотел использовать статический метод отправки для отправки пакетов, не думая об обработке очереди или ожидании очереди.

Может быть, есть где-нибудь учебник? В большинстве игр должна использоваться похожая концепция, но я не смог найти ни одной простой Java-игры с открытым исходным кодом с реализацией NIO (я буду использовать ее для Android, поэтому я пробую ее без фреймворка)

Ответы [ 3 ]

2 голосов
/ 07 января 2012

Вы можете попытаться сохранить очередь (скажем, 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 */
}

Вам также может понадобиться установить / удалить интерес записи для канала в зависимости от того, пуста очередь илинет.

1 голос
/ 07 января 2012

Не прямой ответ на ваш вопрос, но вы должны рассмотреть возможность использования существующей инфраструктуры NIO, чтобы сделать это проще. Нетти и Гризли - популярные примеры. Я бы лично использовал Netty вместо того, чтобы писать свой собственный сервер с нуля, используя NIO.

Вы также можете посмотреть, как Netty обрабатывает чтение / запись в буферы, поскольку я предполагаю, что они оптимизировали свою реализацию.

0 голосов
/ 08 января 2012

Суть NIO в том, что вам не нужны отдельные потоки. Нить, выполняющая заполнение, должна также писать.

...