Java-сокеты - асинхронное ожидание, синхронное чтение - PullRequest
1 голос
/ 06 июня 2009

Я хочу иметь возможность асинхронно ждать в сокете, а затем синхронно читать из него:

for (;;) 
{
    while (data available on socket) 
    {
        read message from socket;
        process it;
    }
    do something else;
}

Мне это нужно, потому что я хочу опрашивать очередь с сообщениями из GUI одновременно, поэтому часть "сделать что-то еще" имеет короткий wait().

Возможно ли это с сокетами Java? Я пытался проверить .available() на DataInputStream, связанном с сокетом, но

  • Кажется, что работает только когда я подключаюсь, а не когда я принимаю соединение (???)
  • У меня нет никаких признаков того, что соединение было закрыто.

Я пытался сделать это с помощью селектора, но он требует, чтобы канал сокета все время находился в неблокирующем режиме.

Ответы [ 5 ]

5 голосов
/ 06 июня 2009

Неблокирующий пакет ввода-вывода Java (java.nio) позволит вам выполнять асинхронное чтение из сокета через Selector s.

Проверьте эту ссылку , чтобы получить несколько примеров, с чего можно начать.

2 голосов
/ 14 октября 2012

Метод available () для InputStream из Socket сообщит вам о наличии данных в сокете, прежде чем вызывать блокирующий метод read ().

InputStream sockIS = sock.getInputStream();
int ba;  // Number of bytes available to read from socket
for (;;) {
    while ((ba = sockIS.available()) > 0) {
        read message from socket;
        process it;
    }
    do something else;
}

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

Связанный метод, представляющий интерес (но не для вашей конкретной потребности): sock.setSoTimeout (millis), этот вызов позволяет вам вызывать sock.read (...) и заставлять его ждать не более определенного времени до того, как он генерирует исключение (которое вы бы обработали) или которое возвращает данные. Это полезно, если вы хотите получить быстрый ответ, но хотите решить проблемы, когда сервер больше не отвечает.

Другая проблема состоит в том, что вы помещаете фигурные скобки в неправильную строку, когда все знают, что они принадлежат в конце оператора if / while / for: -)

2 голосов
/ 06 июня 2009

Почему бы вам не использовать два потока (или я неправильно понимаю, что вы хотите сделать)?

0 голосов
/ 07 июня 2009

Я бы сделал

public class MainClass extends WhateverSuperClass implements WhateverInterface { 
// . . .

  private Listener listener;

  public MainClass() {
    listener = new Listener(this);
  }

  public void theMethod(){
    //do something else
  }
}

public class Listener extends Thread {
  public Listener(MainClass clazz) {

    // initialize thread resources (sockets, database connections, etc)
    start();
    Thread.yield();
  }

  public void run() {
    for (;;) 
    {
      // there's no need to test if there is 
      // data available on socket, since this
      // loop runs in a separate thread

      // read message from socket;
      // clazz.process(message);
    }
  }
}

0 голосов
/ 06 июня 2009

При программировании сокетов данные могут поступать как произвольные порции в зависимости от взаимодействия между отправляющей системой, промежуточными ссылками и того, как ваша ОС обрабатывает флаги PSH. Вам нужно будет поместить BufferedInputStream в середину и использовать метод available () и сдвигать байты назад, пока у вас не появится полное «сообщение», которое вы затем сможете обработать.

Правильное решение Java включает создание собственного MessageInputStream, который оборачивает BufferedInputStream и предоставляет аналогичную функцию available (), которая сообщает вызывающей стороне, сколько сообщений сразу доступно для чтения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...