In a C++Builder Android project, TIdUDPClient
on a TDataModule
respects its BoundPort
as expected when the device is connected to a WiFi network:
// BoundPort property is set to 55555...
amcDeviceDM->UDPC->Active = true;
amcDeviceDM->UDPC->Connect();
if(amcDeviceDM->UDPC->Connected())
{
amcDeviceDM->UDPC->SendBuffer(fHost,fPort,Id_IPv4,DataPkt);
}
Extract from UDP Server receive log:
PeerPort = 55555
If WiFi is disabled, and instead the device is connected to a GSM network (like Telstra Australia), the BoundPort
property is ignored, and the UDP Server receive log shows:
PeerPort = 37091
If WiFi is reactivated, the server once again shows:
PeerPort = 55555
Does anyone know how to ensure the correct sending port is always selected, even if the network socket changes?
Indy has no concept of WiFi vs GSM networks. It is simply binding a socket to a local IP/port, regardless of what they happen to be associated to at the OS/hardware layers. The fact that you are not seeing any exceptions raised means the binding is successful (and you can verify that by looking at the amcDeviceDM->UDPC->Binding->Port
property after activating the socket).
When connected to a GSM network, the device does not have a direct connection to the Internet. The provider is acting as a gateway/proxy to give the device Internet access. As such, the UDP server is going to be receiving packets from a PeerIP
/PeerPort
pair that belongs to the provider's system, not the device (you would see that more clearly if the UDP server were logging the PeerIP
). Whatever BoundPort
you decide to bind TIdUDPClient
to locally on your device has no effect whatsoever on the port binding used by the provider's system, and you have no control over that. And that is perfectly fine, as the provider will handle the linkage between the device's IP/Port and the provider's IP/Port for you so packets can be routed between them as needed.
When connected to WiFi, the device still does not have a direct connection to the Internet. The router is acting as a gateway to give the device Internet access. As such, the UDP server is going to be receiving packets from a PeerIP
/PeerPort
pair that belongs to the router, not the device. Whatever BoundPort
you decide to bind TIdUDPClient
to locally may or may not be preserved by the router. When a router sees an outgoing UDP packet that it needs to forward to the public (Internet) side of the network, the router will open a port that is bound to the router's public IP (if not already open), and then send the packet from that public IP/Port. Any UDP packets that are received by that public IP/port will then be forwarded to the device's IP/Port. That opened port number will usually be the same port number used by the original packet, if that port number is currently available on the router, but that is not a guarantee. So, even on a WiFi network, it is still possible for the UDP server to see a different PeerPort
than what the device is bound to. And that is perfectly fine, as the router will handle the linkage between the device's IP/Port and the router's IP/Port for you so packets can be routed between them as needed. If you need to guarantee the router's public port number, you will have to configure a port mapping rule on the router before your device starts sending packets, either in the router's configuration statically, or dynamically via uPNP.