我试图让Socks v4在java.net中开箱即用,而且我似乎已经成功了!我使用的代码是这样的:"Socks v4"。大致上我使用的代码是这样的。
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;
}
}
长话短说, 当我创建一个套接字并传递 -DocksProxyHost和 -DocksProxyPort时, 它就会工作.
我的问题是,当我在junit测试中使用同样的代码时,我可以用Reflections检查Socket.impl.useV4是否设置为true,socksProxy*设置是否在系统范围内,但当我使用我的socket时,它完全避免使用代理(我可以在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代理即使切换(使用V4)是真的。这是我在SO这里得出的结论。
为了解决第一个问题,我实现了SocketImplFactory(见上面的问题).对解决题目问题有帮助的是我的管理员背景,尽管它直到最近才开始发挥作用:) 我把原来的嫌疑人(JUnit和Gradle)分开,在一个独立的psvm文件中做了测试。测试没有成功,还是避免了通过代理。这时我才恍然大悟:localhost的异常!
基本上,在Java核心库深处有一个硬编码的localhost(127.0.0.1,::等)异常。经过一番搜索,我发现了 DsocksNonProxyHosts(非代理主机) 选项。你可能已经猜到了,这并没有什么帮助:)最终,我结束了在 这个 的回答,其中提到我可能需要实现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));
}
现在我想要的东西都能用了 我既可以E2E测试我的socks4代码 也可以在本地主机上进行测试