ホームページ Java &#&チュートリアル Javaでプロキシを利用してネットワーク接続を実現する方法の紹介

Javaでプロキシを利用してネットワーク接続を実現する方法の紹介

Sep 26, 2017 am 09:38 AM
java 成し遂げる 通信網

这篇文章主要介绍了Java使用代理进行网络连接方法示例,内容十分详细,需要的朋友可以参考下。

需求是这样的:

一、界面上要有这样几种代理类型可以选。

1.HTTP代理

2.Socks代理

3.不使用代理(直连)

4.使用浏览器设置(浏览器也是HTTP、Socks、直连三种)。

可参考QQ登录设置里的代理能,其实跟qq的代理功能是一样的。

二、测试使用所填写的代理配置信息是否可连接

三、记录用户上次选择的代理配置,默认使用用户上次使用的代理配置进行网络连接。

程序运行环境是WindowsXP、Windows7、Windows8系统。

使用的技术为Java7,Swing,CXF。

难点:

1.如何进行全居的代理设置:


/**
 * 网络代理Bean
 * 
 * @author tang
 */
public class NetworkBean implements Serializable {
  private static final long serialVersionUID = 1L;
  // private static sun.misc.BASE64Encoder base64Encoder = new sun.misc.BASE64Encoder();
  private Proxy.Type type;// 代理类型
  private String address;// ip 地址
  private String port;// 端口号
  private String username;// 代理服务器用户名
  private String password;// 代理服务器用户密码
  private String domain;// 域
  private String typeText;// 代理类型显示的文本
  public NetworkBean() {
  }
  public NetworkBean(Type type, String address, String port, String username, String password) {
    this.type = type;
    this.address = address;
    this.port = port;
    this.username = username;
    this.password = password;
  }
  public NetworkBean(Type type, String address, String port, String username, String password, String domain) {
    super();
    this.type = type;
    this.address = address;
    this.port = port;
    this.username = username;
    this.password = password;
    this.domain = domain;
  }
  public Proxy.Type getType() {
    return type;
  }
  public void setType(Proxy.Type type) {
    this.type = type;
  }
  public String getAddress() {
    return address;
  }
  public void setAddress(String address) {
    this.address = address;
  }
  public String getPort() {
    return port;
  }
  public void setPort(String port) {
    this.port = port;
  }
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String getPassword() {
    return password;
  }
  public void setPassword(String password) {
    this.password = password;
  }
  public String getDomain() {
    return domain;
  }
  public void setDomain(String domain) {
    this.domain = domain;
  }
  public String getTypeText() {
    return typeText;
  }
  public void setTypeText(String typeText) {
    this.typeText = typeText;
  }
  /**
   * return domain + "\" + username
   */
  public String getDomainAndUsername() {
    return (Utils.toString(domain).trim().isEmpty()) ? username : domain.trim() + "\\" + username;
  }
  /**
   * return domain + "\" + username + ":" + password
   */
  public String getDomainAndUsernameAndPassword() {
    return getDomainAndUsername() + ":" + password;
  }
  /**
   * return username + ":" + password
   */
  public String getUsernameAndPassword() {
    return username + ":" + password;
  }
  /**
   * return (domain + "\" + username + ":" + password) to 64 bit
   */
  public String getDomainAndUsernameAndPassword64() {
    return org.apache.commons.codec.binary.Base64.encodeBase64String(getDomainAndUsernameAndPassword().getBytes());
  }
  @Override
  public String toString() {
    return "NetworkBean [type=" + type + ", typeText=" + typeText + ", address=" + address + ", port=" + port + ", username=" + username + ", password="
        + password + ", domain=" + domain + "]";
  }
}
ログイン後にコピー


/**
   * 根据指定的代理信息设置系统全局的网络代理
   * 
   * @param networkBean
   */
  public static void setNetworkProxyBySystem(NetworkBean networkBean) {
    System.out.println("System Set Proxy : " + networkBean);
    if (isUserProxy(networkBean)) {
      if (networkBean.getType() == Proxy.Type.SOCKS) {
        System.getProperties().remove("http.proxyHost");
        System.getProperties().remove("http.proxyPort");
        System.getProperties().setProperty("socksProxyHost", networkBean.getAddress());
        System.getProperties().setProperty("socksProxyPort", networkBean.getPort());
      } else {
        System.getProperties().setProperty("http.proxyHost", networkBean.getAddress());
        System.getProperties().setProperty("http.proxyPort", networkBean.getPort());
      }
      Authenticator.setDefault(new BairuiAuthenticator(networkBean.getDomainAndUsername(), networkBean.getPassword()));
    } else if (networkBean != null) {
      System.getProperties().remove("proxySet");
      System.getProperties().remove("socksProxySet");
      System.getProperties().remove("http.proxyHost");
      System.getProperties().remove("http.proxyPort");
      System.getProperties().remove("socksProxyHost");
      System.getProperties().remove("socksProxyPort");
    }
  }
  /**
   * 网络用户名密码校验提供者
   */
  public static class BairuiAuthenticator extends Authenticator {
    private String username, password;
    public BairuiAuthenticator(String username, String password) {
      this.username = username;
      this.password = password;
    }
    protected PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(username, password == null ? null : password.toCharArray());
    }
  }
