TCP从客户端检测断开的服务器

时间:2014-04-07 10:37:26

标签: java tcp stream

我正在用Java编写一个简单的TCP客户端/服务器程序对,如果客户端在10秒内没有发送任何内容,服务器必须断开连接。 socket.setSoTimeout()得到了我,服务器断开连接就好了。问题是 - 如何让客户端确定服务器是否已关闭?目前我正在使用DataOutputStream写入服务器,而SO上的一些答案表明写入一个封闭的套接字会抛出IOException,但这不会发生。

我应该使用哪种编写器对象向服务器发送任意字节块,这会抛出异常或以其他方式指示连接已远程关闭?

编辑:这是客户端代码。这是一个测试函数,它从文件系统中读取一个文件并将其发送到服务器。它以块的形式发送它,并在每个块之间暂停一段时间。

public static void sendFileWithTimeout(String file, String address, int dataPacketSize, int timeout) {
    Socket connectionToServer = null;
    DataOutputStream outStream = null;
    FileInputStream inStream = null;
    try {
        connectionToServer = new Socket(address, 2233);

        outStream = new DataOutputStream(connectionToServer.getOutputStream());

        Path fileObject = Paths.get(file);

        outStream.writeUTF(fileObject.getFileName().toString());

        byte[] data = new byte[dataPacketSize];

        inStream = new FileInputStream(fileObject.toFile());
        boolean fileFinished = false;
        while (!fileFinished) {
            int bytesRead = inStream.read(data);
            if (bytesRead == -1) {
                fileFinished = true;
            } else {
                outStream.write(data, 0, bytesRead);
                System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + bytesRead + " bytes.");
                Thread.sleep(timeout);
            }
        }

    } catch (IOException | InterruptedException e) {
        System.out.println("Something something.");
        throw new RuntimeException("Problem sending data to server.", e);
    } finally {
        TCPUtil.silentCloseObject(inStream);
        TCPUtil.silentCloseObject(outStream);
        TCPUtil.silentCloseObject(connectionToServer);
    }
}

我希望outStream.write在尝试写入已关闭的服务器时抛出IOException,但什么都没有。

3 个答案:

答案 0 :(得分:1)

  

我希望outStream.write在尝试写入已关闭的服务器时抛出IOException,但没有。

由于套接字发送缓冲区,它不会第一次这样做。如果你继续写,它最终会抛出一个IOException:'connection reset'。如果您没有数据可以达到这一点,您将永远不会发现对等方已关闭。

答案 1 :(得分:-1)

记住ServerSocket.setSoTimeout()与客户端的同名功能不同。

对于服务器,如果超时超时,此函数仅抛出SocketTimeoutException以捕获它,但服务器套接字仍然存在。

对于客户,setSoTimeout()与“超时”有关。用于流阅读。

在您的情况下,您必须在捕获SocketTimeoutException =>后显示关闭已连接套接字的服务器代码确保服务器使用指定的客户端关闭关联的套接字。 如果已完成,请在客户端,代码行:

throw new RuntimeException("Problem sending data to server.", e);

将被召唤。

<强> [更新]

我注意到您声明要将服务器端接受的套接字的超时设置为 10秒(= 10,000毫秒);在那个时期,您的客户完成了所有文件发送?如果确实如此,那就不会发生异常。

<强> [推荐]

用于探测,只需注释掉您要读取文件内容的代码以发送到服务器,并尝试将几行写入替换为输出流:

outStream.writeUTF("ONE");
outStream.writeUTF("TWO");
outStream.writeUTF("TREE");

然后你可以得出结论。

答案 2 :(得分:-1)

我认为你需要在写完outStream.flush()之后刷新关闭你的流。 outStream.close(); inStream.close();