将HTTP升级重定向到另一个实例上的WebSocket。

huangapple go评论126阅读模式
英文:

Redirect HTTP upgrade to a websocket on another instance

问题

以下是您提供的内容的中文翻译:

我使用Node集群,在每个工作进程上都有一个运行中的WebSocket服务器。主进程有一个运行中的HTTP服务器。

在主HTTP服务器上,我想要一个HTTP升级调用的实现,它将连接调用者到特定的WebSocket。

为什么?我希望能够将用户连接到正确的WebSocket,但我想通过一个单一的入口点localhost:8000来实现。连接到localhost:8000可能会将您无缝地连接到localhost:8001。

我的想法是调用Upgrade并带有参数,例如:

  1. wscat -c ws://localhost:8000/?id=5

这个调用应该传递到主进程,主进程将转发此升级调用并与localhost:8005建立连接。

我以为我可以简单地使用worker.send()将升级参数转发给工作进程,但这确实不起作用,我在工作进程中接收到的对象缺少很多东西,这可能是我不了解的JS基础知识。

这是我的天真实现:

  1. var http = require('http');
  2. var cluster = require('cluster')
  3. var ws = require('ws');
  4. var NumberOfInstances = 5;
  5. if (cluster.isMaster) {
  6. var forks = []
  7. for (var i=0; i < NumberOfInstances; i++) {
  8. forks.push(cluster.fork());
  9. }
  10. server = http.createServer((req, res) => {
  11. res.writeHead(200);
  12. }).listen(8000);
  13. server.on('upgrade', (request, socket, head) => {
  14. var params = new URL(`https://localhost:8000${request.url}`);
  15. var id = parseInt(params.searchParams.get('clusterId')) - 1;
  16. // How do I forward upgrade??
  17. forks[id].send({r: request, s: socket, h: head});
  18. })
  19. } else {
  20. portStr = `800${cluster.worker.id}`;
  21. wss = new ws.WebSocketServer({
  22. port: portStr
  23. });
  24. wss.on('connection', (ws, request) => {
  25. console.log(`${cluster.worker.id} got connection.`);
  26. })
  27. process.on('message', masterMessage => {
  28. // This absolutely doesn't work.
  29. wss.handleUpgrade(masterMessage.r, masterMessage.s, masterMessage.h, (ws) => {
  30. wss.emit('connection', ws, masterMessage.r);
  31. })
  32. })
  33. }

希望这有助于理解您的代码和问题。如果您有任何进一步的问题,请随时提出。

英文:

I use Node cluster, on each worker there's a running websocket server. Master has a HTTP server running.

On the Master HTTP server I want a HTTP Upgrade call implementation, that will connect the caller to a specific web socket.

Why? I want to be able to connect user to a correct websocket, but I want to do it through a single entry point being localhost:8000. Connecting to localhost:8000 might connect you to localhost:8001 seamlessly.

My idea was to call Upgrade with a parameter like:

  1. wscat -c ws://localhost:8000/?id=5

This call should go to the Master, and master would forward this upgrade call and make connection with localhost:8005.

I thought I could simply forward the upgrade params to the worker with worker.send(), but this doesn't really work, objects I receive in the worker miss a lot of things, it's probably some basics of JS I don't know about.

Here's my naive implementation:

  1. var http = require(&#39;http&#39;);
  2. var cluster = require(&#39;cluster&#39;)
  3. var ws = require(&#39;ws&#39;);
  4. var NumberOfInstances = 5;
  5. if (cluster.isMaster) {
  6. var forks = []
  7. for (var i=0; i &lt; NumberOfInstances; i++) {
  8. forks.push(cluster.fork());
  9. }
  10. server = http.createServer((req, res) =&gt; {
  11. res.writeHead(200);
  12. }).listen(8000);
  13. server.on(&#39;upgrade&#39;, (request, socket, head) =&gt; {
  14. var params = new URL(`https://localhost:8000${request.url}`);
  15. var id = parseInt(params.searchParams.get(&#39;clusterId&#39;)) - 1;
  16. // How do I forward upgrade??
  17. forks[id].send({r: request, s: socket, h: head});
  18. })
  19. } else {
  20. portStr = `800${cluster.worker.id}`;
  21. wss = new ws.WebSocketServer({
  22. port: portStr
  23. });
  24. wss.on(&#39;connection&#39;, (ws, request) =&gt; {
  25. console.log(`${cluster.worker.id} got connection.`);
  26. })
  27. process.on(&#39;message&#39;, masterMessage =&gt; {
  28. // This absolutely doesn&#39;t work.
  29. wss.handleUpgrade(masterMessage.r, masterMessage.s, masterMessage.h, (ws) =&gt; {
  30. wss.emit(&#39;connection&#39;, ws, masterMessage.r);
  31. })
  32. })
  33. }

答案1

得分: 2

根据文档,你需要将套接字处理程序作为worker.send方法的第二个参数发送。

所以你应该这样做,

  1. forks[id].send({ headers: request.headers, method: request.method, head: head }, socket); //socket is in second argument

在你的子进程message事件处理程序中,这样做,

  1. process.on('message', (request, socket) => {
  2. wss.handleUpgrade(request, socket, request.head, (ws) => {
  3. wss.emit('connection', ws, request);
  4. })
  5. })

查看这个示例,了解如何将套接字对象作为参数传递。

英文:

According to docs, you are required to send the socket handler as a second argument to the worker.send method.

So you should do this instead,

  1. forks[id].send({ headers: request.headers, method: request.method, head: head }, socket); //socket is in second argument

and in your child message event handler, do this,

  1. process.on(&#39;message&#39;, (request,socket) =&gt; {
  2. wss.handleUpgrade(request, socket, request.head, (ws) =&gt; {
  3. wss.emit(&#39;connection&#39;, ws, request);
  4. })
  5. })

Look at this example to see how to pass socket object as an argument.

huangapple
  • 本文由 发表于 2023年6月15日 05:00:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76477500.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定