JEP draft: HTTP over Unix Domain Sockets
HTTP через сокеты Unix domain
| Ответственный | Michael McMahon |
| Тип | Feature |
| Область | JDK |
| Статус | Submitted |
| Компонент | core-libs / java.net |
| Обсуждение | net dash dev at openjdk dot org |
| Трудоёмкость | S |
| Длительность | M |
| Рецензенты | Alan Bateman |
| Создан | 2026/02/12 15:35 |
| Обновлён | 2026/09/21 16:12 |
| Задача | 8377806 |
Аннотация
Добавить поддержку сокетов Unix domain (AF_UNIX) в API java.net.http и jdk.httpserver, а также в инструмент командной строки jwebserver в JDK.
Цели
- Распространить существующую поддержку сокетов Unix domain на HTTP-клиент и HTTP-сервер для приложений, которые обмениваются данными в пределах одного хоста или между контейнерами на одном хосте, минуя сетевой стек TCP/IP.
- Поддерживать обе схемы:
httpиhttps. - Добавить в инструмент
jwebserverновые параметры командной строки, чтобы он мог обслуживать HTTP-запросы через сокет Unix domain.
Что не является целью
- Добавление поддержки в устаревший API HttpURLConnection не является целью
- Поддержка QUIC и HTTP/3 (как на клиенте, так и на сервере) не является целью
- Добавление поддержки новых версий протокола HTTP на сервере (сверх HTTP/1.1) не является целью
- Поддержка сокетов Unix domain через специальные схемы URL или иную структуру, навязываемую URL, не является целью
Мотивация
Сокеты Unix domain используются для межпроцессного взаимодействия (IPC) на одном хосте. Почти во всём они похожи на сокеты TCP/IP, за исключением того, что адресуются путями в файловой системе, а не адресами Internet Protocol (IP) и номерами портов. Для локального доступа по HTTP, когда клиент и сервер находятся в одной системе, сокеты Unix domain и безопаснее, и эффективнее, чем соединения TCP/IP через loopback-интерфейс.
-
Сокеты Unix domain предназначены исключительно для взаимодействия между процессами в одной системе. Приложения, которые не должны принимать удалённые соединения, могут повысить безопасность, используя сокеты Unix domain.
-
Кроме того, сокеты Unix domain защищены средствами контроля доступа на уровне файловой системы, которые обеспечивает операционная система.
-
У сокетов Unix domain соединение устанавливается быстрее, а пропускная способность при передаче данных выше, чем у соединений TCP/IP через loopback-интерфейс.
-
Сокеты Unix domain могут быть лучшим решением, чем сокеты TCP/IP, в контейнерных средах, где требуется взаимодействие между контейнерами в одной системе. Этого можно добиться с помощью сокетов, расположенных в общих томах.
Сокеты Unix domain давно доступны на большинстве Unix-платформ, а в Windows поддерживаются начиная с Windows 10 и Windows Server 2019.
Приложения, развёрнутые в контейнерах, получили бы большую выгоду, если бы API HTTP-клиента и API сервера в локальной среде IPC могли использовать сокеты Unix domain, поскольку в таких локальных средах они безопаснее и производительнее.
Описание
API в модулях java.net.http и jdk.httpserver будут расширены, чтобы можно было указать:
- Путь в файловой системе (представляющий сокет Unix domain) в качестве локального адреса конечной точки сервера
- Путь в файловой системе (представляющий сокет Unix domain) в качестве удалённого адреса для конкретного HTTP-запроса клиента
Эти параметры будут полностью независимы от URI запросов, в том числе от любого доменного имени, указанного в URI запроса.
Аргументы командной строки инструмента jwebserver будут расширены, чтобы можно было выполнять привязку к адресу сокета Unix domain.
Изменения в HTTP-клиенте
В модуле java.net.http интерфейс java.net.http.HttpOption будет расширен классом ALT_TRANSPORT_ADDRESS, у которого есть параметр типа java.net.SocketAddress, но который изначально поддерживает только UnixDomainSocketAddress. Пользователи смогут передавать адрес целевого сокета Unix domain с помощью HttpRequest.Builder::setOption:
С помощью HttpRequest::setOption адрес сокета Unix domain можно будет указывать полностью независимо от URI запросов, в том числе от любого доменного имени, указанного в URI запроса.
HTTP/3 не будет поддерживаться через сокеты Unix domain. Если предпочтительной версией с помощью методов HttpClient.Builder::version и HttpRequest.Builder::version задан HTTP/3, запрос будет понижен до HTTP/2 или HTTP/1.1. Аналогично параметр HttpOption.H3_DISCOVERY, если он указан, будет проигнорирован.
Обычно у клиентских сокетов Unix domain (в отличие от сокетов TCP/IP) локальные адреса остаются непривязанными. Этот подход будет применён и в HttpClient. Привязка клиентских соединений к конкретным локальным адресам сокетов Unix domain поддерживаться не будет.
Изменения в HTTP-сервере
В модуль jdk.httpserver будут добавлены новые варианты методов create и bind классов com.sun.net.HttpServer и com.sun.net.HttpsServer, которые принимают java.net.SocketAddress вместо java.net.InetSocketAddress. Так пользователи фактически смогут передавать как java.net.InetSocketAddress, так и java.net.UnixDomainSocketAddress при создании или привязке экземпляров HttpServer или HttpsServer:
Файл по пути, на который указывает сокет Unix domain, будет создаваться при привязке сервера и удаляться при его завершении. Если файл уже существует, привязка сокета, а следовательно, и запуск сервера завершатся ошибкой.
Для поддержки сокетов Unix domain в HTTP-сервере будут добавлены (или изменены) следующие методы:
- HttpServerProvider::createHttpServer(SocketAddress addr, int backlog)
- HttpServerProvider::createHttpsServer(SocketAddress addr, int backlog)
- HttpServerProvider::supportsSocketAddress()
- HttpServer::create(SocketAddress addr, int backlog) // и другие варианты; изменён
- SimpleFileServer::createFileServer(SocketAddress address, Path rootDirectory, OutputLevel outputLevel) // изменён
Пример HTTP-клиента и HTTP-сервера в двух разных контейнерах
Примеры ниже показывают, как запустить HTTP-клиент и HTTP-сервер в двух разных контейнерах, которые обмениваются данными через сокет Unix domain, хранящийся в общем томе.
Настройка тома, общего для двух контейнеров
Создайте общий том с именем sock
docker volume create sock
Запуск HTTP-сервера в контейнере
В следующем фрагменте HTTP-сервер привязывается к сокету Unix domain по пути /mnt/server.sock:
public class Server {
void main() throws IOException {
var path = Path.of("/mnt/server.sock");
Files.deleteIfExists(path);
var address = UnixDomainSocketAddress.of(path);
var server = HttpServer.create(address, 5);
server.createContext("/", exchange -> {
var responseBody = "Hello world!";
exchange.sendResponseHeaders(200, responseBody.length());
exchange.getResponseBody().write(
responseBody.getBytes(StandardCharsets.ISO_8859_1));
exchange.close();
});
server.start();
System.out.println("Listening at: %s\n", server.getSocketAddress());
}
}
Предположим, что Server.java находится в /tmp на вашей машине для разработки, где также есть образ контейнера JDK 27 с тегом jdk:27. Запустите контейнер, выполняющий Server.java, и используйте общий том для хранения файла сокета Unix domain:
docker run \
--mount "type=bind,src=/tmp/Server.java,dst=/src/Server.java" \
--mount "type=volume,src=sock,dst=/mnt" \
-it jdk:27 java /src/Server.java
HTTP-клиент
В следующем фрагменте HTTP-клиент подключается к серверу, привязанному к сокету Unix domain по пути /mnt/server.sock:
public class Client {
void main() throws IOException, InterruptedException {
try (var client = HttpClient.newHttpClient()) {
var request = HttpRequest.newBuilder()
.uri(URI.create("https://foo.com/uri"))
.setOption(
HttpOption.ALT_TRANSPORT_ADDRESS,
UnixDomainSocketAddress.of("/mnt/server.sock"))
.GET()
.build();
var response = client.send(
request, HttpResponse.BodyHandlers.ofString());
// ...
}
}
}
Предположим, что Client.java находится в /tmp на вашей машине для разработки, где также есть образ контейнера JDK 27 с тегом jdk:27. Запустите контейнер, выполняющий Client.java, и используйте общий том, в котором контейнер с HTTP-сервером уже создал файл сокета Unix domain:
docker run \
--mount "type=bind,src=/tmp/Client.java,dst=/src/Client.java" \
--mount "type=volume,src=sock,dst=/mnt" \
-it jdk:27 java /src/Client.java
Альтернативы
Один из высокоуровневых вопросов проектирования состоял в том, привязывать ли настройку использования сокетов Unix domain к структуре URL (например, через специальные схемы, специальные зарезервированные имена хостов или пути) или использовать отдельный механизм настройки, независимый от любых URL, которые могут использовать приложения.
Обзор существующих библиотек и фреймворков быстро показал, что ни одна из них не добивается этого, навязывая URL определённую структуру, а общепринятый способ — использовать для такой настройки специальные API.
Риски и допущения
Один из возможных рисков в том, что тонкие различия в поведении сокетов TCP/IP и Unix domain повлияют на работу протокола HTTP. Если это произойдёт, может потребоваться учесть это в спецификации API.
Эти различия обсуждаются в записи блога о JEP 380.
Зависимости
Эта работа основана на JEP 380: "Unix domain socket channels", в котором сокеты Unix domain были реализованы в сокетных каналах NIO.