为什么 Java 从套接字读取随机数量而不是整个消息?

2024-03-07

我正在做一个项目,有一个关于 Java 套接字的问题。可以找到源文件here https://github.com/ChrisLundquist/Handbrake-Network-Queue/blob/master/java/src/FileTransfer.java.

成功以纯文本方式传输文件大小后,我需要传输二进制数据。 (DVD .Vob 文件)

我有一个循环,例如

                // Read this files size
                long fileSize = Integer.parseInt(in.readLine());

                // Read the block size they are going to use
                int blockSize = Integer.parseInt(in.readLine());
                byte[] buffer = new byte[blockSize];

                // Bytes "red"
                long bytesRead = 0;
                int read = 0;

                while(bytesRead < fileSize){
                System.out.println("received " + bytesRead + " bytes" + " of " + fileSize + " bytes in file " + fileName);
                read = socket.getInputStream().read(buffer);
                if(read < 0){
                    // Should never get here since we know how many bytes there are
                    System.out.println("DANGER WILL ROBINSON");
                    break;
                }
                binWriter.write(buffer,0,read);
                bytesRead += read;
            }

我读取了接近 99% 的随机字节数。我正在使用基于 TCP 的 Socket, 所以我不必担心下层传输错误。

收到的数字发生变化,但总是非常接近末尾 在文件 GLADIATOR/VIDEO_TS/VTS_07_1.VOB 中收到 7266304 字节中的 7258144 字节

然后应用程序会以阻塞读取的方式挂在那里。我很困惑。服务器正在发送正确的 文件大小并在 Ruby 中成功实现,但我无法让 Java 版本工作。

为什么我读取的字节数少于通过 TCP 套接字发送的字节数?

以上是由于下面许多人指出的一个错误。

BufferedReader 占用了我的套接字输入的 8Kb。可以找到正确的实现Here https://github.com/ChrisLundquist/Handbrake-Network-Queue/blob/master/java/src/FileTransfer.java#L112


If your in是一个 BufferedReader 那么你就会遇到缓冲超过需要的常见问题。 BufferedReader 的默认缓冲区大小是 8192 个字符,这大约是您期望的和实际得到的之间的差异。因此,您丢失的数据位于 BufferedReader 的内部缓冲区内,转换为字符(我想知道为什么它没有因某种转换错误而中断)。

The only workaround is to read the first lines byte-by-byte without using any buffered classes readers. Java doesn't provide an unbuffered InputStreamReader with readLine() capability as far as I know (with the exception of the deprecated DataInputStream.readLine(), as indicated in the comments below), so you have to do it yourself. I would do it by reading single bytes, putting them into a ByteArrayOutputStream until I encounter an EOL, then converting the resulting byte array into a String using the String constructor with the appropriate encoding.

请注意,虽然您无法使用 BufferedInputReader,但没有什么可以阻止您从一开始就使用 BufferedInputStream,这将使逐字节读取更加高效。

Update

