BufferedInputStream挂起(未到达文件末尾)

时间:2015-03-29 02:22:09

标签: java sockets

我有Java SSL / TLS服务器和客户端套接字。我的客户端只是将文件发送到服务器,服务器接收它。这是我的代码:

我的客户端方法:

static boolean writeData(BufferedOutputStream bos, File data) {
    FileInputStream fis = new FileInputStream(data);
    BufferedInputStream bis = new BufferdInputStream(fis);

    byte[] bytes = new byte[512];
    int count = 0;
    while ((count = bis.read(bytes, 0, bytes.length)) > 0) {
        System.out.println("Sending file...");
        bos.write(dataByte, 0, count);
        System.out.println(count);
    }
    bos.flush();
    System.out.println("File Sent");
}

我的服务器方法:

static boolean receiveData(BufferedInputStream bis, File data) {

    byte[] bytes = new byte[512];
    int count = 0;
    while ((count = bis.read(bytes, 0, bytes.length)) > 0) {
        System.out.println("Receiving file...");
        // Do something..
        System.out.println(count);
    }
    bos.flush();
    System.out.println("File Received");
}

问题是,服务器在while循环内挂起..它永远不会到达“File Received”消息。

即使文件很小,bis.read()方法也不会因为某种原因在文件末尾返回-1。我测试了文件大小为16字节的方法,输出如下:

客户终端:

> Sending file...
> 16
> File Sent

服务器终端:

> Receiving file...
> 16

正如您所看到的,服务器永远不会到达“文件已接收”消息,并且即使在到达流末尾之后也会在循环内挂起..有人可以猜出原因吗?

由于

1 个答案:

答案 0 :(得分:2)

您的服务器从未检测到该文件已被发送,因为它会检查您是否已关闭另一端的连接(这是您接收-1字节读取的唯一原因)。

但你永远不会关闭连接,只能冲洗它。

bos.flush()替换为bos.close()方法中的writeData,它应该有效。


如果您不想关闭连接,因为您想要更多地使用它,您必须添加某种协议,因为没有默认方式去做。

您可以做的一件事,就是实现此目的的一种更简单的方法,就是在文件之前将文件的长度发送为32位或64位整数。 / p>

然后服务器知道它应该读取多少字节才能认为文件已完全发送。


如果你不知道文件的长度,有很多选择。我不确定是否就最有效的方法达成共识,但鉴于许多协议采用不同的方法,我不认为存在。

这些只是一些建议,您可以调整。

  1. 在任何数据之前,您将要发送的数据长度作为32位(带符号)整数发送。因此,文件将作为多个数据发送。发送负数意味着前一部分是最后一部分,文件已结束。 (如果您需要发送一个大于您可以在带符号的32位整数中表示的最大值的片段,则需要将其分成几个部分。)
  2. 您会想到一个随机数,其长度足够长(类似于16个字节或32个字节),它将永远不会出现在您的数据中。您在文件之前发送该号码,文件完成后,再次发送该号码以指示该事件。这类似于MIME多部分编码。
  3. 您需要一个字节或多个字节来指示文件是否已结束(如0xFF)。但是为了确保您仍然可以合法地将0xFF作为文件的一部分发送,您添加0xFF 0xFF表示文件已结束的规则,但0xFF 0x00表示"只是文字0xFF"在文件中。
  4. 还有很多方法可以做到。