Многопоточный веб-сервер Java - не получает несколько запросов GET - PullRequest
1 голос
/ 06 февраля 2011

У меня запущен очень простой многопоточный веб-сервер, он может принимать все запросы 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)
        {

        }
}

Ответы [ 2 ]

3 голосов
/ 06 февраля 2011

Во-первых, комментарий @ skaffman точный. Вы не должны ловить и игнорировать исключения, как сейчас делает ваш код. В общем, это ужасная практика. В этом случае вы вполне могли бы выбросить улики, которые бы указывали на реальную проблему.

Во-вторых, я думаю, что вы, возможно, страдаете от неправильного понимания того, на что способен сервер. Независимо от того, как вы это реализуете, сервер может обрабатывать только определенное количество запросов в секунду. Если вы добавите к нему больше запросов, некоторые из них будут отброшены.


Что я подозреваю, так это то, что вы отправляете слишком много запросов за короткий промежуток времени и переполняете буфер запросов операционной системы.

Когда ваш код привязывается к сокету сервера, операционная система устанавливает очередь запросов для хранения входящих запросов на привязанном IP-адресе / порте. Эта очередь имеет конечный размер, и, если очередь заполнена при поступлении нового запроса, операционная система отбросит запросы. Это означает, что если ваше приложение не может accept запросов достаточно быстро, некоторые из них будут отброшены.

Что вы можете с этим поделать?

  • Существует перегрузка ServerSocket.bind(...), позволяющая указать backlog запросов, которые будут удерживаться в очереди уровня ОС. Вы можете использовать это ... или использовать большее отставание.
  • Вы можете изменить свой основной цикл, чтобы быстрее получать запросы из очереди. Одна проблема с вашим текущим кодом заключается в том, что вы создаете новую тему для каждого запроса. Создание потоков стоит дорого, и вы можете уменьшить стоимость, используя пул потоков для переработки потоков, использованных для предыдущих запросов.

ПРЕДОСТЕРЕЖЕНИЯ

Вы должны быть немного осторожны. Весьма вероятно, что вы можете изменить свое приложение, чтобы принимать (не отбрасывать) больше запросов в краткосрочной перспективе. Но в долгосрочной перспективе вы должны принимать запросы только настолько быстро, насколько это возможно. Если он принимает их быстрее, чем вы можете их обработать, может произойти ряд плохих вещей:

  • Вы будете использовать много памяти всеми потоками, пытающимися обрабатывать запросы. Это увеличит нагрузку на процессор различными способами.
  • Вы можете повысить конкуренцию за внутренние структуры данных Java, базы данных и т. Д., Стремясь снизить пропускную способность.
  • Вы увеличите время, необходимое для обработки и ответа на отдельные запросы GET. Если задержка слишком велика, клиент может приостановить запрос ... и отправить его снова. Если это произойдет, работа, выполненная сервером, будет потрачена впустую.

Чтобы защититься от этого, на самом деле лучше НЕ принимать столько запросов, сколько сможете. Вместо этого используйте ограниченный пул потоков и настройте размер пула (и т. Д.) Для оптимизации пропускной способности, сохраняя время для обработки отдельных запросов в разумных пределах.

2 голосов
/ 08 февраля 2011

Я действительно обнаружил, что проблема была в следующем:

  static Socket clientSocket = null;

Как только я снял статику, теперь она отлично работает.

...