netty ChannelInboundHandlerAdapter 将帧裁剪为 ~1500 字节

2024-03-12

我已经实现了一个服务器应用程序,它使用 netty 框架通过 ChannelInblundHandlerAdapter 读取传入的字节。

如标题所示,我的问题是,我不定期地从客户端获取内容,我认为这些内容在 ~1.500 字节后被剪切。例如:在这种情况下,我应该收到一个大的 JSON 数组。因为它被剪切了,所以我无法解析它。

我尝试在使用消息之前使用管道中的附加 ByteToMessageDecoder 通道对消息进行解码。但这并不能解决问题。我在 JSON 中没有分隔符,我可以检查并将两个(或更多)部分再次粘在一起。

这是我的管道配置:

        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new IdleStateHandler(45,0,0));
                        ch.pipeline().addLast(new MyByteToMessageDecoder());
                        ch.pipeline().addLast(new GatewayCommunicationHandler());
                    }
                })
                .option(ChannelOption.SO_BACKLOG, 128)
                .option(ChannelOption.SO_RCVBUF, 8192)
                .childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(8192))
                .childOption(ChannelOption.SO_KEEPALIVE, true);

        initRestServer();

        // Bind and start to accept incoming connections.
        ChannelFuture f = b.bind(Config.gatewayPort).sync();
        f.channel().closeFuture().sync();

这就是我的 ByteToMessageDecoder:(我知道它一团糟,但我不知道在我的情况下如何处理它)

public class MyByteToMessageDecoder extends ByteToMessageDecoder {

@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
    byte[] receivedBytes = new byte[in.readableBytes()];
    in.getBytes(in.readerIndex(), receivedBytes);


    if (receivedBytes[in.readableBytes()-1] != (byte) 0) {
        out.add(receivedBytes);
        return;
    }

    int lenForOutBytes = 0;
    for (Object o : out) {
        byte[] bytes = (byte[]) o;
        lenForOutBytes += bytes.length;
    }

    byte[] outBytes = new byte[lenForOutBytes];

    for (Object o : out) {
        byte[] bytes = (byte[]) o;

        if (out.size() == 1) {
            outBytes = (byte[]) out.get(0);
        }
        else {
            int i = 0;

            for (int j = 0; j < bytes.length; j++) {
                outBytes[i + j] = bytes[j];
            }
            i += bytes.length;
        }
    }

    ctx.fireChannelRead(outBytes);
    in.resetReaderIndex();
}
...

还有其他人有这样的问题吗?

感谢您的回复

Br Joe


我发现这个问题经常发生,所以我故意比平时更广泛一些

发生此问题的原因是 TCP 是基于流的,而不是基于数据包的。

这基本上会发生:

  1. [client]想要发送10k字节的数据
  2. [client] 将数据发送到TCP层
  3. [客户端] TCP 层分割数据包,它知道最大数据包大小为 1500(这是默认的 MTU)几乎全部网络使用)
  4. [client] 客户端向服务器发送数据包,其中包含 40 字节作为标头,1460 字节作为数据
  5. [服务器] Netty收到第一个数据包,直接调用你的函数,第一个数据包包含1460字节数据
  6. [服务器] 当您的函数需要处理剩余数据时(初始数据 - 1260)

所以解决这个问题有多种方法

在消息前面添加长度:

虽然这通常是解决数据包的最简单方法,但在同时处理小型和大型消息时,它也是效率最低的方法。这也需要更改协议。

基本思想是在发送数据包之前添加长度,这样您就可以正确拆分消息

优点

  • 无需循环数据来过滤字符或阻止禁止字符
  • 如果您的网络中有中继系统,则它们不必对消息边界进行任何硬解析

缺点

  • 必须知道消息的长度,在长消息中,这会占用内存

How?

如果您使用标准整数字段,这非常简单,因为 Netty 已为此构建了类:

  • LengthFieldBasedFrameDecoder http://netty.io/4.0/api/io/netty/handler/codec/LengthFieldBasedFrameDecoder.html
  • LengthFieldPrepender http://netty.io/4.0/api/io/netty/handler/codec/LengthFieldPrepender.html

这在您的管道中以以下方式使用

// int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024 * 4, 0, 2, 0, 2));
// int lengthFieldLength, int lengthAdjustment
pipeline.addLast(new LengthFieldPrepender(2, 0));

这基本上构成了如下所示的数据包:

您发送:

DATA: 12B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 65 6c 6c 6f 20 57 6f 72 6c 64 21             |Hello World!    |
+--------+-------------------------------------------------+----------------+

LengthFieldPrepender http://netty.io/4.0/api/io/netty/handler/codec/LengthFieldPrepender.html将其转换为:

DATA: 14B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21       |..Hello World!  |
+--------+-------------------------------------------------+----------------+

然后当你收到消息时,LengthFieldBasedFrameDecoder http://netty.io/4.0/api/io/netty/handler/codec/LengthFieldBasedFrameDecoder.html将其解码为:

DATA: 12B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 65 6c 6c 6f 20 57 6f 72 6c 64 21             |Hello World!    |
+--------+-------------------------------------------------+----------------+

按简单分隔符拆分消息

某些协议采用不同的方法,它们不是按固定长度进行拆分,而是按分隔符进行拆分。一种快速查看方法是 Java 中的字符串以 a 结尾",文本文件中的行以换行符结尾,自然文本中的段落以双换行符结尾。

优点

  • 如果您知道某个数据不包含字符,则相对容易生成,例如 JSON 通常不包含空格,因此用空格分隔消息很容易。
  • 易于通过脚本语言实现,因为不需要状态

缺点

  • 与框架字符冲突可能会使消息大小膨胀
  • 长度事先未知,因此要么在代码中设置硬编码限制,要么继续读取直到内存不足或数据结束
  • 即使您对数据包不感兴趣,也需要阅读每个字符

How?

从 Netty 发送消息时,您需要手动将分隔符添加到消息本身,接收时您可以使用DelimiterBasedFrameDecoder https://netty.io/4.0/api/io/netty/handler/codec/DelimiterBasedFrameDecoder.html将传入流解码为消息。

管道示例:

这在您的管道中以以下方式使用

// int maxFrameLength, ByteBuf... delimiters
pipeline.addLast(1024 * 4, DelimiterBasedFrameDecoder(Delimiters.lineDelimiter()));

发送消息时,需要手动添加分隔符:

DATA: 14B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 0d 0a       |Hello World!..  |
+--------+-------------------------------------------------+----------------+

收到消息时,DelimiterBasedFrameDecoder https://netty.io/4.0/api/io/netty/handler/codec/DelimiterBasedFrameDecoder.html为您将消息转换为帧:

DATA: 12B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 65 6c 6c 6f 20 57 6f 72 6c 64 21             |Hello World!    |
+--------+-------------------------------------------------+----------------+

根据复杂的业务分隔符进行拆分

并不是所有的框架都是容易的,有些解决方案如果避免的话实际上是最好的,但有时,你确实需要做一些肮脏的工作。

优点

  • 几乎可以处理所有现有的数据结构
  • 无需修改协议

缺点

  • 通常你必须检查每个字节
  • 代码可能很难理解
  • 快速解决方案可能会因其认为格式错误的输入而产生奇怪的错误

这分为两类:

  • 基于现有解码器
  • 模式检测

基于现有解码器

通过这些解决方案,您基本上可以使用其他框架中的现有解码器来解析数据包,并检测其处理中的故障。

示例为GSON https://github.com/google/gson and ReplayingDecoder https://netty.io/4.0/api/io/netty/handler/codec/ReplayingDecoder.html:

public class GSONDecoder
    extends ReplayingDecoder<Void> {

    Gson gson = new GsonBuilder().create();

    protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) 
        throws Exception {

        out.add(gson.fromJson(new ByteBufInputStream(buf, false), Object.class));
    }
}

模式检测

如果您要使用模式检测方法,您需要了解您的协议。让我们为 JSON 制作一个模式检测解码器。

根据JSON的结构,我们做以下假设:

  1. JSON 基于匹配对{ and }, and [ and ]
  2. 匹配对{ and }之间应该被忽略"
  3. "当前面加上 a 时应被忽略\
  4. A \如果前面加上一个则应被忽略\,从左到右解析时

基于这些属性,让我们制作一个ByteToMessageDecoder https://netty.io/4.0/api/io/netty/handler/codec/ByteToMessageDecoder.html基于这些假设:

public static class JSONDecoder extends ByteToMessageDecoder {

    // Notice, this class is designed for JSON without a charset definition at the start, adding this is hard as we basicly have to call differend
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        in.markReaderIndex();

        int fromIndex = in.readerIndex();

        int unclosedCurlyBracketsSeen = 0;
        boolean inQuotedSection = false;
        boolean nonWhitespaceSeen = false;
        boolean slashSeen = false;

        while (in.isReadable()) {
            boolean newSlashSeenState = false;
            byte character = in.readByte();
            if (character == '{' && !inQuotedSection) {
                unclosedCurlyBracketsSeen++;
            }
            if (character == '}' && !inQuotedSection) {
                unclosedCurlyBracketsSeen--;
            }
            if (character == '[' && !inQuotedSection) {
                unclosedCurlyBracketsSeen++;
            }
            if (character == ']' && !inQuotedSection) {
                unclosedCurlyBracketsSeen--;
            }
            if (character == '"' && !slashSeen) {
                inQuotedSection = !inQuotedSection;
            }
            if (character == '\\' && !slashSeen) {
                newSlashSeenState = true;
            }
            if (!Character.isWhitespace(character)) {
                nonWhitespaceSeen = true;
            }
            slashSeen = newSlashSeenState;
            if(unclosedCurlyBracketsSeen == 0 && nonWhitespaceSeen) {
                int targetIndex = in.readerIndex();
                out.add(in.slice(fromIndex, targetIndex - fromIndex).retain());
                return;
            }
        }

        // End of stream reached, but our JSON is not complete, reset our progress!
        in.resetReaderIndex();
    }

}

接收消息时,它是这样工作的:

DATA: 35B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 68 69 21 22 2c 22 53 74 72 69 6e 67 3a 20 |{"hi!","String: |
|00000010| 5c 22 48 69 5c 22 22 7d 20 20 7b 22 73 6c 61 73 |\"Hi\""}  {"slas|
|00000020| 68 22 3a                                        |h":             |
+--------+-------------------------------------------------+----------------+

DATA: 34B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 22 5c 5c 22 7d 7b 22 4e 65 73 74 65 64 3a 22 3a |"\\"}{"Nested:":|
|00000010| 7b 22 64 65 65 70 65 72 22 3a 7b 22 6f 6b 22 7d |{"deeper":{"ok"}|
|00000020| 7d 7d                                           |}}              |
+--------+-------------------------------------------------+----------------+

正如你所看到的,我们收到了 2 条消息,其中 1 条甚至在 2 个“虚拟 TCP”数据包之间被分段,这由我们的“JSON 解码器”转换为以下 ByteBuf 数据包:

DATA: 24B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 68 69 21 22 2c 22 53 74 72 69 6e 67 3a 20 |{"hi!","String: |
|00000010| 5c 22 48 69 5c 22 22 7d                         |\"Hi\""}        |
+--------+-------------------------------------------------+----------------+

DATA: 16B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 20 20 7b 22 73 6c 61 73 68 22 3a 22 5c 5c 22 7d |  {"slash":"\\"}|
+--------+-------------------------------------------------+----------------+