事实上,我现在正在做类似的事情,只是稍微复杂一点。它是一种应用程序协议,涉及交换一些用 XML 很好地表示的数据结构,但它们有时附加有二进制数据。我们通过在根 XML 中添加两个属性来实现这一点:fragmentLength 和 isLastFragment。第一个指示 XML 部分后面有多少字节的二进制数据,isLastFragment 是一个布尔属性,指示最后一个片段,因此读取方知道不会再有二进制数据。 XML 以 null 结尾,因此我们不必处理 readLine()。读取代码如下所示:

    InputStream ins = new BufferedInputStream(socket.getInputStream());
    while (!finished) {
      ByteArrayOutputStream buf = new ByteArrayOutputStream();
      int b;
      while ((b = ins.read()) > 0) {
        buf.write(b);
      }
      if (b == -1)
        throw new EOFException("EOF while reading from socket");
      // b == 0
      Document xml = readXML(new ByteArrayInputStream(buf.toByteArray()));
      processAnswers(xml);
      Element root = xml.getDocumentElement();
      if (root.hasAttribute("fragmentLength")) {
        int length = DatatypeConverter.parseInt(
                root.getAttribute("fragmentLength"));
        boolean last = DatatypeConverter.parseBoolean(
                root.getAttribute("isLastFragment"));
        int read = 0;
        while (read < length) {
          // split incoming fragment into 4Kb blocks so we don't run 
          // out of memory if the client sent a really large fragment
          int l = Math.min(length - read, 4096);
          byte[] fragment = new byte[l];
          int pos = 0;
          while (pos < l) {
            int c = ins.read(fragment, pos, l - pos);
            if (c == -1)
              throw new EOFException(
                      "Preliminary EOF while reading fragment");
            pos += c;
            read += c;
          }
          // process fragment
        }

事实证明,使用以 null 结尾的 XML 确实是一件很棒的事情,因为我们可以在不更改传输协议的情况下添加其他属性和元素。在传输级别,我们也不必担心处理 UTF-8,因为 XML 解析器会为我们做这件事。在您的情况下,您可能对这两行感到满意,但如果您稍后需要添加更多元数据,您可能也希望考虑以 null 结尾的 XML。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Java 从套接字读取随机数量而不是整个消息? 的相关文章

随机推荐

  • Spring boot:在运行时添加新端点

    我正在开发一项功能 允许 Spring Boot 应用程序具有 插件 这意味着无需新的构建 应用程序就应该能够集成新的代码片段 动态类加载是可以的 但是 对于每个新的 插件 我需要添加一个新的休息端点 我知道一些库能够在 Spring Bo
  • 根据数组生成文件列表

    我尝试了一些事情 但这周我感觉我的大脑正在度假 我需要完成这件事 所以我希望有人可以帮助我 我需要根据保存到数据库中的哈希创建一个文件列表 看起来像这样 file1 dir1 file2 dir1 subdir1 file3 输出应该是这样
  • 如何在 Groovy 中重置模拟静态方法?

    我在测试设置中有以下内容 def originalPostAsXml RestClient postAsXml RestClient metaClass static postAsXml String uriPath String xml
  • 我可以在 Jenkinsfile 中增强 scm 吗?

    我花了很长时间才明白什么checkout scm真正的意思是在 Jenkinsfile 中 checkout 是一个函数 scm 是一个默认的全局变量 现在我明白了 我想补充一下scm例如 增加特定结账的超时时间或设置sparseCheck
  • YouTube 数据 API v3 - 评论线程请求不返回总结果计数

    当我执行以下 YouTube 数据 API 请求来列出 commentThreads 时 pageInfo totalResults未在响应中返回 我预计pageInfo totalResults待退回根据文档 https develope
  • Xcode 4:从命令行(xcodebuild)运行测试?

    我在 Xcode 4 中创建了一个全新的 iOS 项目 并包含单元测试 默认应用程序有 2 个目标 主应用程序和单元测试包 使用 产品 gt 测试 Command U 构建应用程序 构建单元测试包 启动 iOS 模拟器并运行测试 现在我希望
  • 是否可以对 Grid.Column 进行动画处理?

    我可以制作动画吗Grid Column财产 我需要搬家
  • 使用 Jetpack Compose 构造环

    I am learning Jetpack Compose and would like to build something like this 我尝试过通过堆叠使用框布局CircularProgressIndicator但需要对圆圈大小
  • 如何使用模型属性作为变量 ng-click

    我希望将 ng click 的函数调用作为字符串存储在我的模型中 我无法使用 ng click m func 如果我使用 ng click m func 也不起作用 http jsfiddle net j8wW5 19 http jsfid
  • redux-saga 调用调用的函数中对“this”的引用为空

    我在学redux saga我正在尝试将其集成到一个使用 openapi generator 生成的 API 的项目中 该 API 会生成如下所示的输出 async loginUser body Login Promise
  • Pandas - 查找每个组贡献的百分比

    我试图找到每个日期组所做的百分比贡献 下面给出的是我的数据的样子 期望找到每个产品在给定日期的贡献 date product quantity 2020 01 prod a 100 2020 01 prod b 200 2020 01 pr
  • 使用 vgg16 的验证集准确性较低

    我正在为一个项目进行狗品种分类 遇到了一个我不知道如何解决的重大问题 数据集是由以下机构提供的狗的图像斯坦福狗数据集 http vision stanford edu aditya86 ImageNetDogs 我用 keras 进行数据增
  • 在 Javascript/jQuery 中动态添加表行的绑定点击事件

    问题陈述 我有一张桌子thead静态创建 并且 tr td 在tbody动态创建的 我必须实现的是 当用户单击表格上的任意位置时 我需要获取val 被单击的行的第一列 为了测试这一点 我使用绑定一个点击事件on到父元素类 即类tbody 而
  • WPF 互斥列表框

    我有一个应用程序 其中有一个列表框的列表框 我想让 InnerList 框互斥 我的 ViewModel 有一个集合 Foos 它有一个描述 一个 IsSelected 属性和一个集合 Bars 它有一个名称和 IsSelected 属性
  • android studio 中缺少模拟器工具窗口

    我的 Android Studio IDE 缺少工具窗口 模拟器 View gt 工具窗口尽管 在工具窗口中启动 选项已选中File gt Settings gt Tools gt Emulator 我不知道是什么改变了它 但它曾经正常工作
  • 无法将新生成的 Play 框架项目导入 IntelliJ IDEA 15

    当我尝试将新创建的 play 框架项目导入到我的 IntelliJ IDEA 15 时 出现以下异常 Java HotSpot TM 64 Bit Server VM warning ignoring option MaxPermSize
  • 从当前工作树创建分支并重置为 HEAD

    我目前正在开发一个功能 结果比预期的要大 所以最好创建一个分支来处理它 因此 我需要从当前工作目录创建一个新分支 并将 master 分支重置为当前 HEAD 以便可以对生产环境进行一些修复 不知何故 这听起来像是一项简单的任务 但我不太明
  • Angular2 ng-模板位于单独的文件中[重复]

    这个问题在这里已经有答案了 angular2如何使用不同文件中的ng template 当我将 ng template 放在我使用的同一个 HTML 中时 它可以工作 但是当我将 ng template 移动到一个单独的文件中时 它就无法工
  • 在 C# 中捕获本机 C++ 异常

    我有一些本机 C 类库 我将它们封装在 C NET 中 然后从 C 调用它们 三层 我可以从 C NET 中抛出异常 并愉快地在 C 中捕获它们 问题是 我捕获本机 C 异常的唯一方法是捕获 System Exception 这很好 但在从
  • 为什么 Java 从套接字读取随机数量而不是整个消息?

    我正在做一个项目 有一个关于 Java 套接字的问题 可以找到源文件here https github com ChrisLundquist Handbrake Network Queue blob master java src File