【问题标题】:FD_SET and FD_ISSET macros written in javascript用 javascript 编写的 FD_SET 和 FD_ISSET 宏
【发布时间】:2016-07-19 10:08:45
【问题描述】:

我和我的朋友前段时间研究过这个问题。它适用于 js-ctypes。在 Linux 中,有这些宏用于处理将文件描述符(uint32)列表添加到字节数组:FD_SETFD_IS_SET。文档在这里 - http://linux.die.net/man/2/select

我想知道是否有人能够检查我是否做对了,或者是否有人知道有人在 javascript 中做过这件事?我需要完成对大端和小端的 32 位/64 位支持,但如果它已经存在,我很乐意看到它,因为我们在处理这个问题时有很多不确定性。

这是代码,fd_set_get_idx 是这一切所基于的辅助函数。

var MACROS = {
        fd_set_set: function(fdset, fd) {
            let { elem8, bitpos8 } = MACROS.fd_set_get_idx(fd);
            console.info('elem8:', elem8.toString());
            console.info('bitpos8:', bitpos8.toString());
            fdset[elem8] = 1 << bitpos8;
        },
        fd_set_isset: function(fdset, fd) {
            let { elem8, bitpos8 } = MACROS.fd_set_get_idx(fd);
            console.info('elem8:', elem8.toString());
            console.info('bitpos8:', bitpos8.toString());
            return !!(fdset[elem8] & (1 << bitpos8));
        },
  fd_set_get_idx: function(fd) {
            if (osname == 'darwin' /*is_mac*/) {
                // We have an array of int32. This should hopefully work on Darwin
                // 32 and 64 bit.
                let elem32 = Math.floor(fd / 32);
                let bitpos32 = fd % 32;
                let elem8 = elem32 * 8;
                let bitpos8 = bitpos32;
                if (bitpos8 >= 8) {     // 8
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 16
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 24
                    bitpos8 -= 8;
                    elem8++;
                }

                return {'elem8': elem8, 'bitpos8': bitpos8};
            } else { // else if (osname == 'linux' /*is_linux*/) { // removed the else if so this supports bsd and solaris now
                // :todo: add 32bit support
                // Unfortunately, we actually have an array of long ints, which is
                // a) platform dependent and b) not handled by typed arrays. We manually
                // figure out which byte we should be in. We assume a 64-bit platform
                // that is little endian (aka x86_64 linux).
                let elem64 = Math.floor(fd / 64);
                let bitpos64 = fd % 64;
                let elem8 = elem64 * 8;
                let bitpos8 = bitpos64;
                if (bitpos8 >= 8) {     // 8
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 16
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 24
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 32
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 40
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 48
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 56
                    bitpos8 -= 8;
                    elem8++;
                }

                return {'elem8': elem8, 'bitpos8': bitpos8};
            }
        }
};

【问题讨论】:

  • 好老的&gt;&gt;&lt;&lt;&amp;|有什么问题
  • 另外,可以在那里使用for 循环...
  • 我不明白你是想模仿FD_XXX 函数还是必须遵守某些规定。 JS,特别是 ES6,如果你想使用它们,有 DataViewtyped arrays。无论如何,如果FD_SET(i, set) 的语义只是set[i] = i,我认为从头开始以任何字节序或大小实现它都没有任何问题。你能澄清一下吗?这个fdset[elem8] = 1 &lt;&lt; bitpos8 也可能是错误的。
  • 非常感谢 @Margaret 和 Anti - 是的,我们试图模仿 FD_XXX,不符合任何规定。老实说,这是几年前的事了,如果语义正确,我不记得了。我不认为是,因为我刚才使用这个时,上面代码中的索引idx 是不同的。 (这就是为什么我在这个问题中添加了 linux 和 c 的标签。我知道它可能会被关闭,但我没有其他人可以问谁有这种知识。我所有的技能都允许使用这些功能)

标签: javascript c linux macros jsctypes


【解决方案1】:

我将确定字节顺序和字长的负担留给您。
下面的代码模拟 FD_XXX 函数并让您指定字节序和大小。

