为什么java.net.SocksSocketImpl是Java中的默认java.net.Socket实现?

前端之家收集整理的这篇文章主要介绍了为什么java.net.SocksSocketImpl是Java中的默认java.net.Socket实现?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这个问题很简单.为什么一个SOCKS感知套接字实现是实现抽象 java.net.Socket类的默认选择?天真地我会期望java.net.PlainSocketImpl.

背景有点复杂.

我试图杀死GLASSFISH-12213(或者我真的想要解决它).错误本身的细节不是很重要 – 有一个本机库不是线程安全的,并且来自GlassFish创作的LDAP领域的一些并发用法使JVM崩溃.

为了解决这个问题,我开始反向工作:我可以避免首先调用本机库吗?这导致我有各种各样的理由来看sun.net.spi.DefaultProxySelector,负责finding an appropriate proxy (or not) for a given URI.有一个spot in there它进行本地方法调用,这是JVM崩溃发生的地方.如果我可以避免这个电话,我会在业务.

我可以避免这种呼叫的一种方式是,如果我可以确保sun.net.spi.NetProperties.getBoolean("java.net.useSystemProxies")的值为false.如果是这样,那么我之前提到的本机方法不会被调用. false是默认的,我根本没有修改任何这方面的东西.

(实际上是这样的情况;在我观察到错误的机器上运行的GlassFish实例中证明是可以证明的,我不知道这个代码如何可能仍然在加载本机库,这是另一天的主题.)

所以,在这个路径上,我进一步备份:在DefaultProxySelector.select(uri)调用中作为URI方案传递什么协议?也许我可能以某种方式影响愚蠢的事情,仍然以某种方式跳过本地电话.

事实证明,协议是套接字(我认为它可能是像ldap,但不是).这个事实和我的不情愿的假设告诉我,LDAP-realm-land中的某个地方手工打开了一个直接插座(即不使用像HttpUrlConnection或其他抽象类似的东西).果然,太阳编写的LDAP-JNDI网桥就是这样做的;传入的URI是socket:// somehost:389.

所以从所有这一切,尽管事实上我没有设置任何代理信息,配置任何东西或做任何事情,而不是使用直接的默认值,事实证明,JDK尝试使用SOCKS代理.请参阅the setImpl() method in java.net.Socketline 364 or so of SocksSocketImpl.java,详细了解.

(这最后表明,我可以通过简单地在混合中添加一个socksNonProxyHosts = *系统属性来跳过这个整个的codepath.Jeez,这个行为不应该是默认的吗?)

因此,由于某些原因,DefaultProxySelector由于某些原因而拥有hasSystemProxies field set to true,尽管我或GlassFish的配置没有任何变化,但由于花园种类的Sun LDAP连接创建的花园种类套接字导致本机查找一个SOCKS代理服务器.也许这只是我,但那是我疯狂的.

所以读过这个的人也许 – 也许你在JDK团队,或知道一个人,或者知道这里的历史 – 知道为什么java.net.Socket的默认实现总是寻找一个SOCKS代理?

更新:我可以看到答案是:所以如果你有一个系统代理设置在某个地方,并启​​用SOCKS,所有的东西都会流经它.但是如果java.net.useSystemProxies的默认值为false,那么对于SOCKS代理,狩猎(默认情况下)是什么意思?

解决方法

默认套接字实现是SocksSocketImpl,因为JRE可能已经通过系统属性-DsocksProxyHost和-DsocksProxyPort或ProxySelector.setDefault()或通过JRE安装的默认ProxySelect从外部配置为使用SOCKS.

PlainSocketImpl不会参考这些属性或类(因为它是一个普通的套接字,不应该知道任何代理),所以这些外部配置将被忽略,SocksSocketImpl总是被调用来检查它们.我同意,当没有人向JRE发表任何关于SOCKS的内容时,您会收到一个SocksSocketImpl似乎是奇怪的,但是我猜测到java.net.Socket和ProxySelector的架构不允许在Socket实例化时预先选择正确的内容.

我认为你(或谁领导当前的Glassfish bug的调查行为)可能是错误的方式:而不是试图颠覆JRE选择套接字impls和代理的方式,为什么不修复默认的ProxySelector和/或OS本机调用,以便当Java对代理的信息进行标准查询时,事情不会中断.我认为修复是在代理查找过程和类的胆量,而不是更高.

也许另一种方式来问我问的是:如果DefaultProxySelector可以告诉我代理用于套接字连接,为什么Socket首先调用它来帮助它选择一个合理的实现?

我认为问题是java.net.Socket支持多种编程模型.有一个明显的新Socket(主机,端口)构造函数,但是还有一个默认的构造函数Socket()可以先构造,然后在某些任意时间,将来可以调用它的连接(SocketAddress)方法.

由于ProxySelector可用于确定代理是否应被使用的部分标准是要连接的远程主机和远程端口的名称(即提供给connect的信息),即java.net. Socket构造函数太早,无法知道是否需要代理.

无论什么原因(我们可以假设历史?/向后兼容性原因?:),java.net.Socket的构造函数是唯一的含义,也就是说,在某些情况下,这在某些情况下太早了将需要一个代理.

猜你在找的Java相关文章