背景:我有一个用 PHP 编写的非常简单的服务器程序。它基本上可以正常工作,但前提是每个站点的客户端不超过一个。
问题:
- NAT 路由器(典型的 SOHO 路由器)如何知道向哪个内部客户端发送返回流量?
- 我可以使用什么方法来区分 NAT 路由器后面的多个客户端?
答案1
NAT 路由器将重写源原始 IP:原始端口出站 UDP 数据包的元组nat-ip:nat-端口并维护以下关系表:原始 IP:原始端口和nat-ip:nat-端口因此 UDP 应答数据包到达nat-ip:nat-端口因为目的地可以映射回原始 IP:原始端口目的地。有关 NAT 实现如何处理的详细信息,请参阅Linux 中如何实现连接跟踪。
如果您的实现不允许更改客户端端口号,那么它根本无法保证在 NAT 路由器后面工作。它可能对一个客户端有效,因为许多实现会尝试使用与原始数据包相同的源端口号(如果可用),所以nat 端口等于始发港第一个客户端的连接。但是当这个端口不可用时,后续的尝试将不可避免地导致以下情况:nat 端口不同于始发港。
因此,区分不同客户端所需的基本“关键”是客户端的源 UDP 端口。您的服务器聊天应用程序需要生成 UDP 数据包,这些数据包将发送到与它收到用于启动聊天连接的客户端数据包相同的目标端口 - 这与已建立的 TCP 会话的情况几乎相同。
答案2
192.168.1.x 网络的路由器会为每个出站连接分配一个 Internet 端的唯一源端口。当路由器收到回复时,它会在其 NAT 表中查找数据包发送至的端口,并告知其在 LAN 端应将哪个 IP 和端口作为目标。
当数据包从 LAN 端发送到 Internet 端时,路由器会检查其 NAT 表。如果没有与该本地源 IP 地址、本地源端口、远程 IP 地址和远程端口相对应的条目,则创建一个条目。分配一个新的目标端口地址。数据包被发送到 Internet,源 IP 被重写为路由器的 Internet IP,源端口被重写为分配的源端口。
当 Internet 端收到数据包时,路由器会检查其 NAT 表中的目标端口。如果没有与该远程 IP 和目标端口对应的条目,则数据包将被丢弃(除非路由器正在执行其他操作需要它)。如果是,则将目标 IP 地址更改为正确的本地 IP 地址,将目标端口更改为原始本地源端口,并将数据包发送到 LAN。
您所说的“唯一ID”是本地机器想要通信的远程IP地址和路由器选择的本地源端口的组合。