Есть ли проблемы с заменой new Socket() на SocketChannel.open().socket()?

Что может пойти не так, если я просто заменю

socket = new Socket()

с

socket = SocketChannel.open().socket()?

Предыстория: у меня есть устаревший код, использующий new Socket(), и я хотел иметь возможность прервать вызов socket.connect(). Я не хочу переписывать код для использования NIO. Я узнал, что Thread.interrupt() не прерывает socket.connect(), но socket.close() в другом потоке должен прерывать соединение. Как ни странно, это работало с Java 7, но не с Java 6.

Каким-то образом мне пришло в голову, что использование socket = SocketChannel().open().socket() волшебным образом позволит мне использовать Thread.interrupt(), чтобы прервать socket.connect(). Это не так, но, как ни странно, это делает socket.close() прерывание socket.connect() и в Java 6!

Обратите внимание, что я никоим образом напрямую не использую присоединенный SocketChannel --- он появляется, когда я создаю Socket, и больше никогда.

Что может пойти не так с этим?


person Robert Tupelo-Schneck    schedule 04.11.2013    source источник


Ответы (2)


Есть несколько.

  1. Сокет, полученный через SocketChannel, не поддерживает тайм-ауты чтения.
  2. InputStream и OutputStream сокета не являются независимыми: они имеют общую взаимную блокировку.

Почему вы хотите прервать вызов connect()? Конечно, все, что вам нужно, это тайм-аут подключения?

person user207421    schedule 04.11.2013
comment
(2) не является проблемой, поскольку это протокол запроса/ответа. Я расследую (1). Я хочу прервать connect() для Happy Eyeballs: один поток пытается использовать IPv6, а второй — пробую IPv4, и если IPv6 сломан так, что connect() истечет время ожидания, я хочу прервать это connect(), как только будет установлено соединение IPv4. - person Robert Tupelo-Schneck; 05.11.2013
comment
В этом случае вам лучше подключить каналы в неблокирующем режиме и закрыть тот, который запускает OP_CONNECT во второй раз. - person user207421; 05.11.2013
comment
Думаю, я согласен, но я надеялся избежать работы по перенастройке кода для NIO. Но, может быть, я могу вернуться к блокировке после успешного подключения и после этого просто работать с потоками сокетов? Можете ли вы (или кто-то) показать код, который заменит socket = SocketChannel.open().socket(); socket.connect(address, timeout);? - person Robert Tupelo-Schneck; 05.11.2013
comment
Мое тестирование показывает, что socket.setSoTimeout() прекрасно работает с сокетом, полученным через SocketChannel, вызывая ожидаемый java.net.SocketTimeoutException при блокировке socket.getInputStream().read(). - person Robert Tupelo-Schneck; 07.11.2013
comment
странный. Я видел отчет об ошибках Sun, указывающий на обратное. Это цитируется где-то на этом сайте. - person user207421; 10.11.2013
comment
Ну, есть это, но это не ошибка о socketChannel.read() несоблюдении тайм-аута. Как упоминается в оценке ошибок, время ожидания socketChannel.socket().getInputStream().read() истекает нормально. - person Robert Tupelo-Schneck; 11.11.2013
comment
Не могли бы вы уточнить (2) о том, где находится взаимная блокировка? Означает ли это, что OutputStream.write() будет заблокирован, если будет вызван, в то время как другой поток заблокирован в InputStream.read()? - person antak; 14.06.2015
comment
н/м, нашел соответствующие ссылки: stackoverflow.com/questions/174774/ и bugs.java.com/bugdatabase/ - person antak; 14.06.2015

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

Например, закрытие Socket из другого потока, когда Socket.getInputStream().read() блокируется, приведет к AsynchronousCloseException после замены вместо SocketException, который мог ожидать устаревший код. (AsynchronousCloseException не является подклассом SocketException.)

Однако Socket.getInputStream().read() все равно вызовет SocketException, если закрытие из другого потока произойдет до read().

person antak    schedule 13.06.2015