当前位置: 首页 > 知识库问答 >
问题:

为什么socket.is输出关闭()返回false即使套接字是关闭的?

海叶秋
2023-03-14

JavaSocket API告诉我,关闭一个套接字也会关闭套接字的InputStreamOutputStream

Socket API Javadoc和Input/OutputStream API info都没有定义(我还没有找到它)对于OutputStreamInputStream来说,“关机”到底意味着什么,但我一直假设关闭会使它们进入“关机”状态。

然而,在我成功调用客户端套接字的close()方法(调用isClosed()返回true)之后,如果我调用该套接字的isInputShutdown()isOutputShutdown()方法,结果是false

我确信在调用套接字的close()时,两个流都没有缓冲未读/未发送的数据。

我假设我不明白“关机”对套接字的输入/输出流和/或关机发生时意味着什么。

共有3个答案

钱均
2023-03-14

shutdownOutput()导致在任何挂起数据之后发送FIN,对等方将其视为流的结束。

如果您调用了Shutdown Output()isOutputShutdown()将返回true。在所有其他情况下,无论套接字或连接的其他状态如何,它都返回false。

同样适用于:

  • Shutdown输入()isInputShutdown()
  • 关闭()isClose()
  • 连接()或构造一个新的Socket(...)与参数,和isConnect()

除非应用程序调用相关的API,否则这些API都不会神奇地改变状态。唯一的例外是isBound(),如果调用bind()、或connect()、或构造一个新套接字(…),则会出现这种情况 带有参数,或通过ServerSocket获取参数。接受()

它们都不会根据对等端对连接的操作而改变状态。具体来说,isCloded()并不意味着对等端关闭了连接。这意味着您关闭了这个套接字。

柯波娃
2023-03-14

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

让我们来看一下扩展了我们的SocketImplAbstractPlainSocketImpl(默认套接字创建),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被关闭,它就无法打开。

司空坚
2023-03-14

即使在调用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类。