<!doctype>
<html>
    <head>
        <script>
            var SIZE_32 = 4
            var SIZE_64 = 8

            var LITTLE_ENDIAN = [0, 1, 2, 3, 4, 5, 6, 7];
            var BIG_ENDIAN = [7, 6, 5, 4, 3, 2, 1, 0];

            function fdset(setSize, endianness, size)
            {
                var buffer = new Uint8Array(div(setSize + 7, 8));



                function div(a, b)
                {
                    return Math.floor(a / b);
                }

                function make_index(index)
                {
                    return div(index, 8 * size) * size + endianness[div(index % (8 * size), 8)] % size;
                }

                buffer.set_bit = function(index)
                {
                    buffer[make_index(index)] |= 1 << (index % 8);
                };

                buffer.clear_bit = function(index)
                {
                    buffer[make_index(index)] &= ~(index % 8);
                };

                buffer.get_bit = function(index)
                {
                    return buffer[make_index(index)] & 1 << (index % 8);
                };

                buffer.zero = function()
                {
                    buffer.fill(0);
                }


                return buffer;
            }

            function FD_SET(fd, fdset)
            {
                fdset.set_bit(fd);
            }

            function FD_ISSET(fd, fdset)
            {
                return !!fdset.get_bit(fd);
            }

            function FD_CLR(fd, fdset)
            {
                return fdset.clear_bit(fd);
            }

            function FD_ZERO(fdset)
            {
                return fdset.zero();
            }


        </script>
    </head>
    <body>
        <script>
            var s = fdset(128, LITTLE_ENDIAN, SIZE_64);

            //s in an Uint8Array

            console.log(s);

            FD_SET(0, s);    //Byte 0 = 1
            FD_SET(9, s);    //Byte 1 = 2
            FD_SET(18, s);   //Byte 2 = 4
            FD_SET(27, s);   //Byte 3 = 8
            FD_SET(36, s);   //Byte 4 = 16
            FD_SET(45, s);   //Byte 5 = 32
            FD_SET(54, s);   //Byte 6 = 64
            FD_SET(63, s);   //Byte 7 = 128

            FD_SET(120, s);  //Byte 15 = 1
            FD_SET(113, s);  //Byte 14 = 2
            FD_SET(106, s);  //Byte 13 = 4
            FD_SET(99, s);   //Byte 12 = 8
            FD_SET(92, s);   //Byte 11 = 16
            FD_SET(85, s);   //Byte 10 = 32
            FD_SET(78, s);   //Byte 9 = 64
            FD_SET(71, s);   //Byte 8 = 128

            console.log(s);

            //64 bits, BE: [128, 64, 32, 16, 8, 4, 2, 1, 1, 2, 4, 8, 16, 32, 64, 128]
            //64 bits, LE: [1, 2, 4, 8, 16, 32, 64, 128, 128, 64, 32, 16, 8, 4, 2, 1]
            //32 bits, BE: [8, 4, 2, 1, 128, 64, 32, 16, 16, 32, 64, 128, 1, 2, 4, 8]
            //32 bits, LE: [1, 2, 4, 8, 16, 32, 64, 128, 128, 64, 32, 16, 8, 4, 2, 1]
        </script>
    </body>
</html>

fdset 函数返回一个 Uint8Array,您可以将其传递给本机函数或进一步详细说明。
setSize 设置支持的最大文件描述符。


注意 js ctypes 已经有一个数组类型和通常的 [U]intXX_t 类型在本机字节序中,可惜没有一个类型可以映射到基于平台的 32/64 位整数和没有sizeof operator2,所以你仍然需要执行外部检查来检测字长。

使用 ctypes 会更自然。
供参考,hereFD_XXX 函数的官方实现。

您可以使用 uint32/64_tarray 类型的单个字段定义 struct
然后模仿 C 源代码的行为,在需要时小心使用UInt641 并避免使用shifts


1 JS 只有双精度数,这些数字有 53 位尾数、10 位指数和 1 位符号。当使用位运算符时,双精度数被转换为整数,因为它是指定精度的尾数(指数只是一个比例,符号只是一个倒数),这个数字最多可以携带与 53 位一样多的信息数字。

2 据我所知,我根本不是 js ctypes 方面的专家。

【讨论】:

  • 非常感谢您的努力!我记得上次在做这个的时候,我沉迷于阅读这些链接 - gist.github.com/Noitidart/5ddc5fe43dd9b0d5a207d0f70d72efc4 - 我现在要检查你的代码! :)
  • @Noitidart 欢迎您。仔细检查一下,我不确定我是否真的了解您的需求!
  • @Noitidart 我现在在工作。使用您认为相关的所有详细信息编辑问题。如果我能找到解决方案,我会更新我的答案:)
  • @Noitidart 您可以将FDSET 视为一个集合,可以容纳从0 到setSize 的所有描述符。只需将 Y 传递为 setSize 就可以了。
  • @Noitidart 我查看了实现 FD_XXX 的 Linux 源代码。它有效地使用unsigned long 的数组而不是字节数组。我稍后会写新的答案,因为这会影响字节序和字长。请不接受此答案,以便我删除它。谢谢:)
猜你喜欢
  • 1970-01-01
  • 2011-02-02
  • 2016-02-16
  • 2012-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多