【问题标题】:How to detect if two clients/connections are on the same network (nodeJS / express / socket.io)如何检测两个客户端/连接是否在同一个网络上(nodeJS / express / socket.io)
【发布时间】:2020-11-20 15:56:13
【问题描述】:

我将如何检测一个连接是否与另一个连接在同一网络上?这可能来自使用httpexpresssocket.io 或其他库。

这将用于使用户可以快速加入由同一房屋中的另一个用户托管的游戏。所以其他解决方案也将不胜感激。

【问题讨论】:

  • 如果他们在同一所房子但使用不同的移动网络怎么办?或者一个在WiFi上,另一个在手机上?他们不能玩吗? :-)

标签: javascript node.js express http socket.io


【解决方案1】:

通过一些研究,我找到了一种通过查看公共 IP 地址来执行此操作的方法。我找到了一个有用的免费 API:http://ipify.org,但我想保留它在服务器端。 This question 回答了如何从请求中获取 IP,但我决定使用 request-ip

对这种方法有什么想法吗?显然,两个网络具有相同 IPv4 地址的可能性非常低。

Here 是一个工作示例,下面是代码。

index.js

const path = require('path');
const express = require("express");
const socket  = require('socket.io');
const requestIp = require('request-ip');

const app = express();
const server = app.listen(8080, () => console.log(`listening on port ${server.address().port}`));

const io = socket(server);

let networks = {};

app.get('/', (req, res) => {
  res.sendFile( path.join( __dirname, 'index.html') );
});

io.on('connection', function (socket) {
  let clientIP = requestIp.getClientIp(socket.request);
  console.log('New connection from ' + clientIP);
  
  if( networks[clientIP] == undefined ){ networks[clientIP] = []; };
  let network = networks[clientIP];
  
  network.push(socket);
  updateNetwork(network);
  
  socket.on('disconnect', function () {
    console.log('Disconnected ' + clientIP);

    network.splice(network.indexOf(socket), 1);
    updateNetwork(network);
  });
  
});

function updateNetwork(network){
  for( let socket of network ){
    socket.emit( 'network-clients', network.length );
  }
}

index.html

<html>
  <head>
    <meta charset="UTF-8">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.js"></script>
    
    <script src="script.js" type="text/javascript"></script>
  </head>
  <body>
    <p>
      Clients Connected on the same network: <span id="network-clients">loading...</span>
    </p>
  </body>
  <script>
    let socket = io.connect(window.location.origin);

    socket.on('network-clients', (data) => {
      document.getElementById('network-clients').innerHTML = data;
    });
  </script>
</html>

【讨论】:

    【解决方案2】:

    您不能,因为您无法确定子网。

    有点像有门牌号,但没有街道。

    【讨论】:

    • 有没有办法通过比较IP地址来检查?我以前看过投票等网站,在同一网络上再次访问它不会让你再次投票。
    • 你当然可以查看IP地址但无法知道子网;所以无法知道原始网络。假设 1.2.3.4 与 1.2.3.5 在同一个网络上是不好的做法,因为 1.2.3.5 可能是一个完全不同的网络。
    【解决方案3】:

    网络配置太复杂了,在某些(甚至很多)情况下是不透明的¹,您无法为此使用网络。此外,两个人可以在同一个房子里,但使用不同的网络(不同的移动网络;一个在 WiFi 上,另一个在移动网络上;甚至——在极少数情况下我认为——不同的 WiFi 网络)。

    改为使用现有技术:用户 A 创建某种唯一的游戏标识符(或您的系统创建)并将该信息提供给用户 B,以便用户 B 可以加入游戏。 (您可能希望用户 A 在允许他们进入之前对其进行确认。)该主题有上百万种变体,但这是经过时间考验的基本方法。


    ¹ 从浏览器的角度来看是不透明的。记住浏览器会发送 Express 在服务器上看到的信息。

    【讨论】:

    • 使用唯一的游戏标识符将成为默认加入方式,但这种检查它们是否在同一个网络上的想法将是一个易于使用的功能。
    • @JaredParker - 啊,有道理。也许如果您在帐户或其他东西之间建立了联系。 (但您可能也想到了这一点 - 仍然没有改变这样一个事实,如果两个人并排站在一起并且没有事先联系以查找“附近”的游戏会很方便。)也许有一天web bluetooth 会成为一件事。
    • 我们只能希望。感谢您的帮助和想法:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 2013-10-20
    • 2012-05-17
    相关资源
    最近更新 更多