Search code examples
javaandroidsocketsandroid-networking

Socket won't be created if data on


I am doing an app that allows for two devices to connect via socket. One of them creates a hotspot and the serversocket, the other device can join that hotspot and connect to that serversocket.

Everything works fine (actually on Nougat devices it throws a Network Unreachable exception, but i solved it with a retry and it is fine), but IF data 3g/4g is on, it simply won't connect , it will be stuck ( on socket = new Socket(ip,port) and after some time it throws a ConnectException _ Connection timed out.

Here is the full stack for the error :

   java.net.ConnectException: Connection timed out
  W/System.err:     at java.net.PlainSocketImpl.socketConnect(Native Method)
 W/System.err:     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:334)
  W/System.err:     at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:196)
  W/System.err:     at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:178)
  W/System.err:     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:356)
  W/System.err:     at java.net.Socket.connect(Socket.java:586)
  W/System.err:     at java.net.Socket.connect(Socket.java:535)
  W/System.err:     at java.net.Socket.<init>(Socket.java:427)
  W/System.err:     at java.net.Socket.<init>(Socket.java:210)

EDIT : I know that there are similar questions here, but none of them are related to the mobile data (at least i didn't find one), they are just general.


Solution

  • When an endpoint (user) device wants to send something to a remote peer, it usually doesn't know anything about the network between them. All the device has is a set of network interfaces (wifi, cellular, bluetooth) and a routing table.

    Most of the interfaces already should have an IP address assigned by a device (for wifi) or by a cellular operator (for 3g/4g).

    When something is to be sent to IP x.x.x.x, the device looks through the routing table, trying to find what interface to use. If nothing is found (this is most likely scenario actually), default route (gateway) is used.

    In your case it's likely that the default gateway says the device should send the data via 3g/4g when data transfer is on. When it's off, the default gateway is changed to use wifi, the only active network interface at that point of time.

    You have four options on how to overcome this.

    1. When you have two interfaces (wifi and 4g) up, each interface receives it's own IP. Make sure you use wifi's IP (usually 192.168.0.0/16 network).

    2. Add a static route to route your app traffic to wifi. Not sure if it's possible on a not rooted android.

    3. Get a static IPv4 address at your cellular operator. IPv4s are scarce and most of the devices are hidden behind NAT/PAT making direct connections between them impossible. At least one party needs a global static IP address known by the other party.

    4. Get an IPv6 address at your cellular operator.

    Also please note that 3 and 4 makes wifi part effectively unused.