如果在写入OutputStream

时间:2016-02-18 00:33:38

标签: java android ssl tcp outputstream

编辑:

我更改了代码,以便在传输后检查文件的完整性。

但是现在当我在dos.write(buffer, 0, count)的客户端放置一个断点,终止服务器,然后恢复客户端代码执行时,它会无限期地挂起serverMD5[i] = dataInputStream.readByte()

即使用户现在知道传输不成功(应用程序挂起并需要重新启动),再次这不是我预期的做(抛出IOException)。

更改过代码的原帖:

我创建了一个使用SSLSocket连接到服务器并发送一些数据的android客户端。 这是相关的客户端和服务器代码

客户端:

try {
  SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket();
  sslsocket.connect(new InetSocketAddress(SERVER_IP, UPLOAD_PORT), 2000);

  OutputStream outputStream = sslsocket.getOutputStream();

  DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
  dataOutputStream.writeInt(DEVICE_ID);
  dataOutputStream.writeLong(FILE_LENGTH);

  MessageDigest md = MessageDigest.getInstance("MD5");
  DigestOutputStream dos = new DigestOutputStream(outputStream, md);

  InputStream readingsInputStream = new FileInputStream(FILE_NAME);

  int count;
  byte[] buffer = new byte[10 * 1024];
  while ((count = readingsInputStream.read(buffer)) > 0) {
    dos.write(buffer, 0, count);
  }
  readingsInputStream.close();

  byte[] md5 = md.digest();
  byte[] serverMD5 = new byte[16];

  DataInputStream dataInputStream = new DataInputStream(sslsocket.getInputStream());

  for (int i = 0;i<16;i++) {
    serverMD5[i] = dataInputStream.readByte();
    if (md5[i] != serverMD5[i]) throw new Exception("MD5 mismatch");
  }

  sslsocket.close();
} catch (Exception e) {
  ...
}

服务器:

try {
  SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();

  InputStream inputStream = sslSocket.getInputStream();

  DataInputStream dataInputStream = new DataInputStream(inputStream);
  int deviceID = dataInputStream.readInt();
  long fileLength = dataInputStream.readLong();

  MessageDigest md = MessageDigest.getInstance("MD5");
  DigestInputStream dis = new DigestInputStream(inputStream, md);

  OutputStream readingsOutputStream = new FileOutputStream("Device"+deviceID+".txt", false);

  int count;
  byte[] buffer = new byte[1];
  do {
    count = dis.read(buffer);
    readingsOutputStream.write(buffer, 0, count);
    fileLength -= count;
  } while (fileLength > 0);

  readingsOutputStream.close();

  byte[] md5 = md.digest();

  DataOutputStream md5OutputStream = new DataOutputStream(sslSocket.getOutputStream());
  for (int i = 0;i<16;i++) md5OutputStream.writeByte(md5[i]);

  sslSocket.close();
} catch (Exception e) {
  ...
}

通常这一切都按预期工作,但是当我在客户端的dos.write(buffer, 0, count)行放置断点然后在到达断点时终止服务器时会出现问题。

在客户端上继续执行代码后,它不会抛出异常,只是通过代码块的其余部分,让我相信该文件已成功写入服务器。

当然不是这种情况,因为在写入OutputStream之前服务器已关闭。这导致服务器上的空DeviceX.txt(X是设备号)文件。

这是一个很大的问题,因为用户可能认为数据已成功传输并从设备中删除(由于应用程序的性质,发送的数据会在某些时候被删除)。

由于我设法产生了这个bug,我认为它可能会在现实场景中发生。这是我第一次使用套接字,我不知道如何解决这个问题。

此外,如果有人注意到此代码块可能出错的任何其他情况(结果不符合预期但未抛出异常的另一种情况),请告诉我。

2 个答案:

答案 0 :(得分:1)

这是TCP的正常操作。抛开SSL,您的发送将缓冲在套接字发送缓冲区中,并在.userWrap { position: relative; display: inline-block; width: 300px; height: 50px; overflow: visible; z-index: 1; } .userWrap:hover { z-index: 2; } .user { position: absolute; display: inline-block; width: 300px; height: 50px; margin-bottom: 5px; background: #fff; transition: width 0.3s, height 0.3s; } .user:hover { width: 350px; height: 200px; background: #eee; transition: width 0.3s ease 0.5s, height 0.3s ease 0.5s; } .user img { float: left; } .user .name, .skills { margin-left: 5px; } .user .name { font-size: 21px; font-weight: bold; } 函数返回后异步传输。因此send()函数不可能立即检测到对等中断。如果您继续发送,则TCP的重试将最终失败并导致后续发送失败,对于具有send()的Java。

IOException: connection reset

您不能假设inputStream.read(deviceIDbuffer); 填充缓冲区。你应该在这里使用read()

答案 1 :(得分:-1)

看起来您需要在客户端和服务器之间进行双向通信。当客户端完成上传后,您可以让客户端发送传输结束(ascii 0x4)字符(或您的客户端/服务器认为是“特殊”序列的任何其他字符)。当服务器收到转换结束字符时,服务器可以回复它获得的字节数。在客户端,等待响应,如果达到超时,告诉用户出现了问题。