为什么 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 从套接字读取随机数量而不是整个消息? 的相关文章

  • 如何迭代所有注册表项?

    我正在尝试迭代所有注册表项以查找 包含 并删除 jre1 5 0 14 值 有办法做到吗 下面的代码只是在特定键下找到jre1 5 0 14 我确实想迭代所有的键 顺便说一句 if 子句获取是否等于 jre1 5 0 14 但如果它包含 j
  • Java:高性能消息传递(单生产者/单消费者)

    我最初问这个问题here https stackoverflow com questions 3367192 java is while true loop in a thread bad whats the alternative 但我意
  • 如何同时支持 IPv4 和 IPv6 连接

    我目前正在开发 UDP 套接字应用程序 需要构建支持 以便 IPV4 和 IPV6 连接可以将数据包发送到服务器 我希望有人能帮助我并为我指明正确的方向 我发现的大部分文档都不完整 如果您能指出 Winsock 和 BSD 套接字之间的任何
  • 在Java中清空数组/处理

    除了循环遍历数组中的每个元素并将每个元素设置为 null 之外 Java 处理中是否有一个本机函数可以简单地清空数组 或销毁它 以便能够将其重新声明为新数组 There s Arrays fill myArray null 并不是说它执行的
  • 使用 jpql 和 jpa 从日期字段中提取年份

    我想从数据库中的一行中提取年份部分 以便将其与值进行比较 这是我的功能 public List
  • 无法实例化接收器 com.parse.GcmBroadcastReceiver

    我正在编写一个使用 GCM 通知和解析推送的离子应用程序 这个应用程序正在使用这些插件 com ionic keyboard 1 0 3 Keyboard com phonegap plugins PushPlugin 2 4 0 Push
  • 在 TestNG 中运行多个类

    我正在尝试自动化一个场景 其中我想登录一次应用程序 然后进行操作而无需再次重新登录 考虑一下 我有在特定类的 BeforeSuite 方法中登录应用程序的代码 public class TestNGClass1 public static
  • 要打乱的键值(整数、字符串)列表的最佳结构

    我需要在 Java 中实现一个结构 它是一个键值列表 类型为整数 字符串 并且我想对其进行洗牌 基本上 我想做类似的事情 public LinkedHashMap
  • 哈希码是否用于加速集合中的对象查找?

    IIUC 相同类型的两个不同对象可以存储在 HashSet 中 即使两个对象在以下情况下返回相同的值 hashCode 叫做 例如根据本文 https eclipsesource com blogs 2012 09 04 the 3 thi
  • 在 Hibernate 中创建 UPDATE RETURNING 查询

    在 Oracle 中 我们可以创建一个更新查询 该查询将使用 RETURNING 子句返回更新的记录 Hibernate中有类似的功能吗 除了数据库生成的值之外 Hibernate 显然不需要返回更新的实例 因为对象传递给Session s
  • 如何从 Google Custom Search API 获取超过 100 个结果

    我正在尝试使用 Google Custom Search API 在 Java 中进行研究 因此 我需要为每个查询提供一个大的结果集 然而 我似乎仅限于前 100 个结果 这比我需要的要少得多 我使用这样的列表方法 list setStar
  • Java ConcurrentModificationException [重复]

    这个问题在这里已经有答案了 当删除倒数第二个元素时 没有 ConcurrentModificationException List
  • 为什么现在()? (客观化)

    为什么我想要异步加载 Objectify 实体 异步加载到底意味着什么 根据客观化有关加载的文档 https code google com p objectify appengine wiki BasicOperations Loadin
  • 在Java中多次读取System.in会导致IOException?

    我正在尝试创建一个小命令行游戏来强化我在过去几个月中在 Java 中学到的一些东西 我正在尝试创建一个名为 readInput 的方法 它返回一个我可以一次又一次调用的字符串 第一次它工作正常 但第二次它会导致 IO Exception 如
  • 如何使用云打印打印Android活动显示

    我正在尝试将 Google 云打印实现到应用程序中 遵循集成指南 https developers google com cloud print docs android 我试图通过打印 google com 来保持基本 单击我创建的打印按
  • 从命令行运行 Maven 插件的语法是什么。

    我看到这里已经有人问过这个问题 如何从命令行执行maven插件 https stackoverflow com questions 12930656 how to execute maven plugin from command line
  • Google Cloud Messaging - 立即收到或长时间延迟收到的消息

    我在大学最后一年的项目中使用谷歌云消息传递 一切正常 但我在使用 GCM 时遇到了一些麻烦 通常 消息要么几乎立即传递 要么有很大的延迟 我读过这篇文章 但我真的认为它不适用于这种情况 GCM 通常会在消息发送后立即传送消息 然而 这并不总
  • H2 - (相当)长的 INSERT 失败,错误 42000

    H2 内存中 插入 错误 42000 尝试过版本 1 4 196 1 4 197 1 4 199 我还尝试在 H2 服务器 本地 上执行 INSERT 也失败 给出错误的行 抱歉 但出于安全原因 我无法生成更多 INSERT INTO tb
  • JMockit - 初始化问题

    当我使用以下测试时 我收到警告 警告 JMockit 是按需初始化的 这可能会导致某些测试失败 请检查文档以获取更好的初始化方法 这是我的测试实现 package test import static mockit Mockit impor
  • 编写自定义 Eclipse 调试器

    EDIT 一定有某种方法可以解决这个问题 而无需编写全新的调试器 我目前正在研究在现有 java 调试器之上构建的方法 如果有人对如何获取 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