JavaSocket API告诉我,关闭一个套接字也会关闭套接字的InputStream
和OutputStream
。
Socket API Javadoc和Input/OutputStream API info都没有定义(我还没有找到它)对于OutputStream
或InputStream
来说,“关机”到底意味着什么,但我一直假设关闭会使它们进入“关机”状态。
然而,在我成功调用客户端套接字的close()
方法(调用isClosed()
返回true
)之后,如果我调用该套接字的isInputShutdown()
或isOutputShutdown()
方法,结果是false
。
我确信在调用套接字的close()
时,两个流都没有缓冲未读/未发送的数据。
我假设我不明白“关机”对套接字的输入/输出流和/或关机发生时意味着什么。
shutdownOutput()
导致在任何挂起数据之后发送FIN,对等方将其视为流的结束。
如果您调用了Shutdown Output()
,isOutputShutdown()
将返回true。
在所有其他情况下,无论套接字或连接的其他状态如何,它都返回false。
同样适用于:
Shutdown输入()
和isInputShutdown()
关闭()
和isClose()
连接()
或构造一个新的Socket(...)与参数,和isConnect()
。除非应用程序调用相关的API,否则这些API都不会神奇地改变状态。唯一的例外是isBound()
,如果调用bind()
、或connect()
、或构造一个新套接字(…),则会出现这种情况
带有参数,或通过
ServerSocket获取参数。接受()
它们都不会根据对等端对连接的操作而改变状态。具体来说,
isCloded()
并不意味着对等端关闭了连接。这意味着您关闭了这个套接字。
TL; DR
无论您做什么,在调用isOutputShutdown
之后获得true
的唯一方法是在调用之前调用shutdownOutput
。无论套接字的状态如何
。要使方法返回true,确实需要直接关闭输出,而不仅仅是通过继承关闭。
解决这个问题的最佳方法是查看源代码;)
让我们从在java中搜索isOutputShutdown方法开始。网插座
:
public boolean isOutputShutdown() {
return shutOut;
}
它只是一个访问器,好的,那么让我们搜索ShutOut
。然后我们会注意到,只有在调用方法的时候,该值才被设置为true。
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是关闭的,请确认您的想法,关闭socket
也会关闭它。现在让我们看看getImpl
,找到它引用了什么,并从它的引用中检查方法shutdownOutput
。
SocketImpl getImpl() throws SocketException {
if (!created)
createImpl(true);
return impl;
}
该方法的javadoc指定返回附加到此套接字的SocketImpl
。如果有必要的话创建它,但我怀疑它在我们的调试中是相当重要的SocketImpl
只是一个抽象类,我们必须找到哪个实现真正覆盖了shutdownOutput
方法。
现在我们可以发现,实现使用工厂来获取实例
factory.createSocketImpl()
让我们来看一下SocketImplFactory
。这个类是一个带有一行SocketImpl createSocketImpl()的接口
。那么,
SicketImpl
的实例是如何给出的,在哪里真正定义了方法shutdownOutput
?
让我们来看一下扩展了我们的
SocketImpl
的AbstractPlainSocketImpl
(默认套接字创建),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在我们的情况下不为NULL,直接转到<代码> SoCutSuxOut/<代码>。
但是等等!什么是闭嘴?
好问题,正如@EJP在评论中所说的,它们是Berkeley Sockets 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;
又一次,真遗憾,我想我们已经。。。
让我们进入
PlainSocketImpl
类,它扩展了AbstractPlainSocketImpl
。
native void socketShutdown(int howto) throws IOException;
我们可以在这里找到java.net.PlainSocketImp. c
的源代码。现在让我们看看我们方法的代码
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
返回false,而isClosed
返回true?
考虑到关闭
布尔值仅在方法关闭输出
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,它实际上也是关闭的,因为如果Stream
所基于的Socket
被关闭,它就无法打开。
即使在调用socket.getOutputStream(). off()后,socket.isOutputShutdown()调用也将返回false。此外,如果套接字尚未连接,socket.isOutputShutdown()将返回false。
当以前调用socket.isOutputShutdown()时,socket.shutdown输出()的调用返回true。您是对的,文档在这一点上有点误导。
在这个线程中,socket.shutdown输出()的使用得到了更详细的解释。基本上,您可以使用它来创建一个半封闭的连接(意味着您的端决心不再发送数据,但愿意监听另一端的更多数据)。
我包一个插座。通过InputStreamReader获取getInputStream(),并包装一个套接字。getOutputStream()由OutputStreamWriter创建。我发现这些流的关闭顺序真的很重要,但我不知道为什么。 如果我先关闭outputStream,然后再关闭inputStream,它可以正常工作: 但是,如果我先关闭inputStream,然后再关闭outputStr
问题内容: 有人可以解释一下Java套接字中的以下行为: 总体思路是这样的: 打开套接字,获取I / O流。 写请求,关闭流 读取响应,关闭流 关闭插座。 这是我的问题。 如果我将a 用于输出,然后将其关闭,则它将关闭整个套接字,并且随后的读取操作将失败。 相反,如果我直接使用套接字的方法,它将正确关闭输出流通道,同时使套接字保持活动状态。 为什么关闭对象会使整个插槽都掉下来? 问题答案: 这可能
问题内容: 我有一个使用简单套接字在两个系统之间传递某些字符的应用程序。我的Java应用程序作为服务器运行。我建立了良好的连接,甚至传递了一条消息。但是,发送完一条消息后,我的连接关闭。 从我可以看出来的好像是在关闭时,套接字本身正在关闭吗?!这很不好,因为我有多个要在同一连接上发送的消息。 我吃饱了吗?如何在Java中维护此连接? 问题答案: 是的,关闭任何作家/读者将关闭他们包装的所有其他作家
问题内容: 我有服务器和客户端。我的服务器接受所有连接并返回到客户端字符串。但是当我尝试发送更多行时,它崩溃了 这是我的服务器代码: 这是我的客户代码: 问题答案: 来自in中的javadoc: 关闭返回将关闭关联的套接字。 另外,关闭(和所有其他打印机/写入器)也将关闭其基础流。因此,您可以通过关闭(in ),然后尝试写入已关闭的套接字来关闭您的套接字。 要解决此问题,请不要关闭。垃圾收集将为您
问题内容: 什么是JavaScript中的闭包和回调?我还没有找到很好的解释。 问题答案: 回调 是一个更简单的概念。回调基本上是一个函数接受另一个函数作为参数的地方。在执行过程中的某个时刻,被调用函数将执行作为参数传递的函数,这是一个回调。回调实际上经常是作为异步事件发生的,在这种情况下,被调用的函数可能会在未执行回调的情况下返回,这可能会在以后发生。这是一个常见的示例(基于浏览器): 在这里,
我正在为客户机发送对象到服务器,在服务器端修改该对象,并将其重新发送到客户机。将对象从客户机发送到服务器很好,它工作正常,但当我将对象发送回来时,它给出了异常,Socket关闭。这里是代码。IntString和ParentObj是我要发送对象的类。 服务器类 用于发送和接收对象的Send_recv类。