连接两个socket.io客户端(建立一个跨浏览器的socket到socket连接)

4
我想知道是否有办法使用socket.io-client在两个浏览器之间建立P2P连接(但我愿意使用其他任何可以达到此目的的工具)。
当前,这两个浏览器都连接到使用Express处理HTTP请求的node.js应用程序,该应用程序存储了两个客户端的IP地址(当本地运行时还包括端口)。我希望添加第三个连接,将两个客户端(称为A和B)直接链接起来,以便消息/数据可以直接从一个客户端传递到另一个客户端,而不经过node.js服务器。
这可行吗?如果是这样,怎么做呢?
到目前为止,我已经尝试使用以下代码连接两个客户端(称为A和B):
客户端A:
A_to_server_socket = io();

A_to_server_socket.on('p2p', function(address_B){

    A_to_B_socket = io(address_B); // Instantiates a new socket

    A_to_B_socket.on('connect', function() {
            console.log('Connected!');
    });  
});

我对客户端B的代码不确定。然而,我尝试过:
  1. 重复以上代码以连接B,使用B自己的地址(覆盖默认连接到服务器的地址)

  2. 重复以上代码以连接B,这次使用A的地址

  3. 让B_to_server_socket监听新的连接事件

然而,无论B的代码如何,在运行A的代码时,我都会在Firefox上遇到“跨源请求被阻止”错误,在Chrome上则出现“Failed to load resource: net::ERR_CONNECTION_REFUSED”,随后是“net::ERR_CONNECTION_REFUSED”。
欢迎提供任何解决方案的提示或更好地理解问题和套接字工作方式的见解。

客户端的socket.io库不会监听传入的连接,即使它这样做了,传入的连接也会被浏览器所在的防火墙所阻止。WebSockets的整个原则是客户端向服务器连接出站,这就是如何处理防火墙的方式。服务器(或另一个客户端)无法连接到客户端。 - jfriend00
不,没有这样的方法,因为浏览器不会监听新连接。出于安全原因,它不会为webSockets执行此操作。它只建立出站连接。为了直接连接两个端点,一方必须监听新连接,因此如果没有浏览器在监听,则无法在两个浏览器之间建立直接的webSocket连接 - 这就是TCP的工作方式。您可以将每个浏览器连接到中介服务器并通过服务器交换数据。 - jfriend00
好的。感谢您的澄清。 - bsuire
此外,是否有任何方法可以绕过这个限制,例如让客户端A连接到服务器,然后将其(套接字参数)传递给B,或者用服务器IP地址覆盖客户端数据包的“源”字段?如果可以使其工作,我不介意动手。 :) - bsuire
你现在使用的是浏览器(带有其相关的安全限制)。你没有任何可用工具来直接建立P2P连接,而TCP协议旨在防止外部代理重新建立现有TCP连接。数据包可以被外部代理重写以强制它们去不同的地方,但是它们仍然会通过你的服务器之一(进行重写)所以为什么要费这个劲呢? - jfriend00
显示剩余3条评论
3个回答

3
我将尝试把我的评论总结成一个回答。
在TCP中,当一个端点A连接到另一个端点B时就建立了一个连接。要连接到端点B,这台主机必须“侦听”来自其他主机的传入连接。在典型的Web请求中,浏览器与Web服务器建立TCP连接,这是因为Web服务器正在特定端口上监听传入请求,当其中之一请求进来时,它会接受传入请求以建立活动的TCP连接。所以,你必须有一个端点发起请求,另一个端点监听请求。
出于各种安全原因,浏览器本身不会“监听”传入连接,因此您无法直接连接到它们。它们只允许您对互联网上的其他侦听代理进行出站连接。因此,如果浏览器从未监听传入webSocket连接,则无法建立真正的点对点(例如,浏览器到浏览器的)webSocket连接。
此外,TCP的设计使得你不能让两个浏览器都连接到一个共同的服务器,然后通过这样的方式将它们的管道连接起来,以便这两个浏览器直接互相连通。TCP就是不起作用的。可以通过在中间加入代理程序将一个客户端的数据包转发到另一个客户端,但是中间的代理程序不能简单地将两个TCP连接连接在一起,以便数据包可以直接从一个客户端到另一个客户端传输(不再通过服务器),就像消防员连接两根消防水管那样。TCP就是不起作用的。可能有一些复杂的方案,涉及重写数据包头部,使得从端点A发送的数据包被转发到端点B,看起来像是来自服务器,但这仍然需要服务器作为中间人或代理。
解决这个问题的常规方法是让每个浏览器连接到一个共同的服务器,并使服务器充当中间人或交通警察,转发来自一个浏览器的数据包到另一个浏览器。
现有的P2P应用程序(在浏览器之外)通过让每个客户端实际上监听传入连接(表现得像一个服务器)来工作,以便另一个客户端可以直接连接到它们。P2P本身比此更加复杂,因为需要有一种方法发现要连接的IP地址(因为客户端通常不在DNS中),而且通常有防火墙阻挡了连接,需要两端之间的合作才能让防火墙允许传入的连接。但是,不幸的是,使用纯JavaScript编写的浏览器不允许您执行监听传入连接的操作。

0
你可以考虑使用https://github.com/socketio/socket.io-p2p
这个模块提供了一种简单可靠的方式来建立WebRTC连接,并使用事件(即socket.io协议)进行通信。
Socket.IO用于传输信令数据,并作为WebRTC PeerConnection不支持的客户端的备用方案。
简而言之,这将允许你使用WebRTC p2p库在服务器上协调连接的客户端,并从那里继续进行基本上是点对点的websocket/socket.io-client连接。
这将允许在基本上是socket.io上进行点对点的音频/视频/文本/二进制通信。
只是提一下,Google Chrome和其他浏览器会阻止非HTTPS的音频/视频播放(除了localhost的URL),这是出于安全考虑。虽然有点离题,但如果在开发或测试过程中遇到这个问题,我建议您设置一个VPS(Digital Ocean的droplet大约6美元/月)。设置一个Nginx反向代理:我们将使用SSH将您的开发机器端口3000连接到服务器的端口3000。因此,配置Nginx来获取端口3000,并通过端口443以HTTPS方式传输。然后使用Let's Encrypt获取免费的TLS证书,并将其安装到Nginx上。最后,使用SSH将您的开发机器的HTTP端口3000转发到服务器的端口3000。确保服务器上的任何防火墙都对端口443开放。现在,您和其他人都可以通过合法的域名以HTTPS方式进行本地开发。
祝好运!

0

目前 "socket.io-client" 并不支持 "两个浏览器之间的连接"。

但是,你可以通过以下方式实现 "两个浏览器连接到运行 Express 服务的 Node.js 应用程序,并跟踪这两个客户端的 IP 地址(以及在本地运行时的端口)。"

如果您想要在两个浏览器之间建立 P2P 连接,可以参考以下步骤:

  1. 当您得到客户端 A 的连接时,请加入一个房间 "P2P"
  2. 当您得到客户端 B 的连接时,请加入一个房间 "P2P"
  3. 为了在客户端 A 和客户端 B 之间进行交换,请使用

    socket.broadcast.to('P2P').emit("message", "Good Morning");

希望这可以帮助到您。


那么这就是我已经设置好的内容。现在我想要实现的是两个浏览器之间真正的P2P连接,以便通过该连接发送的数据不再通过浏览器中转。如果有可能的话。 - bsuire

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接