简体   繁体   English

Java HttpsServer 多线程

[英]Java HttpsServer multi threaded

I have set up an HttpsServer in Java.我已经在 J​​ava 中设置了一个 HttpsServer。 All of my communication works perfectly.我所有的沟通都完美无缺。 I set up multiple contexts, load a self-signed certificate, and even start up based on an external configuration file.我设置了多个上下文,加载了自签名证书,甚至基于外部配置文件启动。

My problem now is getting multiple clients to be able to hit my secure server.我现在的问题是让多个客户端能够访问我的安全服务器。 To do so, I would like to somehow multi-thread the requests that come in from the HttpsServer but cannot figure out how to do so.为此,我想以某种方式对来自 HttpsServer 的请求进行多线程处理,但不知道该怎么做。 Below is my basic HttpsConfiguration.下面是我的基本 HttpsConfiguration。

  HttpsServer server = HttpsServer.create(new InetSocketAddress(secureConnection.getPort()), 0);
  SSLContext sslContext = SSLContext.getInstance("TLS");

  sslContext.init(secureConnection.getKeyManager().getKeyManagers(), secureConnection.getTrustManager().getTrustManagers(), null);

  server.setHttpsConfigurator(new SecureServerConfiguration(sslContext));
  server.createContext("/", new RootHandler());
  server.createContext("/test", new TestHandler());
  server.setExecutor(Executors.newCachedThreadPool());
  server.start();

Where secureConnection is a custom class containing server setup and certificate information.其中 secureConnection 是包含服务器设置和证书信息的自定义类。

I attempted to set the executor to Executors.newCachedThreadPool() and a couple of other ones.我试图将执行程序设置为Executors.newCachedThreadPool()和其他几个。 However, they all produced the same result.然而,它们都产生了相同的结果。 Each managed the threads differently but the first request had to finish before the second could process.每个人都以不同的方式管理线程,但第一个请求必须在第二个可以处理之前完成。

I also tried writing my own Executor我也尝试编写自己的 Executor

public class AsyncExecutor extends ThreadPoolExecutor implements Executor
{
   public static Executor create()
   {
      return new AsyncExecutor();
   }

   public AsyncExecutor()
   {
      super(5, 10, 10000, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(12));
   }

   @Override
   public void execute(Runnable process)
   {
      System.out.println("New Process");

      Thread newProcess = new Thread(process);
      newProcess.setDaemon(false);

      newProcess.start();

      System.out.println("Thread created");
   }
}

Unfortunately, with the same result as the other Executors.不幸的是,结果与其他 Executor 相同。

To test I am using Postman to hit the /Test endpoint which is simulating a long running task by doing a Thread.sleep(10000) .为了测试,我使用 Postman 命中 /Test 端点,该端点通过执行Thread.sleep(10000)来模拟长时间运行的任务。 While that is running, I am using my Chrome browser to hit the root endpoint.在运行时,我使用 Chrome 浏览器访问根端点。 The root page does not load until the 10 second sleep is over.直到 10 秒睡眠结束后才会加载根页面。

Any thoughts on how to handle multiple concurrent requests to the HTTPS server?关于如何处理对 HTTPS 服务器的多个并发请求的任何想法?

For ease of testing, I replicated my scenario using the standard HttpServer and condensed everything into a single java program.为了便于测试,我使用标准 HttpServer 复制了我的场景,并将所有内容压缩到一个 Java 程序中。

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Example
{
   private final static int PORT = 80;
   private final static int BACKLOG = 10;

   /**
    * To test hit:
    * <p><b>http://localhost/test</b></p>
    * <p>This will hit the endoint with the thread sleep<br>
    * Then hit:</p>
    * <p><b>http://localhost</b></p>
    * <p>I would expect this to come back right away. However, it does not come back until the
    * first request finishes. This can be tested with only a basic browser.</p>
    * @param args
    * @throws Exception
    */
   public static void main(String[] args) throws Exception
   {
      new Example().start();
   }

   private void start() throws Exception
   {
      HttpServer server = HttpServer.create(new InetSocketAddress(PORT), BACKLOG);

      server.createContext("/", new RootHandler());
      server.createContext("/test", new TestHandler());
      server.setExecutor(Executors.newCachedThreadPool());
      server.start();

      System.out.println("Server Started on " + PORT);
   }

   class RootHandler implements HttpHandler
   {
      @Override
      public void handle(HttpExchange httpExchange) throws IOException
      {
         String body = "<html>Hello World</html>";

         httpExchange.sendResponseHeaders(200, body.length());
         OutputStream outputStream = httpExchange.getResponseBody();

         outputStream.write(body.getBytes("UTF-8"));
         outputStream.close();
      }
   }

   class TestHandler implements HttpHandler
   {
      @Override
      public void handle(HttpExchange httpExchange) throws IOException
      {
         try
         {
            Thread.sleep(10000);
         }
         catch (InterruptedException e)
         {
            e.printStackTrace();
         }

         String body = "<html>Test Handled</html>";

         httpExchange.sendResponseHeaders(200, body.length());
         OutputStream outputStream = httpExchange.getResponseBody();

         outputStream.write(body.getBytes("UTF-8"));
         outputStream.close();
      }
   }
}

TL;DR: It's OK, just use two different browsers, or specialized tool to test it. TL;DR:没关系,只需使用两种不同的浏览器,或专门的工具来测试它。

You original implementation is OK and it work as expected, no custom Executor needed.您最初的实现是可以的,它按预期工作,不需要自定义 Executor。 For each request it executes method of "shared" handler class instance.对于每个请求,它执行“共享”处理程序类实例的方法。 It always picks up free thread from pool, so each method call is executed in different thread.它总是从池中获取空闲线程,因此每个方法调用都在不同的线程中执行。

The problem seems to be, that when you use multiple windows of the same browser to test this behavior... for some reason requests get executed in serialised way (only one at the time).问题似乎是,当您使用同一浏览器的多个窗口来测试此行为时……出于某种原因,请求以序列化方式执行(当时只有一个)。 Tested with latest Firefox, Chrome, Edge and Postman.使用最新的 Firefox、Chrome、Edge 和 Postman 进行测试。 Edge and Postman work as expected. Edge 和 Postman 按预期工作。 Also anonymous mode of Firefox and Chrome helps. Firefox 和 Chrome 的匿名模式也有帮助。

Same local URL opened at the same time from two Chrome windows.从两个 Chrome 窗口同时打开相同的本地 URL。 In first the page loaded after 5s, I got Thread.sleep(5000) so that's OK.首先页面在 5 秒后加载,我得到了 Thread.sleep(5000) 所以没关系。 Second window loaded respons in 8,71s, so there is 3,71s delay of unknown origin.第二个窗口在 8.71 秒内加载响应,因此有 3.71 秒的未知来源延迟。

铬窗 1 铬窗 2

My guess?我猜? Probably some browser internal optimization or failsafe mechanism.可能是一些浏览器内部优化或故障保护机制。

尝试指定一个非零的最大积压( create()的第二个参数):

HttpsServer server = HttpsServer.create(new InetSocketAddress(secureConnection.getPort()), 10);

I did some experiments and what works for me is:我做了一些实验,对我有用的是:

public void handler(HttpExchange exchange) {
    executor.submit(new SomeOtherHandler());
}

public class SomeOtherHandler implements Runnable {

}

where the executor is the one you created as thread pool.其中 executor 是您创建为线程池的那个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM