HTTP-сервер, поддерживающий Keep-Alive

Я пытаюсь создать http-сервер на Java, способный обеспечивать постоянные соединения. Я использую класс com.sun.net.httpserver.HttpServer.

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

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

public class httpHandler implements HttpHandler {

private String resp = "<?xml version='1.0'?><root-node></root-node>";

private OutputStream os = null;

public void handle(HttpExchange t) throws IOException {
    System.out.println("Handling message...");
    java.io.InputStream is = t.getRequestBody();

    System.out.println("Got request body. Reading request body...");
    byte[] b = new byte[500];
    is.read(b);
    System.out.println("This is the request: " + new String(b));

    String response = resp;
    Headers header = t.getResponseHeaders();
    header.add("Connection", "Keep-Alive");
    header.add("Keep-Alive", "timeout=14 max=100");
    header.add("Content-Type", "application/soap+xml");
    t.sendResponseHeaders(200, response.length());

    if(os == null) {
        os = t.getResponseBody();
    }

    os.write(response.getBytes());

    System.out.println("Done with exchange. Closing connection");
    os.close();
}

public static void main(String[] args) {
    HttpServer server = null;
    try {
        server = HttpServer.create(new InetSocketAddress(8080), 5);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    server.createContext("/", new httpHandler());
    server.setExecutor(null); // creates a default executor
    System.out.println("Starting server...");
    server.start();
}
}

Клиент не закрывает соединение. Похоже, что сервер закрывает его сразу после обмена. Я попытался удалить строку os.close, но тогда сервер не будет отвечать на второй запрос. Но это тоже не закрывает. У меня есть ощущение, что это связано с выполнением чего-либо в основном коде с объектом server, но я понятия не имею, что. Гугл тоже не особо.

У кого-нибудь есть идеи? Любая помощь приветствуется.

4 ответа

Похоже, проблема в том, что вы не удалили все данные из запроса. Вы должны продолжать делать is.read() пока он не вернет -1, затем закройте его.

Поскольку вы не исчерпали запрос, остались еще байты. Сервер не может просто "перейти" к следующему запросу; это не как диск, а как лента. Сервер должен прочитать (и отбросить) все данные из текущего запроса, прежде чем он сможет достичь следующего запроса.

Без ограничения это может быть использовано для атаки на сервер; таким образом, сервер будет пытаться использовать только предел, который по умолчанию составляет 64 КБ. Вы, вероятно, получаете запрос больше, чем 64K.

Обычно обработчик должен сначала прочитать весь запрос. Иначе откуда он знает, как обслуживать запрос?

А если серьезно, то если запрос не будет обработан первым, может возникнуть тупик. Клиенты, как правило, простые: они пишут запрос, а затем читают ответ. Если сервер пишет ответ до того, как прочитает весь запрос, клиент все еще может писать запрос. Оба пишут друг другу, но ни один не читает. Если буферы заполнены, то мы зашли в тупик, оба блокируются при записи. Обратите внимание, что для write() нет времени ожидания!

Почему вы получаете ResponseBody OutputStream, только если предыдущий был нулевым?

if(os == null) {
    os = t.getResponseBody();
}

Может быть лучше каждый раз получать OutputStream, так как вы не можете быть уверены, что предыдущий идентичен предыдущему Request.

Попробуй позвонить t.close(), сервер ответит

Это клиент отправляет заголовки keep-alive. Если это так, HttpServer не закрывает соединение. Вам не нужно ничего делать с этим.

Другие вопросы по тегам