Вам не нужно ничего записывать в сокет как таковой, но если вы закроете его сразу же, он сгенерирует предупреждение close_notify
(хотя это и называется «предупреждение», это часть обычного способа закрытия Сокет TLS / SSL).
Кроме того, сокеты SSL / TLS спроектированы так, чтобы вести себя «почти», как обычные сокеты TCP, но есть детали, где они не (и не могут) из-за того, как работает SSL / TLS.
В частности, в начале соединения SSL / TLS происходит рукопожатие SSL / TLS, которое включает в себя несколько операций чтения / записи с каждой стороны перед отправкой любых данных приложения.
Документация для SSLSocket гласит:
Начальное рукопожатие на этом
соединение может быть инициировано в одном из
три способа:
- вызов
startHandshake
, который явно начинает рукопожатие, или
- любая попытка чтения или записи данных приложения на этом сокете вызывает неявное рукопожатие, или
- вызов
getSession
пытается установить сеанс, если в данный момент его нет
действительный сеанс и неявный
рукопожатие сделано.
По сути, getInputStream().read()
клиентом в вашем примере инициирует рукопожатие, в результате чего сервер продолжает работу с accept()
и выполняет рукопожатие на его стороне . Однако, так как вы закрываете его (обычно, но сразу) на стороне сервера, вы даже не оставляете время для завершения рукопожатия. Следовательно, close_notify
отправляется во время рукопожатия, что вызывает исключение, которое вы получаете. Если бы вы пытались читать или писать со стороны сервера, рукопожатие, по крайней мере, было бы завершено.
РЕДАКТИРОВАТЬ : После комментария @ EJP я должен уточнить, что я имел в виду:
createSocket("localhost", 1443)
на стороне клиента устанавливает соединение, и сервер принимает его через accept()
.
getInputStream().read()
на стороне клиента заставляет его инициировать рукопожатие. Таким образом, он отправляет на сервер сообщение ClientHello
TLS.
- Поскольку сервер использует
close()
сразу после принятия сокета, он отправляет предупреждение close_notify
. Поскольку сервер не начал чтение / запись, он не начал рукопожатие (и, следовательно, не завершает его).
Обратите внимание, что цель ServerSocket.accept()
, которую реализует SSLServerSocket
, состоит в том, чтобы создать SSLSocket
, не обязательно что-либо делать с ним. SSLServerSocket
настраивает его, но продолжение рукопожатия выходит за рамки. С одной стороны, это может звучать так, что SSLSocket
ведет себя более прозрачно, как обычный TCP-сокет; с другой стороны, это будет означать чтение из основного потока TCP, поэтому у него будут побочные эффекты.
Я не пробовал, но SSLSocket
, созданный SSLServerSocket
, все еще может быть настроен в клиентском сокете . В конце концов, как гласит RFC 2246 :
"client: прикладная сущность, которая инициирует соединение TLS с сервером. Это может означать или не означать, что клиент инициировал базовое транспортное соединение." Это определенно будет иметь последствия в отношении прозрачности и когда делать рукопожатие с точки зрения API.
(Написание API для сокетов SSL / TLS, которое сопоставляется с API обычных сокетов TCP, является непростым делом, и Java не делает для этого слишком плохую работу. Настоящее «удовольствие» начинается с асинхронного TLS с использованием * Каналы 1066 * и NIO. Еще лучше, если учесть, что любая из сторон может инициировать новое рукопожатие в любое время: последствия для уровня выше не определены в отношении TLS, что может привести к неловким проблемам .)