如何访问 NAT 路由器后面的 ServerSocket?

How do I access a ServerSocket behind an NAT router?

目标

我正在为 android 制作一个聊天应用程序,目前正在测试 2 个 phones,它们最终必须为几千个用户工作。

问题

每当 2 个 phone 尝试通过套接字相互连接时,我都会收到一个 ConnectionException 说 "Connection refused"。

当前设计

每个phone启动一个ServerSocket,调用accept()方法等待某个Socket连接,谁phone先发送消息就会创建一个客户端Socket。我确定我使用的 IP 地址是正确的(它们实际上都使用相同的外部 IP)。 我相信问题出在端口上。我随机生成一个端口号,如果可以免费使用,我说 ServerSocket s = new ServerSocket( randomPortNumber ).

我认为是问题的根源

我认为问题在于这个端口号位于 NAT 路由器后面。因此,当 Socket 尝试使用 Socket socket = new Socket( ip, serverSocketRandomPortNumber ) 之类的方式连接到 ServerSocket 时,它将尝试连接到 NAT 路由器并向其提供此端口号,但由于路由器本身未在该端口上侦听,因此该端口号将不起作用,但是路由器后面的 phone 是。

问题和想法

我的问题是,我该如何处理这个问题?

我必须更改设计吗?

如果必须的话,我正在考虑的另一种设计是在 Web 主机上使用单个 ServerSocket,并使用它将从客户端套接字发送的消息重定向到其他客户端套接字。

我将在 php 中实现服务器端,参考这些内容: http://php.net/manual/en/sockets.examples.php

我仍然会在客户端使用 Java。

由于其中一部电话在 NAT 路由器后面,除非在路由器上启用端口转发(或其他一些技术),否则没有任何东西可以启动到它的连接。

实现聊天应用程序的通常方式是,所有客户端都将连接到一个公共服务器。

您不必编写自己的聊天服务器(除非您真的想要)。我建议使用 XMPP 协议。已经创建的服务器列表 here. On the client side (Android), you can find libraries you can use here.