2015-02-12 2 views
4

API Java Socket API говорит мне, что закрытие сокета также закрывает InputStream и OutputStream сокета.Почему socket.isOutputShutdown() возвращает false, даже если сокет закрыт?

Ни гнездо API Javadoc, ни информация ввода/OutputStream API не определяет (я не нашел его еще) именно то, что «выключение» означает для OutputStream или InputStream, но я предполагаю, что закрытие либо ставит их в "shutdown" состояние.

Однако, после того, как я вызываю метод close() моего клиента сокета успешно (вызова isClosed() возвращается true), если я затем вызвать либо сокет в isInputShutdown() или isOutputShutdown() метод, результатом является false.

Я уверен, что ни один поток не имеет непрочитанных/неотправленных данных, буферизованных в то время, когда вызывается Socket's close().

Я предполагаю, что я не понимаю, что означает «выключение» означает входные/выходные потоки сокета и/или при завершении работы.

+1

Я считаю, вы имеете в виду isOutputShutdown? –

+0

Спасибо @ Jean-François Savard - я редактировал вопрос, чтобы изменить «isInputStreamShutdown» и «isOutputStreamShutdown» на правильные имена методов в этих двух местах. – DigSigBlake

ответ

3

Даже после вызова socket.getOutputStream(). Близкий(), в socket.isOutputShutdown() вызов возвратит ложь. Кроме того, если разъем еще не подключен, то socket.isOutputShutdown() вернет false.

invokation из socket.isOutputShutdown()ТОЛЬКО возвращает истинных, когда socket.shutdownOutput() ранее был вызван. Вы правы, что документ немного вводит в заблуждение в этой точке.

В this thread, использование socket.shutdownOutput() объясняется более подробно. В основном вы можете использовать его для создания полузакрытого соединения (что означает, что ваш конец решил не отправлять больше данных, но готов слушать больше данных с другого конца).

1

shutdownOutput() вызывает отправку FIN после любых ожидающих данных, которые peer увидит как конец потока.

Если вы назвалиshutdownOutput(), isOutputShutdown() вернется true. Во всех остальных случаях и независимо от другого состояния сокета или соединения, он возвращает ложь.

Аналогично для:

  • shutdownInput() и isInputShutdown()
  • close() и isClosed()
  • connect() или построить new Socket(...) с аргументами и isConnected().

Ни один из этих API не изменяет состояние, если ваше приложение не вызывает связанный API.Единственным исключением, что является isBound(), которая может стать правдой, если вы звоните bind() или connect(), или построить new Socket(...) с аргументами, или получить один через ServerSocket.accept().

И никто из них не меняет свое состояние в зависимости от того, что peer делает для подключение. В частности, isClosed() не означает, что сверстник закрыл соединение. Это значит вы закрыто этот разъем.

2

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.chere. Теперь давайте посмотрим на код нашего метода

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, закрыт.

+0

'SHUT_RD' и' SHUT_WR' являются давней частью API-интерфейсов Berkeley Sockets. – EJP

+0

@EJP Спасибо за точность, отредактирован. –

+0

@ Jean-François Savard (и все остальные) Большое спасибо за то, что вы разбираете код, создающий поведение. Я бы не сказал, что эта часть государственной машины Socket-коммуникаций хорошо реализована, но теперь я понимаю ее лучше. – DigSigBlake

Смежные вопросы