【问题标题】:Node JS Fork TCP ClientNode JS Fork TCP 客户端
【发布时间】:2020-04-10 00:31:12
【问题描述】:

我对在 Node JS 中分叉 TCP 客户端有疑问。这是场景。

  1. 客户端将连接到服务器(建立?)。
  2. 客户端将第一条消息写入服务器。
  3. 客户端将第二条消息写入服务器。
  4. “写入”方法将无限循环,延迟 5 秒。
  5. 点号 1-4 将被分叉并创建一个新的 TCP 连接(与以前不同),延迟 8 秒。

这是我目前的做法。

// tcp_client.js

const cluster = require('cluster')

if (cluster.isMaster) {
  for (let i = 0; i < 2; i += 1) {
    setTimeout(() => {
      cluster.fork()
    }, 8000) // I expect this will delay between one and another fork
  }
} else {
  console.log(`Connected on ${process.pid}`)
  require('./sender').send()
}
cluster.on('exit', (worker) => {
  console.log('server',`Worker %d died :( ${worker.id}`);
  cluster.fork();
})
// sender.js

const net = require('net')
const send = () => {
  const client = new net.Socket()
  client.connect(8090, 'localhost', () => {
    const firstMessage = 'first_message'
    const secondMessage = 'second_message'
    const write = function () {
      client.write(firstMessage)
      /*
        The reason why I'm using setTimeout() is because if I write it as
        `client.write(firstMessage)
        client.write(secondMessage)`
        The second message won't be sent. Is there any better methods?
      */
      setTimeout(() => {
          client.write(secondMessage)
      }, 1);
    }

    setTimeout(write, 5000) // I expect this will loop infinitely
  })
}

module.exports = { send }

当我运行代码时,fork 不会延迟,消息也不会循环。有什么解决办法吗?谢谢。

【问题讨论】:

  • 您的集群循环仅在 8 秒后安排两个 cluster.fork() 调用。它不会在 8 秒内执行一次,然后再过 8 秒。不确定这是否与您的要求有关。
  • 您最初是从connect 事件处理程序内部调用setTimeout(write, 5000),但您在write() 函数本身中没有这些处理程序之一,因此它不会重复。跨度>
  • 另外,连续进行两次client.write() 调用是完全可以的——两者都会被发送。但是,TCP 可能会将它们组合成同一个数据包。 TCP 是流协议,而不是基于消息的协议。因此,要描述消息之间的差异,您必须解析流。例如,在这种情况下,您可以在每条消息的末尾放置一个\n,并在读取 TCP 流时将其用作消息分隔符。

标签: javascript node.js networking tcp fork


【解决方案1】:

如果您希望两个分叉相隔 8 秒,则需要在 setTimeout() 上设置不同的时间。 setTimeout() 没有阻塞,所以你所有的代码都在安排两个setTimeout()s - 从现在开始每个 8 秒。这将安排一个 8 秒和一个 16 秒:

// tcp_client.js

const cluster = require('cluster')

if (cluster.isMaster) {
  for (let i = 0; i < 2; i += 1) {
    setTimeout(() => {
      cluster.fork()
    }, (i + 1) * 8000);
  }
} else {
  console.log(`Connected on ${process.pid}`)
  require('./sender').send()
}
cluster.on('exit', (worker) => {
  console.log('server',`Worker %d died :( ${worker.id}`);
  cluster.fork();
})

而且,您的编写代码没有循环,因为 setTimeout(write, 5000)connect 事件处理程序内,而不是在 write() 函数内。因此,当connect 事件触发时,它会被调用一次,并且不会再次被调用。如果您希望 write() 重复,则将其放入 write() 函数本身(或使用 setInterval())。

// sender.js

const net = require('net')
const send = () => {
  const client = new net.Socket()
  client.connect(8090, 'localhost', () => {
    const firstMessage = 'first_message'
    const secondMessage = 'second_message'
    const write = function () {
      client.write(firstMessage)

      setTimeout(() => {
          client.write(secondMessage)
      }, 1);

      setTimeout(write, 5000) // I expect this will loop infinitely
    }
    write();

  })
}

module.exports = { send }

另外,像这样连续调用两次client.write() 完全没问题 - 都将被发送。但是,TCP 可能会将它们组合成同一个数据包。 TCP 是流协议,而不是基于消息的协议。因此,要描述消息之间的差异,您必须在读取时解析流。您不应该依赖于到达与发送数据完全相同的数据块的数据。它可以被分解成更小的块,或者多个单独写入的块可以组合成同一个到达的数据包。例如,在这种情况下,您可以在每条消息的末尾放置一个 \n,并在读取 TCP 流时将其用作消息分隔符,这样您就可以单独解析每条传入消息,即使它们被 TCP 组合到相同的数据包。

或者您可以在 TCP 之上使用基于消息的协议(例如 webSocket),它会为您打包和解包成不同的消息,并且只会向您发送一个完整且单独的消息。

【讨论】:

  • 只是想知道为什么 write 函数没有被触发。原来我没有打电话所以应该是const write = function () { client.write(firstMessage) setTimeout(() =&gt; { client.write(secondMessage) }, 1); setTimeout(write, 5000) // I expect this will loop infinitely } write()你的回答太棒了。它完美地工作。谢谢。
  • 是的,我编辑了我的第一次调用它。我第一次立即打电话给它,但如果你愿意,你也可以用setTimeout() 打电话给它。我希望您了解 TCP 数据包和作为流协议的内容,因为任何使用原始 TCP 都必须在其之上构建您自己的协议,并且能够在数据到达时解释或解析它,因为您永远不知道您的数据块是什么会得到。您在接收端获得的块可能与您在另一端发送的大小不同。所有数据都会按顺序到达,但可能是不同的块。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
  • 2012-11-20
  • 1970-01-01
  • 2013-03-28
  • 2016-12-10
相关资源
最近更新 更多