【问题标题】:get number of bytes a DataOutputStream wrapped around Socket.getOutputStream wrote获取包裹在 Socket.getOutputStream 周围的 DataOutputStream 写入的字节数
【发布时间】:2016-02-23 20:31:35
【问题描述】:

我有一个服务器-客户端应用程序并使用 java Sockets API。

服务器会通过调用DataOutputStream的write(bytes[] b)向客户端发送字节,DataOutputStream直接包裹在client.getOutputStream上(这里没有Buffer)。

这是一个文件下载功能并且我将支持简历,我在这里没有使用任何HTTP,我已经实现了我自己的简单协议。

我在 SO 上看到了这些问题:
1-question1.
2-C# question.
3-FileChannel question

第一个没有回答我的问题,我不能将 DataOutputStream 包裹在 ByteArrayOutputStream 周围,因为后者不能包裹在 client.getOutputStream 周围,而且我不知道如何实现我自己的 write(int i) 方法(并且不要不想使用 JNI)。

第二个是 C# 而不是 java(无论如何它都在调用 WIN API,顺便说一句,我是 linux 用户 :))。

第三个是关于 FileChannels 和 HTTP,正如我所说的,我没有使用 HTTP,我使用的是 java Socket 的 API。

那么如何获取实际写入的字节数?

PS(编辑)

通过恢复支持,我的意思是让客户端能够在特定字节处停止下载,然后在一段时间(几分钟、几小时、几天等)之后,他/她可以从它离开的地方继续下载。

【问题讨论】:

  • 对你来说是透明的。一旦你调用socket.read(bytes),它还会返回读取了多少字节。看这个例子:http://stackoverflow.com/a/19863726/3710490
  • @Valijon 我知道socket.read(bytes) 返回读取了多少字节,但socket.write(bytes) 返回无效而不是写入了多少字节,假设客户端决定停止下载,那么服务器如何知道那个?
  • 因为你的连接是TCP,你写的就是你的客户端读的!
  • @Valijon 错了。由于他的套接字发送缓冲区和阅读器的套接字接收缓冲区,作者可能比阅读器领先许多 KB。

标签: java sockets io


【解决方案1】:
  • write(int c)写的byes数为1。

  • write(bye[] buffer) 写入的字节数由buffer.length 给出。

  • write(bye[] buffer, int offset, int length) 写入的字节数由length 给出。

正如它在 Javadoc 中所说的那样。

【讨论】:

  • 如果客户端停止下载(我计划为我的简历提供支持),那么 buffer.length 将不会给出 write(byte[] buffer)
  • @niceman 错了。如果客户端停止下载并且它的接收缓冲区已满并且发送者的发送缓冲区已满,因此发送者在write()中被阻塞并且 客户端关闭套接字,OutputStream.write()抛出 IOException。 在所有其他情况下,写入将完全成功并将所有数据传输出缓冲区。在任何情况下,它都不会在不抛出异常的情况下传输更少并返回。
  • 嗯我想到了,所以我可以在 catch 子句中做我的简历支持,但是如何知道异常是由于客户端还是其他原因(旁注:奇怪的是 read 没有'写时不抛出异常)
  • @niceman 又错了。如果连接已重置,read() 会抛出 IOException。在我看来,你在问一个不同的问题。您需要知道客户端读取了多少数据,这与发送方写入的数据量不同,因为两端都有 TCP 缓冲。知道这一点的唯一方法是客户端在下载协议中告诉您。可能真正的答案是让客户端在它恢复时告诉您从哪里恢复,就像在 HTTP 中一样。我不知道你所说的“我想到那个”是什么意思,因为它并没有阻止你说出这个错误。
  • 承认:我投了反对票,我的问题值得反对,但也有人反对,顺便说一句,我试图禁用我的反对票,但它被锁定了 :)
【解决方案2】:

当你将数据写入字节数组时,也要写入数据的大小。读取数据时,读取大小并构造字节数组。

我更喜欢并使用这种方法将大文件(> 10 MB)包括图像从客户端发送到服务器。通过预先写入大小,您知道要从 byte[] 读取多少字节

查看onethis article 将文件转换为 byte[] 并返回

/*  Convert File to byte[] msgBytes */


/* Write byte array */
OutputStream out = socket.getOutputStream(); 
DataOutputStream dos = new DataOutputStream(out);
int length = msgBytes.length;// it is byte array of message to be sent
dos.writeInt(length);
if (length > 0) {
    dos.write(msgBytes);
}

/*Read byte array */
DataInputStream dis = new DataInputStream(socket.getInputStream());
int length = dis.readInt();                   
if(length>0) {
    byte[] msgBytes = new byte[length];
    dis.readFully(msgBytes, 0, length); 
}

/* Now you can convert byte array back to File*/

编辑:(用于恢复下载,当我回答时这不是原始帖子的一部分)

  1. 在客户端保存从服务器读取的字节数(使用 inputStream.read() 而不是 inputStream.readFully()

  2. 重新连接到服务器时跳过该值 (bytesAlreadyRead)

【讨论】:

  • 我已经这样做了,在dos.write(msgBytes)之后,我怎么知道长度是实际写的?
  • 如果您希望从暂停丢失时间的点恢复文件读取,请查看:stackoverflow.com/questions/22107380/…
猜你喜欢
  • 1970-01-01
  • 2015-05-09
  • 1970-01-01
  • 1970-01-01
  • 2018-02-03
  • 1970-01-01
  • 2014-05-28
  • 2013-08-16
  • 1970-01-01
相关资源
最近更新 更多