在我的应用程序中,有两台物理计算机,均在 Windows 环境中。计算机 2(IP 为“192.168.2.2”)上安装了 VMware Linux 虚拟机(IP 为“192.168.80.129”)。我想要做的是从虚拟机向计算机 1(IP 为“192.168.2.1”)发送 UDP 套接字。
根据我的应用程序的要求,当udp通过虚拟机发送到计算机2时,应该指定端口。
现在我的情况是,当我在Linux中创建和配置udp套接字时,我指定了两个端口LOCAL_PORT(9000)和REMOTE_PORT(9001)。
我打开WireShark监控,在Linux虚拟机中,源端口是LOCAL_PORT(9001),但目的端口是“iua(9900)”,源IP是“192.168.80.129”,目的IP是“192.168.2.1”,这是正确的。
我在计算机 1 或计算机 2 上的 Windows 中打开 Wireshark,显示的源 IP 为“192.168.2.2”,而目标 IP 为“192.168.2.1”。这似乎可以理解,因为发送方是虚拟机,因此 Udp 实际上是由主机(计算机 2)发送的。目标端口是正确的,为 9001,但是源端口似乎是任意的。
有人知道我可以在虚拟机中做什么,以便源端口可以是指定的数字(9900)而不是任意数字吗?谢谢!
int sock1; struct sockaddr_in slAddr, myAddr; memset(&slAddr, 0, sizeof(slAddr)); memset(&myAddr, 0, sizeof(myAddr)); slAddr.sin_family = AF_INET; slAddr.sin_port = htons(RM_PORT);//RM_PORT=9900 slAddr.sin_addr.s_addr = inet_addr(SL_IP);//SL_IP="192.168.2.1" myAddr.sin_family = AF_INET; myAddr.sin_port = htons(LC_PORT);//LC_PORT=9901 myAddr.sin_addr.s_addr = inet_addr(MY_IP);//MY_IP="192.168.80.129" sock1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); bind(sock1, (struct sockaddr *)&myAddr, sizeof(myAddr)); sendto(sock1, packeddata, 8, 0, (struct sockaddr*)&slAddr, sizeof(slAddr));
答案1
您的代码似乎没有问题(除了有时写端口 9901,有时写 9001)。
您的问题是您的 VMWare 主机正在对所有出站数据包进行 NAT。
您需要 NAT 来重写虚拟机的源 IP,使其与 192.168.2.* 网络相对应。要对许多源 IP(这里有两个,虚拟机和物理机)执行此操作,NAT 还需要能够重写源端口。它使用源端口来记住数据包来自何处。您不需要这样做,因为您只有一个应用程序,但 NAT 不知道这一点。
(实际上,根据经典的思科术语,您正在执行 PAT,而非过载 NAT 将通过要求专用于您的 VM 的 192.168.2.* IP 来解决您的问题,但我认为没有人再使用它了...)
我认为 VMWare 无法在保留源端口的情况下进行 NAT。因此,您需要关闭 NAT(使第 2 层桥物理 LAN 和虚拟机网络适配器之间的 IP 地址)。这意味着您必须为虚拟计算机指定一个与物理服务器相同的 192.168.2.* IP(否则您将必须进行路由,这会复杂得多)。
您所做的事情(根据您的评论)是编写一个代理,该代理绑定到主机上的端口 9901。您的代理将 IP 从 192.168.80.129 转换为 192.168.2.2 并返回,并且它保留了源端口,因为您是这样编写的。
如果该解决方案对您有用,那么就很好!
通常在互联网上,程序和协议的编写并不关心源端口;源端口只是一个大于 1023 的数字,用作回复数据包的目标端口。其他协议(例如 DNS 和 NTP)已经发展到允许非固定源端口。