DATA: 29B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 4e 65 73 74 65 64 3a 22 3a 7b 22 64 65 65 |{"Nested:":{"dee|
|00000010| 70 65 72 22 3a 7b 22 6f 6b 22 7d 7d 7d          |per":{"ok"}}}   |
+--------+-------------------------------------------------+----------------+
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

netty ChannelInboundHandlerAdapter 将帧裁剪为 ~1500 字节 的相关文章

  • Netbeans 8.1 Gnome 3 GTK+ UI 字体和选项卡高度

    我刚刚在运行 GNOME 3 桌面的 Ubuntu 16 04 上安装了 NetBeans 8 1 如果可能的话 我想继续使用 IDE 的 GTK 外观和感觉 但 UI 上的字体 尤其是选项卡中的字体 太小且重叠 我尝试添加 fontsiz
  • 如何在由子控件组成的 SWT 复合材料上跟踪鼠标?

    我创建了自己的控件 我想跟踪鼠标并添加一个MouseTrackListener 很遗憾MouseEnter and MouseLeave当鼠标移动到我的合成部分 即标签和按钮 上时 也会生成事件 Mouse enter mouse ente
  • eclipse行号状态行贡献项是如何实现的?

    我需要更新状态行编辑器特定的信息 我已经有了自己的实现 但我想看看 eclipse 贡献项是如何实现的 它显示状态行中的行号 列位置 谁能指点一下 哪里可以找到源代码 提前致谢 亚历克斯 G 我一直在研究它 它非常复杂 我不确定我是否了解完
  • Java 的支持向量机?

    我想用Java编写一个 智能监视器 它可以随时发出警报detects即将到来的性能问题 我的 Java 应用程序正在以结构化格式将数据写入日志文件
  • 为什么即使我的哈希码值相同,“==”也会返回 false

    我写了一个像这样的课程 public class HashCodeImpl public int hashCode return 1 public static void main String args TODO Auto generat
  • 将巨大的模式编译成Java

    有两个主要工具提供了将 XSD 模式编译为 Java 的方法 xmlbeans 和 JAXB 问题是 XSD 模式确实很大 30MB 的 XML 文件 大部分模式在我的项目中没有使用 所以我可以注释掉大部分代码 但这不是一个好的解决方案 目
  • 将非 Android 项目添加到 Android 项目

    我在 Eclipse 中有三个项目 Base Server 和 AndroidClient Base和Server是Java 1 7项目 而AndroidClient显然是一个android项目 基础项目具有在服务器和 Android 客户
  • WebService ASP.NET MVC 3 发送和接收

    这几天我一直在绞尽脑汁思考如何满足新的要求 我有两个网站 第一个让用户填写申请表 第二个网站是用于管理用户应用程序的内部网站 我需要开发一个 Web 服务 将应用程序数据从网站 1 发送到网站 2 并向网站 2 返回成功或失败的响应 我以前
  • 如何在 Spring 中使 @PropertyResource 优先于任何其他 application.properties ?

    我正在尝试在类路径之外添加外部配置属性资源 它应该覆盖任何现有的属性 但以下方法不起作用 SpringBootApplication PropertySource d app properties public class MyClass
  • Sun 在 EDT 之外做 GUI 工作的演示?

    我正在看SplashDemo java http download oracle com javase tutorial uiswing examples misc SplashDemoProject src misc SplashDemo
  • 在Java中运行bat文件并等待

    您可能会认为从 Java 启动 bat 文件是一项简单的任务 但事实并非如此 我有一个 bat 文件 它对从文本文件读取的值循环执行一些 sql 命令 它或多或少是这样的 FOR F x in CD listOfThings txt do
  • 如何在JPanel中设置背景图片

    你好 我使用 JPanel 作为我的框架的容器 然后我真的想在我的面板中使用背景图片 我真的需要帮助 这是我到目前为止的代码 这是更新 请检查这里是我的代码 import java awt import javax swing import
  • 使用 Elastic Beanstalk 进行 Logback

    我在使用 Elastic Beanstalk 记录应用程序日志时遇到问题 我正在 AWS Elastic Beanstalk 上的 Tomcat 8 5 with Corretto 11 running on 64bit Amazon Li
  • 将 JavaFX FXML 对象分组在一起

    非常具有描述性和信息性的答案将从我这里获得价值 50 声望的赏金 我正在 JavaFX 中开发一个应用程序 对于视图 我使用 FXML
  • 使用 HtmlUnit 定位弹出窗口

    我正在构建一个登录网站并抓取一些数据的程序 登录表单是一个弹出窗口 所以我需要访问这个www betexplorer com网站 在页面的右上角有一个登录链接 写着 登录 我单击该链接 然后出现登录弹出表单 我能够找到顶部的登录链接 但找不
  • Log4j2 ThreadContext 映射不适用于parallelStream()

    我有以下示例代码 public class Test static System setProperty isThreadContextMapInheritable true private static final Logger LOGG
  • MiniDFSCluster UnsatisfiedLinkError org.apache.hadoop.io.nativeio.NativeIO$Windows.access0

    做时 new MiniDFSCluster Builder config build 我得到这个异常 java lang UnsatisfiedLinkError org apache hadoop io nativeio NativeIO
  • Java 11 - 将 Spring @PostConstruct 替换为 afterPropertiesSet 或使用 initMethod

    我正在使用 spring 应用程序 有时会使用 PostConstruct用于代码和测试中的设置 看来注释将被排除在外Java 11 https www baeldung com spring postconstruct predestro
  • 由 Servlet 容器提供服务的 WebSocket

    上周我研究了 WebSockets 并对如何使用 Java Servlet API 实现服务器端进行了一些思考 我没有花费太多时间 但在使用 Tomcat 进行一些测试时遇到了以下问题 如果不修补容器或至少对 HttpServletResp
  • java'assert'和'if(){}else exit;'之间的区别

    java和java有什么区别assert and if else exit 我可以用吗if else exit代替assert 也许有点谷歌 您应该记住的主要事情是 if else 语句应该用于程序流程控制 而assert 关键字应该仅用于

随机推荐

  • 如何将vim(通过tmux)绑定到Cmd键

    我通常使用 macvim 并且使用 macs 命令键有许多键绑定 我正在尝试切换到 tmux 但这些绑定都不起作用 有关如何修改我的 tmux config 或 vimrc 以恢复这些绑定的任何提示 你是否有机会使用
  • 如何在单击时切换选中/未选中状态时更改复选框标签的颜色

    当我选中或取消选中时 我试图更改复选框标签的字体颜色和背景颜色 我在这个网站上找到了一个 javascript 解决方案 但无法使代码正常工作 这是我到目前为止所尝试过的 现在它正在将 突出显示 类附加到父 div 我只想更改标签 谢谢你的
  • 如何在 ASP.NET 5 中将实体框架 6 与 MySQL 结合使用?

    我有一个使用 ASP NET MVC 4 Entity Framework 6 和 MySQL 的现有网站 我正在尝试将其升级到 ASP NET 5 但希望继续使用实体框架 6 因为实体框架缺少一些功能并且尚不支持 MySQL 如何在 AS
  • 如何在条形图上方注释geom_bar?

    我正在尝试使用 ggplot2 做一个简单的绘图 library ggplot2 ggplot diamonds aes x cut y depth geom bar stat identity color blue facet wrap
  • R - 如何将数据转换为块形式以进行弗里德曼测试?

    在此输入图像描述 https i stack imgur com N0cvs png我有一些与治疗前后血液中化学物质水平有关的数据 有 4 个治疗组 ABCD 有人告诉我可以运行弗里德曼测试来立即比较所有这些变量 我尝试过的代码是 atta
  • 如何限制极坐标的显示宽度,以便以清晰的方式打印宽数据帧?

    考虑下面的例子 pd set option display width 50 pl DataFrame data np random randint 0 20 size 10 42 columns list abcdefghijklmnop
  • EF 中的 CurrentDateTime()

    我使用这段代码来获取服务器日期 但我真的不明白 CreateDateTime 不是一个 sql 函数 那么它是什么 DateTime ServerDate Entities CreateQuery
  • Python matplotlib 减小颜色条标签的大小

    我需要你的帮助 我有一个绘图代码如下 fig plt figure ax1 fig add subplot 111 imax1 ax1 imshow data interpolation nearest origin lower cmap
  • Log4J - 类似 SiftingAppender 的功能

    我在一个使用的项目中工作Log4J http logging apache org log4j 1 2 index html 要求之一是为每个线程创建一个单独的日志文件 这本身就是一个奇怪的问题 通过动态创建一个新的 FileAppende
  • 在 Matlab 图中重叠两个轴

    我正在寻找一种方法来覆盖 x y 时间序列 比如用 plot 创建的 在 contourf 生成的显示之上 在 y 轴上具有不同的缩放比例 似乎在两个 x y 图的情况下执行此操作的典型方法是使用内置函数 plotyy 它甚至可以由 plo
  • 实体框架代码优先一对一必需-必需关系

    使用 Entity Framework Code First 4 3 1 时 可以创建具有多重性的 1 对 1 关系 也就是说 关系的每一端都有一个实体 可以将一对一关系配置为需要 需要 or 必需 可选 然而 当我在两者之间切换时 我没有
  • Spark - 它如何在节点周围分发数据?

    Spark如何将数据分发给worker 工作人员是从数据源读取数据 还是驱动程序读取数据并将其发送给工作人员 当一个工作人员需要另一个工作人员中的数据时 他们是否直接进行通信 Thanks 如果您使用分布式输入法 例如SparkContex
  • 如果对于屏幕来说太长,则使水平单选按钮换行

    所以我有以下单选按钮 我想让它们像这样显示 然而 出现这种情况 我怎样才能让它像上面那样显示 我可以在 Eclipse 中的 GUI 编辑器中移动它 但它会从 RadioGroup 中删除 RadioButton 在组内 它忽略所有其他布局
  • 对象初始值设定项和构造函数有什么区别?

    两者之间有什么区别 何时使用 对象初始值设定项 而不是 构造函数 反之亦然 我正在使用 C 如果这很重要的话 另外 对象初始值设定项方法是否特定于 C 或 NET 对象初始值设定项是 C 3 中添加的内容 目的是在使用对象时简化对象的构造
  • 强制抽象类属性由具体类实现

    考虑这个抽象类和实现它的类 from abc import ABC class FooBase ABC foo str bar str baz int def init self self bar bar self baz baz clas
  • 无论如何,在一个 neo4j 实例上有多个数据库?

    从关系数据库的思维方式来看 每个 Neo4j 实例只有一个图形数据库似乎很奇怪 我们的想法是从根开始创建多个子图吗 Thanks 根 节点的概念正在消失 这存在很多问题 其中大部分与节点密度有关 我相信您问题的核心在于数据库设计 以及拥有多
  • Eclipse 类似于:“无法确定 [项目名称]/[文件路径]/[文件名称] 的 URI”

    主要问题 我在 Eclipse Luna 上遇到以下错误 有一天 您上班并尝试启动 Eclipse 并提高工作效率 但是工作台一打开 您就会看到所有文件选项卡都出现错误 如下所示 无法确定 my project path to file f
  • 与 object.prop 相比,使用 `in` 有什么好处?

    我们都看到该功能检测到执行以下操作 var touch function return ontouchstart in window 但我想知道使用它是否还有其他好处in类似这样的操作符 这可以节省一些字节 var touch functi
  • 获取 JavaScript 对象的第一个键名称[重复]

    这个问题在这里已经有答案了 假设我们有以下 JavaScript 对象 ahash one 1 2 3 two 4 5 6 是否有一个函数可以返回给定对象的第一个键名称 从上面的例子我想得到one作为该功能的结果 在 JavaScript
  • netty ChannelInboundHandlerAdapter 将帧裁剪为 ~1500 字节

    我已经实现了一个服务器应用程序 它使用 netty 框架通过 ChannelInblundHandlerAdapter 读取传入的字节 如标题所示 我的问题是 我不定期地从客户端获取内容 我认为这些内容在 1 500 字节后被剪切 例如 在