ログイン後にコピー

2.如何让CXF的Service使用系统的代理:


 /**
   * 为WebService接口添加网络代理支持:httpClientPolicy.setAllowChunking(false);
   * 
   * @param client
   */
  public static void setWebServiceSupportProxy(Client client) {
    HTTPConduit conduit = (HTTPConduit) client.getConduit();
    HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
    httpClientPolicy.setAllowChunking(false);
    conduit.setClient(httpClientPolicy);
  }
ログイン後にコピー

3.使用浏览器设置:


/**
   * 读取用户注册表获取浏览器的代理设置
   * 
   * @return 该方法不会返回null值也不会抛出异常
   */
  public static NetworkBean getBrowserProxy() {
    NetworkBean networkBean = new NetworkBean();
    networkBean.setTypeText(typeTexts[3]);
    networkBean.setType(Proxy.Type.DIRECT);
    String key = "reg query \"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\"";// 注册表浏览器代理key
    try {
      Process exec = Runtime.getRuntime().exec(key);
      try (InputStreamReader i = new InputStreamReader(exec.getInputStream()); BufferedReader ir = new BufferedReader(i)) {
        for (String line = ir.readLine(); line != null; line = ir.readLine()) {
          if (line.indexOf("ProxyServer") >= 0) {
            String[] split1 = line.split("  ");
            if (split1.length > 3) {
              String[] split2 = split1[3].trim().split(":");
              if (split2.length > 1) {
                if (!Utils.toString(split2[0]).isEmpty() && !Utils.toString(split2[1]).isEmpty()) {
                  networkBean.setAddress(split2[0]);
                  networkBean.setPort(split2[1]);
                  networkBean.setType(Proxy.Type.HTTP);
                  break;
                }
              }
            }
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    } catch (Exception e) {// 从注册表读取失败
      e.printStackTrace();
    }
    return networkBean;
  }
ログイン後にコピー

4.测试代理是否可用

因为程序中使用了服务器的两个不同的端口,所以需要测试两个端口是否都可连。

如果使用了多台服务器,更加需要分别测试了。


 /**
   * 测试网络代理是否能通过连接,如果不通过抛出异常
   * 
   * @throws Exception
   */
  private static void testNetworkProxy() throws Exception {
    testWebService();
    testURLConnection();
  }
  /**
   * 测试CXF Service接口50367端口
   * 
   * @param networkBean
   * @throws Exception
   */
  public static void testWebService() throws Exception {
    JcptLoginService service = WebServiceUtils.getService(JcptLoginService.class, GeneralWebServiceAddress.LOGIN_SERVICE_URL_ADD);
    String result = service.getLoginPicture();
    System.out.println(result);
  }
  /**
   * 从HttpURLConnection对象读取指定字符,如果不匹配则抛出异常
   * 
   * @param connection
   * @throws Exception
   */
  private static void checkConnectionContent(HttpURLConnection connection) throws Exception {
    try (InputStream inputStream = connection.getInputStream()) {
      byte[] b = new byte[1024];
      boolean success = false;
      StringBuffer sb = new StringBuffer();
      for (int i = inputStream.read(b); i > 0; i = inputStream.read(b)) {
        String tempStr = new String(b, 0, i);
        sb.append(tempStr);
        if (tempStr.indexOf("3,file not found") >= 0) {// service固定返回这个字符串,如果service作了更改此处也应更改
          success = true;
          break;
        }
      }
      if (!success) {
        String str = sb.toString();
        if (str.length() > 3) {
          char char0 = str.charAt(0);
          char char1 = str.charAt(1);
          if (Utils.isNumber(char0 + "") && char1 == ',') {
            success = true;
          }
        }
      }
      if (!success) {
        throw new RuntimeException("result content does not meet expectations.");
      }
    } catch (Exception ex) {
      throw ex;
    }
  }
  /**
   * 测试文件下载接口9067端口
   * 
   * @param networkBean
   * @throws Exception
   */
  public static void testURLConnection() throws Exception {
    HttpURLConnection connection = (HttpURLConnection) new URL(GeneralWebServiceAddress.FILE_DOWN_URL_ADD + "path=").openConnection();
    checkConnectionContent(connection);
  }
ログイン後にコピー


 /**
   * 测试代理服务器连接
   */
  private void testProxyConnection() {
    NetworkBean readNetworkBean = NetworkProxyTool.readNetworkBean();// 先获得正在使用的NetworkBean
    try {
      NetworkBean networkBean = createNetworkBean();// 根据用户填写的信息创建的NetworkBean对象
      showTestResultDialog(NetworkProxyTool.testNetworkProxyBySystem(networkBean));
    } catch (Exception ex) {
      showTestResultDialog(false);
    }
    NetworkProxyTool.setNetworkProxyBySystem(readNetworkBean);// 测试结束,还原原来的NetworkBean
  }
ログイン後にコピー

5.因为java连接网络时,如果使用当前的代理连接失败,那么就会使用操作系统中缓存的代理进行网络连接,如何是测试连接时不使用操作系统缓存,但测试结束后使用操作系统缓存。


 /**
   * 设置长连接和验证信息缓存是否开启
   * 
   * @param keepAlive
   */
  public static void setKeepAliveAndAuthCache(boolean keepAlive) {
    System.setProperty("http.keepAlive", keepAlive + "");// 设置是否开始长连接,如果为false可以防止连接被缓存(如果连接被缓存,用户名密码等所有信息都会被缓存)
    if (keepAlive) {
      AuthCacheValue.setAuthCache(new AuthCacheImpl());
    } else {
      // 设置一个空的实现AuthCache可以防止用户名密码信息被缓存
      AuthCacheValue.setAuthCache(new AuthCache() {
        public void remove(String pkey, AuthCacheValue entry) {
        }
        public void put(String pkey, AuthCacheValue value) {
        }
        public AuthCacheValue get(String pkey, String skey) {
          return null;
        }
      });
    }
  }
ログイン後にコピー

在登录之前:


  NetworkProxyTool.setKeepAliveAndAuthCache(false);
  new.Login();
ログイン後にコピー

登录成功后:


 NetworkProxyTool.setKeepAliveAndAuthCache(true);
ログイン後にコピー

6.保存用户的代理配置:

因为直接序列化自定义类型的对象,会存在版本问题(比如这个类的包名、类名改了,就死定了)。
所以不能直接序列化自定义类的对象,二是将自定义类对象的属性转成字典(Map),然后序列化map。


/**
   * 读取本地网络代理设置配置文件
   * 
   * @return
   */
  public static NetworkBean readNetworkBean() {
    NetworkBean networkBean = getCurrNetworkBean(readNetworkBeanMap());
    if (networkBean == null) {
      networkBean = new NetworkBean();
      networkBean.setType(Proxy.Type.DIRECT);
    }
    return networkBean;
  }
  /**
   * 获取用户上次选择网络代理设置
   * 
   * @param map
   * @return
   */
  public static NetworkBean getCurrNetworkBean(Map<String, Object> map) {
    putBrowserProxy(map);
    return (NetworkBean) map.get(getTypeMapKey(map));
  }
  /**
   * 将浏览器的信息存放入代理信息总配置map
   * 
   * @param map
   */
  private static void putBrowserProxy(Map<String, Object> map) {
    if (browserProxyBean == null) {
      browserProxyBean = getBrowserProxy();
    }
    NetworkBean networkBeanBrowser = (NetworkBean) map.get(key_browser);
    if (networkBeanBrowser == null) {
      networkBeanBrowser = browserProxyBean;
    }
    if ((Utils.toString(browserProxyBean.getAddress()).isEmpty() || !browserProxyBean.getAddress().equals(networkBeanBrowser.getAddress()))
        || (Utils.toString(browserProxyBean.getPort()).isEmpty() || !browserProxyBean.getPort().equals(networkBeanBrowser.getPort()))) {
      networkBeanBrowser.setUsername(null);
      networkBeanBrowser.setPassword(null);
      networkBeanBrowser.setDomain(null);
    }
    networkBeanBrowser.setType(browserProxyBean.getType());
    networkBeanBrowser.setTypeText(browserProxyBean.getTypeText());
    networkBeanBrowser.setAddress(browserProxyBean.getAddress());
    networkBeanBrowser.setPort(browserProxyBean.getPort());
    map.put(key_browser, networkBeanBrowser);
  }
ログイン後にコピー

在登录之前:


  NetworkBean networkBean = NetworkProxyTool.readNetworkBean();
  NetworkProxyTool.setNetworkProxyBySystem(networkBean);
  NetworkProxyTool.setKeepAliveAndAuthCache(false);
  new.Login();
ログイン後にコピー

在用户配置完代理点击确定时:


 /**
   * 点击确定
   */
  private void confirm() {

    if ((isHttp() || isSocks()) && !checkIpAndPortNotNull()) {
      return;
    }
    NetworkBean networkBean = createNetworkBean();
    if (isHttp()) {// HTTP代理
      if (networkBean.getDomain() != null) {
        networkBean.setDomain(networkBean.getDomain().trim());
      }
      proxySettingMap.put(key_http, networkBean);
      proxySettingMap.put(key_proxy_type, key_http);
    } else if (isSocks()) {// SOCKS代理
      proxySettingMap.put(key_socks, networkBean);
      proxySettingMap.put(key_proxy_type, key_socks);
    } else if (isBrowser()) {
      proxySettingMap.put(key_browser, networkBean);
      proxySettingMap.put(key_proxy_type, key_browser);
    } else {
      proxySettingMap.put(key_direct, networkBean);
      proxySettingMap.put(key_proxy_type, key_direct);
    }
    userCurrShowNetworkBean = networkBean;
    isConfirm = true;
    setVisible(false);
    NetworkProxyTool.saveNetworkProxyConfig(proxySettingMap);
  }
ログイン後にコピー

System Properties

Java System Properties网络设置有哪些key

http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html

http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html

Java System Properties优先级说明

host和port比set优先级高,也就是说set可以不用去设置。

如存在http.proxyHost和http.proxyPort时,proxySet设为false无效,系统仍然可以使用http代理。

存在socksProxyHost和socksProxyPort时,socksProxySet设为false无效,系统仍然可以使用socks代理。

http比socks优先级高,即存在http.proxyHost和http.proxyPort时,socksProxySet、socksProxyHost、socksProxyPort都会失效,系统会使用http代理。

使用java.net.Proxy

如果只是单个的连接需要使用代理,那么可以采用Proxy类进行代理连接。

说明:

1.Socket只能使用socks代理不能使用http代理。

2.Socket使用使用Authenticator来进行验证。

3.URLConnection 使用RequestProperty是只对当前连接有效,不会缓存,Authenticator是全局性的,对所有网络请求都有效,会缓存,但RequestProperty的优先级比Authenticator高。

4.只有RequestProperty需要64位编码,Authenticator不需要。

5.需要清除验证缓存的,不使用验证缓存上面已经有代码了,这里就不重复写了。

6.其实,建议采用全局性的代理连接,不管是URLConnection 还是Socket 都简单方便、统一。

代码:


NetworkBean httpBean = new NetworkBean(Proxy.Type.HTTP, "192.168.77.5", "8888", "tzc", "123", null);
Proxy httpProxy = new Proxy(httpBean.getType(), new InetSocketAddress(httpBean.getAddress(), Integer.parseInt(httpBean.getPort())));
NetworkBean socksBean = new NetworkBean(Proxy.Type.SOCKS, "192.168.77.5", "9999", "tzc", "123", "ttt");
Proxy socksProxy = new Proxy(socksBean.getType(), new InetSocketAddress(socksBean.getAddress(), Integer.parseInt(socksBean.getPort())));
URLConnection httpProxyConnection = new URL("http://www.baidu.com/").openConnection(httpProxy);
//或者Authenticator.setDefault(new BairuiAuthenticator(networkBean.getDomainAndUsername(), networkBean.getPassword()));
httpProxyConnection.setRequestProperty("Proxy-Authorization", "Basic "+httpBean.getDomainAndUsernameAndPassword64());
URLConnection socksProxyConnection = new URL("http://www.baidu.com/").openConnection(socksProxy);
//或者Authenticator.setDefault(new BairuiAuthenticator(networkBean.getDomainAndUsername(), networkBean.getPassword()));
socksProxyConnection.setRequestProperty("Proxy-Authorization", "Basic "+httpBean.getDomainAndUsernameAndPassword64());
Socket socket = new Socket(socksProxy);
Authenticator.setDefault(new BairuiAuthenticator(networkBean.getDomainAndUsername(), networkBean.getPassword()));
socket.connect(new InetSocketAddress("www.baidu.com", 5555));
ログイン後にコピー

总结

以上がJavaでプロキシを利用してネットワーク接続を実現する方法の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

See all articles