簡體   English   中英

Java多線程Web服務器-無法接收多個GET請求

[英]Java Multithreaded Web Server - Not recieving multiple GET requests

我有一個非常基礎的多線程Web服務器的啟動,它可以接收所有GET請求,只要它們一次出現即可。

但是,當同時收到多個GET請求時,有時會全部收到,而有時卻丟失了一些。

我通過創建一個帶有多個指向我的網絡服務器的圖像標簽的html頁面並在firefox中打開該頁面來進行測試。 我總是使用shift + refresh。

這是我的代碼,我必須做的是根本錯誤的事情。

public final class WebServer
{
    public static void main(String argv[]) throws Exception
    {
        int port = 6789;

        ServerSocket serverSocket = null;
        try
        {
            serverSocket = new ServerSocket(port);
        }
        catch(IOException e)
        {
            System.err.println("Could not listen on port: " + port);
            System.exit(1);
        }

        while(true)
        {
            try
            {
                Socket clientSocket = serverSocket.accept();
                new Thread(new ServerThread(clientSocket)).start();
            }
            catch(IOException e)
            {

            }
        }
    }
}

public class ServerThread implements Runnable
{
    static Socket clientSocket = null;

    public ServerThread(Socket clientSocket)
    {
        this.clientSocket = clientSocket;
    }

    public void run()
    {
        String headerline = null;
        DataOutputStream out = null;
        BufferedReader in = null;

        int i;

        try
        {
            out = new DataOutputStream(clientSocket.getOutputStream());
            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            while((headerline = in.readLine()).length() != 0)
            {
                System.out.println(headerline);
            }
        }
        catch(Exception e)
        {

        }
}

首先,@ skaffman的評論很明確。 您不應像代碼當前那樣捕獲並忽略異常。 通常,這是一種可怕的做法。 在這種情況下,您很可能會丟掉可以告訴您真正問題是什么的證據。

其次,我認為您可能會誤解服務器的功能。 無論您如何實現,服務器每秒只能處理一定數量的請求。 如果您對它提出的請求更多,則必須丟棄一些請求。


我懷疑正在發生的事情是,您在短時間內發送了太多請求,並且淹沒了操作系統的請求緩沖區。

當您的代碼綁定到服務器套接字時,操作系統將設置一個請求隊列,以將傳入的請求保存在綁定的IP地址/端口上。 該隊列的大小是有限的,如果在收到新請求時隊列已滿,則操作系統將丟棄請求。 這意味着,如果您的應用程序不能足夠快地accept請求,則某些請求將被丟棄。

你能為這個做什么?

  • ServerSocket.bind(...)的重載允許您指定要保存在OS級別隊列中的請求的backlog 您可以使用此...或使用更大的積壓。
  • 您可以更改主循環以更快地從隊列中拉出請求。 當前代碼的一個問題是,您正在為每個請求創建一個新的線程。 創建線程很昂貴,您可以通過使用線程池回收用於先前請求的線程來降低成本。

洞穴

您需要注意一點。 您很有可能可以在短期內修改應用程序以接受(而不是丟棄)更多請求。 但是從長遠來看,您應該只接受盡可能快地接受請求的速度。 如果接受它們的速度超過了處理它們的速度,則可能會發生許多不良情況:

  • 您將在所有試圖處理請求的線程上使用大量內存。 這將以各種方式增加CPU開銷。
  • 您可能會增加對內部Java數據結構,數據庫等的爭用,從而傾向於降低吞吐量。
  • 您將增加處理和回復單個GET請求所需的時間。 如果延遲時間太長,客戶端可能會使請求超時……然后再次發送。 如果發生這種情況,服務器的工作將被浪費。

為了保護自己,實際上最好不要急於接受盡可能多的請求。 相反,請使用有線程池,並調整池大小(等)以優化吞吐率,同時將處理單個請求的時間保持在合理的范圍內。

我實際上發現問題是這樣的:

  static Socket clientSocket = null;

移除靜電后,它現在可以正常使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM