【问题标题】:Can I get my IP address in a chrome app without using an external service?我可以在不使用外部服务的情况下在 chrome 应用程序中获取我的 IP 地址吗?
【发布时间】:2015-02-16 11:25:26
【问题描述】:

我正在构建一个chrome app 并通过chrome socket api 创建一个UDP 套接字

有没有办法在不使用外部服务的情况下检索您自己的IP 地址? 我所说的“自己的 IP 地址”是什么意思:clientserver 都在同一个网络上。 chrome 应用需要使用自己的本地 IP 地址响应 UDP 广播

实际上有一个chrome socket API 用于该用例。但不幸的是,我只收到以下回调对象:Object {paused: false, persistent: false, socketId: 17},它错过了localAddress 属性。根据documentation,它是SocketInfo 对象中的(可选) 属性。这实质上是我正在运行的代码:

chrome.sockets.udp.create({}, function(socketInfo){
    chrome.sockets.udp.getInfo(socketInfo.socketId, function (detailedInfo){
        ipAddress = detailedInfo.localAddress;
        console.debug(detailedInfo); // containts no `localAddress`
    });
});

我也不认为我缺少任何manifest-permissions,因为API documentation 中没有描述特殊权限。这是我使用的:

"sockets": {
  "udp": {
    "send": "*",
    "bind": "*"
  }
}

当我使用 Python 时,我可以通过以下方式实现该目标:

import socket
ip_address = socket.gethostbyname(socket.gethostname())

任何帮助都会很棒!

【问题讨论】:

  • 如果调用机器有多个网络接口,gethostbyname()可以返回多个本地IP。
  • 错误 - 它只会返回一个 IP 地址。 Python 会选择操作系统提供的接口列表中当前“最高”的接口。这正是我想要的,99% 的其他用户也是如此。
  • 相信我,操作系统列表中的“最高”接口并不总是正确的,除此之外,gethostbyname() 执行 DNS 查找,在某些情况下可能会报告意外结果,即使是本地主机名。 gethostbyname(gethostname()) 组合多年来一直被广泛滥用,因为人们误以为它总是返回本地 IP,但事实并非如此。这就是network.getNetworkInterfaces()存在的原因,在不涉及DNS的情况下获得正确准确的本地IP。

标签: javascript sockets google-chrome google-chrome-app


【解决方案1】:

您提供给udp.create() 的回调在最初创建套接字时调用,而不是在套接字接收数据包时调用。在创建时,套接字尚未与任何localAddresslocalPort 关联。您必须调用udp.bind() 来建立特定的localPort(以及可选的特定localAddress),套接字将在其上侦听数据包。如果您将bind() 改为"0.0.0.0",则套接字将侦听所有 本地IP。

当一个新的数据包到达时,udp.onReceive 事件被触发。数据包由特定的localAddress 接收,但是 Chrome API 不提供直接查询哪个localAddress 接收数据包的方法(底层recvfrom() 套接字函数不提供该信息)。要发现接收本地 IP,您必须:

  1. 将套接字绑定到特定的localAddress,因为这将是唯一可以触发该套接字的onReceive 事件的本地 IP。

  2. 检查chrome.system.network.getNetworkInterfaces() 报告的接口列表。如果报告了1个接口,那将是接收所有数据包的接口,所以你可以使用它的address。但是,如果报告了 2 个以上的接口,则必须从数据包的 remoteAddress 中解析网络前缀,并将该值与每个报告的接口的前缀进行比较,直到找到匹配项(假设发送方正在从同一网络子网广播本地计算机已连接到,而不是跨子网边界广播)。

话虽如此,只有当您需要将本地 IP 放入广播回复的数据负载中时,所有这些才是相关的。假设有 3 个本地接口,并且在接口 2 上接收到广播包。用接口 1 或 3 的localAddress 回复显然是错误的,因为它们与广播者在不同的网络上。但是,如果您不需要将您的localAddress 放入回复的有效负载中,那么广播公司只需查看回复的remoteAddress 即可知道您的 IP 地址是什么。然后你根本不需要弄清楚你的本地IP,当你发送回复到你收到广播的remoteAddress/remotePort时,操作系统会为你处理一切。

【讨论】:

    【解决方案2】:

    原来我一直在使用错误的 API。对于我的用例,我需要使用chrome.system.network.getNetworkInterfaces

    这将返回一个包含所有接口及其IP地址的数组。

    这是我的示例代码:

    chrome.system.network.getNetworkInterfaces(function(interfaces){
        console.log(interfaces);
    });
    

    清单权限:

    "permissions": [
      "system.network"
    ],
    

    考虑到 cmets,提供完美的解决方案并不容易,因为必须找到 UDP 端口的正确接口。

    此时,完美匹配接口的唯一方法必须是bindgetNetworkInterfaces 给出的所有接口的所有地址。然后您就可以准确地知道是哪个接口用来接听电话的,并且您可以用正确的 IP 地址进行响应。

    【讨论】:

    • 这并不能告诉你哪个接口实际上正在接收 UDP 广播数据包。回复时,您应该指定接收数据包的接口的 IP,因为那是连接到发生广播的 LAN 的接口。
    • 没错——总得有人想出一个完美的解决方案。对于我来说,界面很明显,这个解决方案对我有用。如果我能找到更好的接口匹配解决方案,我会发布它 - 或者就此而言认可其他人的解决方案......
    • 如果机器安装了多个接口,您的解决方案将失败,这在当今很常见(虚拟机、多个网络、WiFi 与有线网络等)。
    • 正如我所说 - 我理解你的反对意见。解决方案并不适合所有人。但至少在我的情况下(也有多个接口)很明显,根据发送者哪个接口对我来说是正确的。欢迎您找到更好的解决方案。与此同时,我认为有些人已经对这篇文章表示感谢。它也是有效的,因为它解决了我的问题的基本部分 - 以与 Python 相同的方式在不使用外部服务的情况下找到自己的 IP 地址。现在最棘手的部分是让其他人推断出正确的接口。
    • 查看我的答案以获得可能的解决方案。
    【解决方案3】:

    未连接的套接字还没有本地地址,除非它专门绑定到地址。一旦套接字连接(TCP)或您通过套接字(UDP)发送数据,它只会获取本地和远程地址。它只获取本地机器的 IP 地址,而如果您在某个 NAT 路由器后面(即大多数家庭用户),外部服务会看到路由器面向互联网的外部地址。

    【讨论】:

    • 我想你的回答可能已经给了我我想知道的东西。我在本地网络中运行此应用程序(客户端和服务器都将在同一网络上)。我收到一条 UDP 广播消息,我将用我自己的 IP 地址对其进行响应。所以这对我来说已经足够充分了——一旦我知道它是否有效,我就会回信。
    • 如此接近...我确实等待getInfo 电话,直到我收到第一个包裹。是的,它现在终于有了属性localAddress。不幸的是它的0.0.0.0 - 即使我在我的send 之后回来查看......现在完整的对象是Object {localAddress: "0.0.0.0", localPort: 22222, paused: false, persistent: false, socketId: 21}
    • 这是因为你的 UDP 套接字在创建时没有绑定到任何特定的本地 IP,因此它会侦听并接收所有本地 IP 上的数据包。这就是"0.0.0.0" 所代表的。
    猜你喜欢
    • 2015-04-19
    • 2014-08-31
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    相关资源
    最近更新 更多