Java ProxySelector未定义的行为

1 人关注

我正在尝试使用java网络中的代理服务器。我已经 阅读了 关于它们的文档,目前正在测试ProxySelector。

我注意到这个ProxySelector在与HttpURLConnection一起使用时和与Socket类一起使用时有两种行为

当与HttpUrlConnection一起使用这个代码时

  class CustomSelector extends ProxySelector
   @Override
   public List<Proxy> select(URI uri)
    System.out.println("Selecting");
    System.out.println("===============");
    return List.of
      new Proxy(Proxy.Type.HTTP,new InetSocketAddress("localhost",5000))
     ,new Proxy(Proxy.Type.HTTP,new InetSocketAddress("localhost",8000))
     ,Proxy.NO_PROXY
   @Override
   public void connectFailed(URI uri, SocketAddress sa, IOException ioe) 
    System.out.println("Failed:"+uri);
    System.out.println("Address:"+sa);
    System.out.println("Exception:"+sa);
    System.out.println("=========================");
 public static void main(String[] args)throws Exception
  ProxySelector.setDefault(new CustomSelector());
  HttpURLConnection con=(HttpURLConnection)new URL("http://192.168.1.2:2000/Test")
                        .openConnection();
  System.out.println(con.getResponseMessage());
  con.disconnect();

我得到了预期的输出

Selecting
===============
Failed:http://192.168.1.2:2000/Test
Address:localhost/127.0.0.1:5000
Exception:localhost/127.0.0.1:5000
=========================
Failed:http://192.168.1.2:2000/Test
Address:localhost/127.0.0.1:8000
Exception:localhost/127.0.0.1:8000
=========================
Not-Implemented

这是有道理的,因为端口5000和8000只是假的端口,上面没有运行的服务器,因此在它们上面的连接失败了,最后转到NO_PROXY,它直接连接到我的运行在端口2000上的自定义HttpServer,该端口没有实现所有的功能。

现在我使用同样的程序来处理套接字。我再次验证了我的服务器是在2000端口上运行的。

  class CustomSelector extends ProxySelector
   @Override
   public List<Proxy> select(URI uri)
    System.out.println("Selecting");
    System.out.println("===============");
     return List.of
       new Proxy(Proxy.Type.SOCKS,new InetSocketAddress("localhost",5000))
      ,new Proxy(Proxy.Type.SOCKS,new InetSocketAddress("localhost",8000))
     ,Proxy.NO_PROXY 
   @Override
   public void connectFailed(URI uri, SocketAddress sa, IOException ioe) 
    System.out.println("Failed:"+uri);
    System.out.println("Address:"+sa);
    System.out.println("Exception:"+sa);
    System.out.println("=========================");
 public static void main(String[] args)throws Exception
  ProxySelector.setDefault(new CustomSelector());
  try(Socket client=new Socket())
   System.out.println("Connecting");
   client.connect(new InetSocketAddress(InetAddress.getLocalHost(),2000));
   System.out.println("Connected");

我得到这样的输出

Connecting
Selecting
===============
Failed:socket://DESKTOP-1N0I046:2000
Address:localhost/127.0.0.1:5000
Exception:localhost/127.0.0.1:5000
=========================
Failed:socket://DESKTOP-1N0I046:2000
Address:localhost/127.0.0.1:8000
Exception:localhost/127.0.0.1:8000
=========================
Exception in thread "main" java.net.SocketException: Socket closed
    at java.base/sun.nio.ch.NioSocketImpl.beginConnect(NioSocketImpl.java:498)
    at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:580)
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
    at java.base/java.net.Socket.connect(Socket.java:633)
    at java.base/java.net.Socket.connect(Socket.java:583)
    at n_networking.proxy.TCPClient.main(TCPClient.java:237)

这不应该发生,因为代理列表中的最后一个选项是NO_PROXY,这意味着没有任何代理的直接连接,这应该是成功的,但似乎ProxySelector从未使用列表中的最后一个选项。

更奇怪的是,如果我把我的ProxyType从SOCKS改为HTTP,如下所示。我知道在这种情况下没有意义,但这只是为了测试目的

   @Override
   public List<Proxy> select(URI uri)
    System.out.println("Selecting");
    System.out.println("===============");
     return List.of
       new Proxy(Proxy.Type.HTTP,new InetSocketAddress("localhost",5000))
      ,new Proxy(Proxy.Type.HTTP,new InetSocketAddress("localhost",8000))
      ,Proxy.NO_PROXY 

然后一切都会正常。

Connecting
Selecting
===============
Connected

由于某些原因,它跳过了所有的HTTP代理类型,甚至没有测试,然后。

我已经使用Sockets与Proxy.HTTP和它的工作原理是完美的,因为它发出一个CONNECT命令之前发送数据。

这是我的假服务器,我使用这两个测试案例

 public static void main(String[] args)throws Exception
  try(ServerSocket server=new ServerSocket(2000,0,InetAddress.getLocalHost()))
   System.out.println("Main Server Started");
   try(Socket socket=server.accept())
    System.out.println("Accepted");
    socket.getOutputStream().write("HTTP/1.1 501 Not-Implemented\r\n\r\n".getBytes());
    socket.getOutputStream().flush();