Запись Java SocketChannel заблокирована при чтении

Я пытаюсь использовать SocketChannel.write и SocketChannel.read одновременно в двух разных потоках (Android API Level 25).

Я настроил SocketChannel как режим блокировки.

Для чтения я создал бесконечный цикл для чтения всего с сервера:

// Make socketChannel.read() return after 500ms at most
socketChannel.socket().setSoTimeout(500);
while(!SHUTDOWN) {
    int read = socketChannel.read(buffer);
    if(read > 0 ){
      // Do something nice
      break;
    }
}

А для записи я пишу данные каждые 10 секунд.

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

Но если я заставлю поток чтения спать в течение короткого периода времени в каждом цикле, например. 100 мс, эта проблема больше не появится.

похоже, поток чтения блокирует поток записи

Насколько я знаю, TCP-соединения могут одновременно выполнять двунаправленные операции. Кто-нибудь может помочь объяснить это?


person WoooHaaaa    schedule 14.05.2017    source источник
comment
Вы полностью игнорируете информацию, возвращаемую методом read(). Не делай этого.   -  person user207421    schedule 14.05.2017
comment
Извините, @EJP, это просто демонстрация, показывающая, что я читаю данные в цикле, исправил   -  person WoooHaaaa    schedule 14.05.2017
comment
Было бы неплохо, если бы парень, который понизил этот вопрос, мог объяснить, почему   -  person WoooHaaaa    schedule 14.05.2017
comment
Было бы неплохо, если бы вы объяснили, какое отношение «просто демонстрация» имеет к совершению основной ошибки программирования. Кроме того, в чем именно смысл спать в потоке чтения.   -  person user207421    schedule 14.05.2017
comment
Вы поняли это? Я сталкиваюсь с той же проблемой   -  person fileyfood500    schedule 23.05.2019
comment
@fileyfood500, к сожалению, я не нашел разумного объяснения этой проблемы, если у вас есть дополнительная информация, я хотел бы знать.   -  person WoooHaaaa    schedule 24.05.2019
comment
@MrROY Я обнаружил, что для TCP-соединения средство чтения/записи сокетов использует блокировку, поэтому чтение и запись не происходят одновременно. Из того, что я читал, обычный шаблон для TCP-клиента — это подключение (трехстороннее рукопожатие между клиентом и сервером), запись сообщения (с пакетами, подтверждениями и т. д.), ожидание ответа и затем отключение. Протокол не предназначен для того, чтобы клиент мог читать и писать одновременно. В некоторых вариантах использования есть возврат и возврат (клиент пишет, затем читает, затем пишет, затем читает, затем записывает и т. д.), но непрерывного чтения нет. В этом случае UDP может быть вариантом?   -  person fileyfood500    schedule 28.05.2019


Ответы (1)


Как поясняется в TCP Wikipedia — управление потоком:

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

person Aubin    schedule 14.05.2017
comment
Спасибо, но это не объясняет, почему чтение блокирует запись. - person WoooHaaaa; 14.05.2017
comment
Читатель блокирует запись, когда читатель читает слишком медленно. - person Aubin; 15.05.2017
comment
Как я узнаю, что читатель читает слишком медленно? Я инициализирую ридер при запуске и сразу же блокирую запись (потому что в это время читать нечего). - person fileyfood500; 23.05.2019
comment
Я просмотрел вики-раздел управления потоком (который я действительно прочитал до того, как нашел этот пост), но он предполагает, что читатель с сервера блокирует писатель от клиента или наоборот. Мне кажется, что вопрос в том, почему читатель клиента (в отдельном потоке) блокирует писатель клиента от отправки сообщений на сервер. Клиент блокирует себя локально, но сокеты не блокируются. У меня такой же вопрос. - person fileyfood500; 23.05.2019
comment
Пожалуйста, опубликуйте свой код в новом вопросе, потому что я подозреваю, что вы путаете читатель/писатель с клиентом/сервером. Код однозначный. - person Aubin; 24.05.2019
comment
@Aubin, я полагаю, что спрашивающий использует TCP-клиент для непрерывного чтения и записи каждые 10 секунд. Я ошибаюсь в этом? - person fileyfood500; 28.05.2019