【问题标题】:Socket InputStream glitches while reading bytes in chunksSocket InputStream 在读取块中的字节时出现故障
【发布时间】:2015-03-03 12:58:02
【问题描述】:

我正在通过套接字连接编写简单的文件传输,但我遇到了问题 在以字节块下载文件时。当我一次读取一个字节时,一切正常,但是当我尝试读取例如 512 字节的块时,在下载文件的所有字节后(由于我的标题,我知道长度),套接字开始接收一些随机字节最终发生了崩溃,因为找到了 2x "%" 并且服务器尝试计算传入消息的长度,而没有开始。

 @Override
  public void run() {

      while (client.isConnected() && !client.isClosed() && !client.isInputShutdown()){
          try {
                readResponse();
                clientWriter.write("0%"); /// IF IT CATCHES EXCEPTION SOCKET CLOSED ON THE OTHER SIDE(DON'T KNOW HOW TO CHECK IT IN ANOTHER WAY)
           } 
          catch (IOException e) {
               System.out.println(e.toString());
               return;
           } 
          catch (InterruptedException e) {
               System.out.println(e.toString());
               return;
           } 
      }

   }

private void readResponse() throws IOException, InterruptedException {

       int length = 0;
       int ch;
       FileOutputStream file = new FileOutputStream("holder");
       boolean bWrite = false;
       StringBuilder name = new StringBuilder();
       int percentageCount = 0;
       String filename="";
       length = 0;
       int l = 0;
       int old = 0;
       while ((ch=client.getInputStream().read())!=-1){
           if (!bWrite) {
               name.append(Character.toChars(ch));
           }
           if (ch==37 && !bWrite){
               if (percentageCount<1){
                   percentageCount++;
               } else {
                filename = name.toString();
                length = Integer.parseInt(filename.substring(0,filename.indexOf("%")));
                l = length;
                filename = filename.substring(filename.indexOf("%")+1);
                filename = filename.substring(0,filename.indexOf("%"));
               file = new FileOutputStream(filename);
               bWrite = true;
               break;
               }
           }
       }
       byte[] bytes = new byte[512];
       while (length>=512){
           client.getInputStream().read(bytes, 0, 512);
           file.write(bytes, 0, 512);
           length-=512;
       }
       if (length>0){
           bytes = new byte[length];
           client.getInputStream().read(bytes,0,length);
           file.write(bytes,0,length);
           length = 0;
       }
       file.flush();
       file.close();
    }

【问题讨论】:

  • 顺便说一句,我的标题格式是:%%
  • 您需要先清理循环。不要做client.getInputStream().read() 之类的事情,并尝试删除所有与您的问题无关的代码。很难找到愿意阅读所有内容的人。
  • 一个明显的问题是您读取了一个 512 字节的缓冲区,但实际上并没有检查返回了多少字节。您必须使用 read 的返回值(并且只写入 readLen 字节)。这在您的代码中发生了 2 次。特别是长度较大的第二次会失败。
  • 删除其他内容?我知道这有点混乱,但应该都能正常工作
  • 如果一切正常,那你为什么要问? :)

标签: java file sockets byte inputstream


【解决方案1】:

最后一段代码可以改成(未测试):

   byte[] bytes = new byte[512];
   InputStream is = client.getInputStream();
   while (length>0) {
       int read = is.read(bytes, 0, Math.min(bytes.length, length));
       if (read > 0) {
         file.write(bytes, 0, read);
         length-=read;
       }
       if (read < 0)
         throw new IOException("end reached before all data read"; 
   }

这会正确检查返回的大小,避免两个循环并检查流的结尾。

BTW2:getInputStream() 非常重,应该只执行一次(我的示例中的 is 应该在方法开始时检索,尤其是在读取循环之前)。

【讨论】:

  • 还有一个问题,另一方面,如何才能最好地检测套接字是否已关闭?
  • 除非您发送/接收某种形式的心跳消息,否则您无法在所有情况下都检测到它。您可以为套接字打开keepalive option,但这只会在数小时后检测到它(典型的操作系统设置)。但是,如果操作系统检测到它,您将在读取时获得 -1 或在写入时获得异常。您应该在您的协议中包含“我完成了”消息,以便您可以干净地关闭。 @Peter-Lawrey 有一个 -1 示例:stackoverflow.com/a/5562456/13189
猜你喜欢
  • 2015-07-11
  • 2023-03-30
  • 2017-07-15
  • 1970-01-01
  • 2011-08-07
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多