Почему java.net.SocksSocketImpl реализует java.net.Socket по умолчанию в Java?
Вопрос короткий. Почему реализация сокета SOCKS-сокетов является выбором по умолчанию для реализации абстрактного класса java.net.Socket
? Na & iuml; vely Я бы ожидал java.net.PlainSocketImpl
.
Фон немного сложнее.
Я пытаюсь убить GLASSFISH-12213 (или действительно пытаюсь обойти это). Детали самой ошибки не очень важны - есть собственная библиотека, которая не является потокобезопасной, и некоторые ее одновременные использования из созданной GlassFish области LDAP приводят к сбою JVM.
Чтобы обойти это, я начал работать в обратном порядке: могу ли я избежать использования первой библиотеки? Это привело меня по разным причинам, чтобы посмотреть sun.net.spi.DefaultProxySelector
, который отвечает за поиск соответствующего прокси (или нет) для данного URI. Там есть место там, где он вызывает собственный вызов метода, и именно там происходит сбой JVM. Если бы я мог избежать этого звонка, я был бы в бизнесе.
В одном случае я мог бы избежать этого вызова, если бы я мог гарантировать, что значение sun.net.spi.NetProperties.getBoolean("java.net.useSystemProxies")
ложно. Если бы это было так, то нативный метод, о котором я говорил ранее, не будет называться. false
- это значение по умолчанию, и я ничего не изменил в этом отношении.
(На самом деле это так, очевидно, доказано в экземпляре GlassFish, запущенном на этой машине, где я заметил ошибку. Я не уверен, как этот код, возможно, по-прежнему может загружать родную библиотеку; на другой день.)
Итак, пробирая этот путь, я еще больше поддержал: какой протокол передавался как URI
scheme
в вызове DefaultProxySelector.select(uri)
? Возможно, я мог бы каким-то образом повлиять на глупую вещь, чтобы по-прежнему пропустить этот родной звонок.
Как оказалось, протокол был socket
(я предположил, что это, вероятно, что-то вроде ldap
, но нет). Этот факт и мое опровергающее предположение подсказывали мне, что где-то в LDAP-сфере открывалось прямое сокет вручную (т.е. Не используя что-то вроде HttpUrlConnection
или какой-либо другой абстракции). Разумеется, созданный Sun профиль LDAP-JNDI-моста делает именно это; URI, который передается, равен socket://somehost:389
.
Итак, из всего этого , несмотря на то, что я не настроил никакой информации прокси-сервера, не настроил ничего или не сделал ничего, кроме использования прямых значений по умолчанию, оказывается, что JDK пытается использовать прокси-сервер SOCKS. См. метод setImpl()
в java.net.Socket
и строке 364 или около того SocksSocketImpl.java
и проследите его для деталей.
(Это, наконец, говорит о том, что я мог бы пропустить всю эту кодировку, просто добавив в этот элемент системное свойство socksNonProxyHosts=*
. Jeez, не должно ли это поведение по умолчанию?)
В результате - и снова, полагая, что DefaultProxySelector
по какой-то причине имеет поле hasSystemProxies
, установленное на true
, несмотря на никакие изменения в конфигурации мной или GlassFish, сорт сорта сада, созданный садовым разнообразием Соединение Sun LDAP вызывает естественный поиск прокси-сервера SOCKS. Может быть, это только я, но это поражает меня как безумие.
Так кто-нибудь читает это - возможно, вы находитесь в команде JDK или знаете кого-то, кто знает или знаете историю здесь, - знаете, почему реализация по умолчанию java.net.Socket
всегда ищет прокси-сервер SOCKS?
Обновление: Я вижу, что ответ будет таким: чтобы, если у вас есть системный прокси-сервер, и он включен с помощью SOCKS, через него проходит весь материал. Но если значение по умолчанию java.net.useSystemProxies
равно false
, как это, то какая точка поиска (по умолчанию) для SOCKS-прокси?
Ответы
Ответ 1
Реализация сокета по умолчанию SocksSocketImpl
, потому что JRE может иметь внешнюю конфигурацию для использования SOCKS через свойства системы -D socksProxyHost
и -D socksProxyPort
или ProxySelector.setDefault()
или через по умолчанию ProxySelector
, установленный JRE.
PlainSocketImpl
выполняет не эти свойства или классы (потому что это простой сокет и ничего не знает о прокси), и поэтому эти внешние конфигурации будут игнорироваться не были SocksSocketImpl
, которые всегда вызывались, чтобы проверить их. Я согласен, что кажется странным, что вы получаете SocksSocketImpl
, когда никто ничего не сказал о SOCKS для JRE, но я предполагаю, что архитектура java.net.Socket
и ProxySelector
не позволяет предварительно выбрать правильный impl во время Socket конкретизации.
Я думаю, что вы (или кто бы ни вел текущую линию расследования этой ошибки в Glassfish), возможно, ошибаются: вместо того, чтобы пытаться подорвать способ, которым JRE выбирает сокеты и прокси-серверы, почему бы не исправить по умолчанию ProxySelector
и/или ОС, так что, когда Java выполняет свои стандартные запросы для получения информации о прокси, все не прерывается. Я думаю, что исправление находится в кишках процесса поиска прокси и классов, а не выше.
Возможно, еще один способ спросить, что я спрашиваю: if DefaultProxySelector
может сказать мне, что прокси-серверы используют для подключения сокета, почему Socket не вызывает это первым, чтобы помочь ему выбрать разумную реализацию?
Я думаю, проблема в том, что java.net.Socket
поддерживает несколько моделей программирования. Там есть очевидный конструктор new Socket(host, port)
, но есть и конструктор по умолчанию new Socket()
, который может быть построен первым, а затем в какое-то произвольное время в будущем может быть вызван его метод connect(SocketAddress)
.
Поскольку часть критериев, которые a ProxySelector
может использовать для определения использования прокси-сервера или нет, - это имя удаленного хоста и удаленного порта, к которому необходимо подключиться (то есть информация, предоставленная connect
), конструктор java.net.Socket
слишком рано знать, нужен ли прокси-сервер или нет.
По какой-либо причине (можем ли мы просто предположить исторические?/обратные соображения совместимости?:), конструктор для java.net.Socket
- единственное место, где установлено impl, и, как я уже сказал, это в некоторых случаях слишком рано говорить нужен ли прокси-сервер или нет.