4

node.js 中是否有类似 setsockopt/getsockopt 的套接字选项操作功能?

4

3 回答 3

7

我正在扩展socketpairwhich show 留下的评论getsockopt。您可以通过使用ffi和来完成此操作ref。我已经重新格式化它以使其易于操作。

我编辑了我的评论,因为我必须进行一些更改才能使代码在 Linux 和 Win32 上都可以工作。我必须为 Windows 创建一个节点库来获取套接字句柄并将其传递给setsockopt. 请注意,Linux 和 Windows 可能有不同的套接字选项值

编辑:这是我正在使用的一段清理后的生产代码:

var net = require("net");
var ffi = require("ffi");
var ref = require("ref");
var getSocketHandleAddress;

var SOL_SOCKET = 0x1;
var SO_OOBINLINE = 0xA;
var _setsockopt;

if (process.platform == "win32") {
  SOL_SOCKET = 0xffff;
  SO_OOBINLINE = 0x0100;
}

var setSocketOption = function (handle, level, option, value) {
  if (!_setsockopt) {
    var library;
    var paramTypes;
    if (process.platform === "win32") {
      library = "ws2_32.dll";
      paramTypes = [
        ref.types.int,
        ref.types.int,
        ref.types.int,
        ref.refType(ref.types.void),
        ref.types.int
      ];
    } else {
      paramTypes = [
        ref.types.int,
        ref.types.int,
        ref.types.int,
        ref.refType(ref.types.void),
        ref.refType(ref.types.int)
      ];
    }
    var lib = new ffi.DynamicLibrary(library);
    _setsockopt = ffi.ForeignFunction(
      lib.get("setsockopt"),
      ref.types.int,
      paramTypes);
  }
  var refType;
  var length;
  if (typeof value === "boolean") {
    refType = ref.types.bool;
  } else {
    refType = ref.types.int;
  }
  if (process.platform !== "win32") {
    return _setsockopt(
      handle.fd, 
      level, 
      option, 
      ref.alloc(refType, value), 
      ref.alloc(ref.types.int, refType.size)
    );
  }
  if (!getSocketHandleAddress) {
    getSocketHandleAddress = require("getsockethandleaddress");
  }
  return _setsockopt(
    getSocketHandleAddress.getAddress(handle),
    level,
    option,
    ref.alloc(refType, value), 
    refType.size
  );

};

var tcpserver = net.createServer(function (socket) {
  var ret = setSocketOption(socket._handle, SOL_SOCKET, SO_OOBINLINE, true);
  if (ret !== 0) {
    console.error("OOB Inline socket option failed: " + ret);
  }
});
于 2016-08-26T19:13:30.820 回答
4

这是我的getsockopt:

var ffi = require('ffi');
var net = require('net');
var StructType = require('ref-struct');
var ref = require('ref');

var current = ffi.Library(null, {
  'getsockopt': [ 'int', [ 'int', 'int', 'int', 'pointer', 'pointer']],
  'ntohs': ['uint16', ['uint16']],
//    const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

});

var SOL_IP = 0;
var SO_ORIGINAL_DST = 80;
var AF_INET = 2;

var sockaddr_in = StructType([
    ['int16', 'sin_family'],
    ['uint16', 'sin_port'],
    ['uint32', 'sin_addr'],
    ['uint32', 'trash1'],
    ['uint32', 'trash2'],
]);

function get_original_dst(client) {
    var dst = new sockaddr_in;
    var dstlen = ref.alloc(ref.types.int, sockaddr_in.size);
    var r = current.getsockopt(client._handle.fd, SOL_IP, SO_ORIGINAL_DST, dst.ref(), dstlen);
    if (r === -1)
        throw new Error("getsockopt(SO_ORIGINAL_DST) error");
    if (dst.sin_family !== AF_INET)
        throw new Error("getsockopt(SO_ORIGINAL_DST) returns unknown family: " + dst.sin_family );

    // TODO: inet_ntop. inet_ntoa is _UNSAFE_
    var ipaddr = dst.ref(); ipaddr = ipaddr[4] + "." + ipaddr[5] + "." + ipaddr[6] + "." + ipaddr[7];

    return [ipaddr, current.ntohs(dst.sin_port)];
}

module.exports.get_original_dst = get_original_dst;
于 2015-04-14T19:07:56.200 回答
-1

有点晚了,但这是 npm 上的一个 pacakge https://www.npmjs.com/package/net-keepalive

提供对 TCP_KEEPIDLE、TCP_KEEPINTVL、TCP_KEEPCNT 等套接字选项的高级访问

var Net = require('net')
  , NetKeepAlive = require('net-keepalive')
;

// Create a TCP Server
var srv = Net.createServer(function(s){>
  console.log('Connected %j', s.address())
  // Doesn't matter what it does
  s.pipe(s)
});

// Start on some port
srv.listen(1337, function(){
  console.log('Listening on %j', srv.address())
});

// Connect to that server
var s = Net.createConnection({port:1337}, function(){
  console.log('Connected to %j', s.address())

  //IMPORTANT: KeepAlive must be enabled for this to work
  s.setKeepAlive(true, 1000)

  // Set TCP_KEEPINTVL for this specific socket
  NetKeepAlive.setKeepAliveInterval(s, 1000)

  // and TCP_KEEPCNT
  NetKeepAlive.setKeepAliveProbes(s, 1)
});
于 2016-06-12T15:47:17.503 回答