SocketImpl 和 JUnit/Gradle
SocketImpl and JUnit/Gradle
我正在尝试让 Socks v4 在 java.net 中开箱即用,我似乎已经成功了!
我使用的代码大概是这样的:
class SocketImplFactorySocks4 implements SocketImplFactory {
@Override
public SocketImpl createSocketImpl() {
System.out.println("Socket implementation triggered");
try {
return socketSocks4Factory();
} catch (Exception e) {
e.printStackTrace();
throw new Error("Can't go further");
}
}
private SocketImpl socketSocks4Factory() throws
[...] {
Class<?> aClass = Class.forName("java.net.SocksSocketImpl");
Constructor<?> cons = aClass.getDeclaredConstructor();
if (!cons.isAccessible())
cons.setAccessible(true);
Object socket = cons.newInstance();
Method method = socket.getClass().getDeclaredMethod("setV4");
if (!method.isAccessible())
method.setAccessible(true);
method.invoke(socket);
Field field = socket.getClass().getDeclaredField("useV4");
field.setAccessible(true);
Object value = field.get(socket);
return (SocketImpl) socket;
}
}
长话短说,当我创建套接字并传递 -DsocksProxyHost 和 -DsocksProxyPort 时它起作用。
我的问题是当我在我的 junit 测试中使用相同的代码时,我可以通过 Reflections 检查 Socket.impl.useV4 设置为 true,socksProxy* 设置在系统范围内设置,但是当我使用我的套接字时, 它完全避免使用代理(我可以在 wireshark 中看到它)。
它是 JUnit 或 Gradle,但我已经达到了我的极限。请建议我下一步应该去哪里。 build.gradle.kts供参考:
tasks{
test{
systemProperty("socksProxyHost", "localhost")
systemProperty("socksProxyPort", "8080")
}
}
提前致谢!
好吧,我花了太多时间才弄明白,但我做到了。我最初的目标是测试我的 Socks v4 服务器代码,但我遇到了两个问题:
1) 尽管 Java Socket 支持 Socks v4 作为客户端,但默认情况下未启用。而且没有办法翻转开关。
2) 解决了 #1 之后,我尝试编写 E2E 测试来完成整个过程,但由于某种原因,它 避免进入 Socks 代理 ,即使切换(useV4)是真的。这就是我在 SO 上带来的。
为了解决第一个问题,我实现了SocketImplFactory(见上文问题)。
帮助解决主题问题的是我的管理背景,尽管它直到最近才开始出现。 :) 我分离了最初的嫌疑人(JUnit 和 Gradle)并在独立的 psvm 文件中进行了测试。测试没有成功,还是避免了通过代理。这就是它击中我的时候:localhost 的异常!
基本上,在 Java 核心库的深处有一个针对本地主机(127.0.0.1、:: 等)的硬编码异常。经过一些搜索,我遇到了 DsocksNonProxyHosts 选项。这没有帮助,正如您可能已经猜到的那样:)
最终我得到了 this 答案,其中提到我可能需要实施 ProxySelector。我做了什么:
static class myProxySelector extends ProxySelector {
@Override
public List<Proxy> select(URI uri) {
List<Proxy> proxyl = new ArrayList<Proxy>(1);
InetSocketAddress saddr = InetSocketAddress.createUnresolved("localhost", 1080);
Proxy proxy = SocksProxy.create(saddr, 4);
proxyl.add(proxy);
System.out.println("Selecting Proxy for " + uri.toASCIIString());
return proxyl;
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
if (uri == null || sa == null || ioe == null) {
throw new IllegalArgumentException("Arguments can't be null.");
}
}
}
整个套接字设置如下所示:
private void setupSocket() throws IOException {
Socket.setSocketImplFactory(new SocketImplFactorySocks4());
ProxySelector proxySelector = new myProxySelector();
ProxySelector.setDefault(proxySelector);
proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 1080));
}
现在我想要的一切都可以工作了:我既能对我的 socks4 代码进行 E2E 测试,又能在本地主机上进行测试。
我正在尝试让 Socks v4 在 java.net 中开箱即用,我似乎已经成功了! 我使用的代码大概是这样的:
class SocketImplFactorySocks4 implements SocketImplFactory {
@Override
public SocketImpl createSocketImpl() {
System.out.println("Socket implementation triggered");
try {
return socketSocks4Factory();
} catch (Exception e) {
e.printStackTrace();
throw new Error("Can't go further");
}
}
private SocketImpl socketSocks4Factory() throws
[...] {
Class<?> aClass = Class.forName("java.net.SocksSocketImpl");
Constructor<?> cons = aClass.getDeclaredConstructor();
if (!cons.isAccessible())
cons.setAccessible(true);
Object socket = cons.newInstance();
Method method = socket.getClass().getDeclaredMethod("setV4");
if (!method.isAccessible())
method.setAccessible(true);
method.invoke(socket);
Field field = socket.getClass().getDeclaredField("useV4");
field.setAccessible(true);
Object value = field.get(socket);
return (SocketImpl) socket;
}
}
长话短说,当我创建套接字并传递 -DsocksProxyHost 和 -DsocksProxyPort 时它起作用。
我的问题是当我在我的 junit 测试中使用相同的代码时,我可以通过 Reflections 检查 Socket.impl.useV4 设置为 true,socksProxy* 设置在系统范围内设置,但是当我使用我的套接字时, 它完全避免使用代理(我可以在 wireshark 中看到它)。
它是 JUnit 或 Gradle,但我已经达到了我的极限。请建议我下一步应该去哪里。 build.gradle.kts供参考:
tasks{
test{
systemProperty("socksProxyHost", "localhost")
systemProperty("socksProxyPort", "8080")
}
}
提前致谢!
好吧,我花了太多时间才弄明白,但我做到了。我最初的目标是测试我的 Socks v4 服务器代码,但我遇到了两个问题:
1) 尽管 Java Socket 支持 Socks v4 作为客户端,但默认情况下未启用。而且没有办法翻转开关。
2) 解决了 #1 之后,我尝试编写 E2E 测试来完成整个过程,但由于某种原因,它 避免进入 Socks 代理 ,即使切换(useV4)是真的。这就是我在 SO 上带来的。
为了解决第一个问题,我实现了SocketImplFactory(见上文问题)。 帮助解决主题问题的是我的管理背景,尽管它直到最近才开始出现。 :) 我分离了最初的嫌疑人(JUnit 和 Gradle)并在独立的 psvm 文件中进行了测试。测试没有成功,还是避免了通过代理。这就是它击中我的时候:localhost 的异常!
基本上,在 Java 核心库的深处有一个针对本地主机(127.0.0.1、:: 等)的硬编码异常。经过一些搜索,我遇到了 DsocksNonProxyHosts 选项。这没有帮助,正如您可能已经猜到的那样:) 最终我得到了 this 答案,其中提到我可能需要实施 ProxySelector。我做了什么:
static class myProxySelector extends ProxySelector {
@Override
public List<Proxy> select(URI uri) {
List<Proxy> proxyl = new ArrayList<Proxy>(1);
InetSocketAddress saddr = InetSocketAddress.createUnresolved("localhost", 1080);
Proxy proxy = SocksProxy.create(saddr, 4);
proxyl.add(proxy);
System.out.println("Selecting Proxy for " + uri.toASCIIString());
return proxyl;
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
if (uri == null || sa == null || ioe == null) {
throw new IllegalArgumentException("Arguments can't be null.");
}
}
}
整个套接字设置如下所示:
private void setupSocket() throws IOException {
Socket.setSocketImplFactory(new SocketImplFactorySocks4());
ProxySelector proxySelector = new myProxySelector();
ProxySelector.setDefault(proxySelector);
proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 1080));
}
现在我想要的一切都可以工作了:我既能对我的 socks4 代码进行 E2E 测试,又能在本地主机上进行测试。