2017-06-15 75 views
1

我正在製作一個接收HTTP請求的Java應用程序。對於每個進入的請求,我都會啓動一個新線程,並在該線程中讀取請求並執行必要的操作。但是,我想阻止用戶執行「Slow Loris Attack」,所以我正在考慮給線程一個maxTime值。如果線程比maxTime花費的時間更長,則無論如何都將終止。所以它也會阻塞緩慢的連接,這是不是的一個問題。Java - 在不阻塞主線程的情況下停止時間片

但是,我不知道正確的做法是什麼。我試過下面的代碼,但是這段代碼阻止了我的主線程。我正在尋找一種方式來做類似的事情,而不會阻塞主線程。

代碼:

/** 
* Executor which is used for threadpools. 
*/ 
private ExecutorService executor; 

/** 
* Constructor for the class RequestReceiver. 
* Initializes fields. 
*/ 
public RequestReceiver() { 
    this.executor = Executors.newFixedThreadPool(200); 
} 

@Override 
public void run() { 
    try { 
     this.serverSocket = new ServerSocket(port); 
    } catch (IOException ex) { 
     Logger.getInstance().logText("Could not start server on port: " + port); 
     return; 
    } 

    Logger.getInstance().logText("Server running at port: " + port); 

    try { 
     while (shouldContinue) { 
      Socket client = serverSocket.accept(); 
      HTTPRequestHandler handler = new HTTPRequestHandler(client); 
      Thread t = new Thread(handler); 
      executor.submit(t).get(10, TimeUnit.SECONDS); //This line is blocking 
     } 
    } catch (IOException ex) { 
     Logger.getInstance().logText("Server is shutdown"); 
    } catch (InterruptedException | ExecutionException | TimeoutException ex) { 
     Logger.getInstance().logText("Thread took too long, it's shutdown"); 
    } 
} 
+0

你可以添加'executor.shutdown() ;'在阻塞語句後立即執行'executor.submit(t).get(10,TimeUnit.SECONDS);'並嘗試? – harshavmb

+0

@harshavmb我不明白這將如何解決我的問題..我確實嘗試了它,並且像我預測的那樣墜毀了。因爲當您發送第二個HTTP請求時,池將不會接受它,因爲它已關閉。 'java.util.concurrent.RejectedExecutionException' – Guido

+0

你爲什麼在你的主線程中調用Future#?你甚至不用做任何事情。另外,TimeOutException不會停止任務。 – matt

回答

1

您的示例中的變化最小,可以讓你類似的東西給你想要的是提交一個新的任務。

Socket client = serverSocket.accept(); 
HTTPRequestHandler handler = new HTTPRequestHandler(client); 
Future f = executor.submit(handler); 
executor.submit(()->{ 
    try{ 
     f.get(10, TimeUnit.SECONDS); 
    } catch(TimeoutException to){ 
     //timeout happened, this will cancel/interrupt the task. 
     f.cancel(true); 
    } catch(Exception e){ 
     throw new RuntimeException(e); 
     //something else went wrong... 
    } 
}); 

這會工作,但它會阻止一個額外的線程等待獲取調用。您還需要處理HTTPRequestHandler代碼中的中斷。

另一種方式可能是使用ScheduledExecutorService

0

有幾個問題,你的方法:

我正在接收HTTP請求的Java應用程序。對於每個進入的請求,我都會啓動一個新線程,並在該線程中讀取請求並執行必要的操作。

這是一個肯定的方式,用盡內存或其他資源。相反,在一個servlet容器(tomcat,jetty)中運行你的應用程序並讓它爲你處理多線程。只要確保處理請求的代碼是「線程安全的」,因爲它將被多個線程同時調用。

如果您必須使用ServerSocket,然後使用具有固定數量的線程的ExecutorService。 (從未使用的線程數量不受限制)

不過,我想阻止用戶進行「懶猴攻擊」

爲了防止slowloris進攻,你應該運行後面的應用程序http服務器(例如Apache)並確保安裝適當的安全模塊。請參閱:http://www.techrepublic.com/blog/smb-technologist/secure-your-apache-server-from-ddos-slowloris-and-dns-injection-attacks/

我在考慮給線程一個maxTime值。如果線程花費的時間超過maxTime,它將會終止,無論如何。

這不是一個好主意。一般來說,當你收到一個HTTP請求時,控制器(處理請求的代碼)必須儘可能快地回覆,但要做到這一點的方法是優化請求處理(例如,不要做操作處理http請求需要很長時間)。 如果你的處理時間很快,但從客戶的角度來看,服務器沒有響應,那麼你應該考慮分發你的應用程序(把你的服務器的許多實例放在負載平衡器後面)

相關問題