TL; DR
不管你做什么,要求isOutputShutdown
后得到true
的唯一方法就是之前调用shutdownOutput
。不管Socket
的状态如何。输出真的需要直接关闭,方法返回true,而不仅仅是通过继承关闭。
解决这个是看源代码的最佳方式;)
让在java.net.Socket
搜索方法isOutputShutdown开始:
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;
}
注意这里只当值设置为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
,它在Steven B. Byrne先生的顶层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在评论中指出的,它们是Berkeley套接字API的一个长期部分。他们只需指定如何进行(0读,1写入)
public final static int SHUT_RD = 0;
public final static int SHUT_WR = 1;
现在回到socketShutdown
,
abstract void socketShutdown(int howto)
throws IOException;
再次,真可惜,我因子评分我们有它...
因此,让我们继续AbstractPlainSocketImpl
的课PlainSocketImpl
。
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
结束设置为true。但即使该方法返回false,它实际上也会关闭,因为如果Socket
Stream
基于关闭,它将无法打开。
我相信你的意思是isOutputShutdown? – 2015-02-12 00:42:59
谢谢@ Jean-FrançoisSavard - 我编辑了这个问题,将“isInputStreamShutdown”和“isOutputStreamShutdown”更改为这两个地方的正确方法名称。 – DigSigBlake 2015-02-12 01:00:25