TL; DR
Что бы вы ни делали, единственный способ получить true
после вызова isOutputShutdown
это прежде, чем позвонить shutdownOutput
. Независимо от состояния Socket
. Выход действительно нужно закрыть непосредственно для того, чтобы метод возвращал true, а не просто закрывался по наследству.
Лучший способ решить эту проблему, чтобы посмотреть на исходный код;)
Пусть для начала поиска метода isOutputShutdown в java.net.Socket
:
public boolean isOutputShutdown() {
return shutOut;
}
Это просто сбруя, хорошо тогда пусть поиск shutOut
. Затем мы заметили, что установлено значение истинно только при вызове метода shutdownOutput
(что логично)
public void shutdownOutput() throws IOException
{
if (isClosed())
throw new SocketException("Socket is closed");
if (!isConnected())
throw new SocketException("Socket is not connected");
if (isOutputShutdown())
throw new SocketException("Socket output is already shutdown");
getImpl().shutdownOutput();
shutOut = true;
}
Заметьте здесь, что мы бросаем SocketException
если сокет закрыт, который до сих пор, подтверждают свою мысль, что закрытие Socket
также закрывает поток. Теперь давайте посмотрим на getImpl
, чтобы найти то, что он ссылается, и проверить метод shutdownOutput
с его ссылкой.
SocketImpl getImpl() throws SocketException {
if (!created)
createImpl(true);
return impl;
}
Javadoc метода определения, что она возвращает SocketImpl
, подключенный к этому разъему. При необходимости создайте его, но я сомневаюсь, что это немаловажно для нашей отладки. SocketImpl
- это просто абстрактный класс, и мы должны найти, какая реализация действительно переопределяет метод shutdownOutput
.
Теперь мы можем найти, что реализация использует завод, чтобы получить instance
factory.createSocketImpl()
Итак, давайте посмотрим на SocketImplFactory
. Ну класс - это интерфейс с одной строкой SocketImpl createSocketImpl();
. Тогда как представлен пример SicketImpl
, где действительно определен метод shutdownOutput
?
Давайте посмотрим на AbstractPlainSocketImpl
(создание сокета по умолчанию), которое расширяет наш SocketImpl
. Это указано в javadoc в верхней части г-на Стивена Б. Бирна, что это реализация сокета по умолчанию. Итак, я думаю, что отсюда мы должны иметь возможность получить представление о том, что делает shutdownOutput
.
/**
* Shutdown read-half of the socket connection;
*/
protected void shutdownInput() throws IOException {
if (fd != null) {
socketShutdown(SHUT_RD);
if (socketInputStream != null) {
socketInputStream.setEOF(true);
}
shut_rd = true;
}
}
/**
* Shutdown write-half of the socket connection;
*/
protected void shutdownOutput() throws IOException {
if (fd != null) {
socketShutdown(SHUT_WR);
shut_wr = true;
}
}
Интересно, не так ли? Ради нашей отладки, давайте рассмотрим, что fd
не является нулевым в нашем случае и перейдите непосредственно к socketShutdown
.
Но подождите! Что такое SHUT_WR?
Хороший вопрос, как указано в комментарии @EJP, они являются давней частью API-интерфейсов Berkeley Sockets. Они просто указать, как поступить (0 для чтения 1 для записи)
public final static int SHUT_RD = 0;
public final static int SHUT_WR = 1;
Теперь вернемся к socketShutdown
,
abstract void socketShutdown(int howto)
throws IOException;
Еще раз, какая жалость, я учил нас было это ...
Итак, давайте перейдем в класс PlainSocketImpl
, который расширяет AbstractPlainSocketImpl
.
native void socketShutdown(int howto) throws IOException;
Мы можем найти исходный код из java.net.PlainSocketImpl.c
here. Теперь давайте посмотрим на код нашего метода
Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
jint howto)
{
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
jint fd;
/*
* WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
* -1 already?
*/
if (IS_NULL(fdObj)) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"socket already closed");
return;
} else {
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
}
JVM_SocketShutdown(fd, howto);
}
Теперь я думаю, что у вас есть довольно хорошее представление о том, как метод действительно перейти закрыть поток.
, что означает "завершение работы" для OutputStream или InputStream
Но почему isOutputShutdown
возвращение ложным, а isClosed
возвращение правда?
Ну учитывая shutOut
логическое значение устанавливается истина только в конце метода shutdownOutput
public void shutdownOutput() throws IOException
{
if (isClosed())
throw new SocketException("Socket is closed");
if (!isConnected())
throw new SocketException("Socket is not connected");
if (isOutputShutdown())
throw new SocketException("Socket output is already shutdown");
getImpl().shutdownOutput();
shutOut = true;
}
, что означает, что закрытие Socket
по умолчанию не устанавливает, что логическое значение для true
. Но даже если метод возвращает false, он фактически закрыт, поскольку он не может быть открыт, если Socket
, основанный на Stream
, закрыт.
Я считаю, вы имеете в виду isOutputShutdown? –
Спасибо @ Jean-François Savard - я редактировал вопрос, чтобы изменить «isInputStreamShutdown» и «isOutputStreamShutdown» на правильные имена методов в этих двух местах. – DigSigBlake