【问题标题】:My simple java HTTPS server only works for localhost我的简单 java HTTPS 服务器仅适用于 localhost
【发布时间】:2014-06-11 20:57:50
【问题描述】:

我有一个用 Java 实现的简单 HTTPS 测试服务器,如下所示。它接受客户端连接并发回一段关于套接字的文本。问题是它在使用https://localhost:8888 的浏览器上本地工作,但是当我使用我机器的真实 IP (129.46.xx.xx:8888) 时,它不适用于远程浏览器。问题出在哪里?测试时,不要忘记生成示例证书并提供以下信息。

编辑:有趣的是,当我在 Ubuntu 12.04 上运行它时,我可以连接到它。但在 Windows 上运行时不会!

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
public class HttpsEchoer {
   public static void main(String[] args) {
      String ksName = "myks.jks";
      char ksPass[] = "mypass".toCharArray();
      char ctPass[] = "mypass".toCharArray();
      try {
         KeyStore ks = KeyStore.getInstance("JKS");
         ks.load(new FileInputStream(ksName), ksPass);
         KeyManagerFactory kmf = 
         KeyManagerFactory.getInstance("SunX509");
         kmf.init(ks, ctPass);
         SSLContext sc = SSLContext.getInstance("TLS");
         sc.init(kmf.getKeyManagers(), null, null);
         SSLServerSocketFactory ssf = sc.getServerSocketFactory();
         SSLServerSocket s 
            = (SSLServerSocket) ssf.createServerSocket(8888);
         System.out.println("Server started:");
         printServerSocketInfo(s);
         // Listening to the port
         int count = 0;
         while (true) {
            SSLSocket c = (SSLSocket) s.accept();
            // Someone is calling this server
            count++;
            System.out.println("Connection #: "+count);
            printSocketInfo(c);
            BufferedWriter w = new BufferedWriter(
               new OutputStreamWriter(c.getOutputStream()));
            BufferedReader r = new BufferedReader(
               new InputStreamReader(c.getInputStream()));
            String m = r.readLine();
//            System.out.println(m);
            if (m!=null) {
               // We have a real data connection
               w.write("HTTP/1.1 200 OK");
               w.newLine();
               w.write("Content-Type: text/html");
               w.newLine();
               w.newLine();
               w.write("<html><body><pre>");
               w.newLine();
               w.write("Connection #: "+count);
               w.newLine();
               w.newLine();
               w.write(m);
               w.newLine();
               while ((m=r.readLine())!= null) {
                  if (m.length()==0) break; // End of a GET call
                  w.write(m);
                  w.newLine();
               }
               w.write("</pre></body></html>");
               w.newLine();
               w.flush();
            }     
            w.close();
            r.close();
            c.close();
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
   private static void printSocketInfo(SSLSocket s) {
      System.out.println("Server socket class: "+s.getClass());
      System.out.println("   Remote address = "
         +s.getInetAddress().toString());
      System.out.println("   Remote port = "
         +s.getPort());
      System.out.println("   Local socket address = "
         +s.getLocalSocketAddress().toString());
      System.out.println("   Local address = "
         +s.getLocalAddress().toString());
      System.out.println("   Local port = "
         +s.getLocalPort());
   }
   private static void printServerSocketInfo(SSLServerSocket s) {
      System.out.println("Server socket class: "+s.getClass());
      System.out.println("   Socker address = "
         +s.getInetAddress().toString());
      System.out.println("   Socker port = "
         +s.getLocalPort());
      System.out.println("   Need client authentication = "
         +s.getNeedClientAuth());
      System.out.println("   Want client authentication = "
         +s.getWantClientAuth());
      System.out.println("   Use client mode = "
         +s.getUseClientMode());
   } 
}

这是printServerSocketInfo() 方法显示的内容:

Server started:
Server socket class: class sun.security.ssl.SSLServerSocketImpl
   Socker address = 0.0.0.0/0.0.0.0
   Socker port = 8888
   Need client authentication = false
   Want client authentication = false
   Use client mode = false

这是本地浏览器显示的内容:

Connection #: 3

GET / HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36 OPR/22.0.1471.50 (Edition Campaign 38)
Accept-Encoding: gzip,deflate,lzma,sdch
Accept-Language: en-US,en;q=0.8

【问题讨论】:

  • 您应该在防火墙中打开端口 8888。如果您使用的是 Windows,则打开Start 菜单,输入firewall,单击Inbound Rules,单击New Rule...,选择Port,单击Next,选择Specific local ports,然后输入8888
  • 创建套接字时printServerSocketInfo 的输出是什么样的?
  • 服务器的防火墙,还是客户端的防火墙?那么我可以使用什么端口不被阻塞? 443、4443 对 HTTPS 有效吗?!
  • @JohnFarrelly 刚刚添加了它的外观。
  • @TinaJasmin 看起来不像 printServerSocketInfo 将打印的输出?

标签: java servlets


【解决方案1】:

尝试像这样创建您的服务器套接字:

SSLServerSocket s = (SSLServerSocket) ssf.createServerSocket(8888, 0, null);

null 作为最后一个参数应该告诉服务器套接字工厂创建一个绑定到所有网络接口的套接字。

这是该方法的特定版本的link to the javadoc

【讨论】:

  • 我还怀疑您的套接字仅绑定到您的环回接口。
  • 这和他做的效果一样。事实上,他调用的构造函数调用了这个构造函数,并将 null 作为第三个参数。
  • @EJP printServerSocketInfo 调用的输出表明套接字绑定到localhost,而不是0.0.0.0,如果它绑定到所有网络接口?
  • @JohnFarrelly 没有区别。有趣的是,当我在 Ubuntu 上运行它时,我可以连接到它。但不是窗户!
  • @TinaJasmin 这很可能是您的 Windows 操作系统上的防火墙设置。在这里查看有关在 Windows 上打开端口的信息:windows.microsoft.com/en-ie/windows/…
猜你喜欢
  • 2011-01-19
  • 2019-03-30
  • 2019-11-20
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 2020-09-03
  • 2012-01-01
  • 1970-01-01
相关资源
最近更新 更多