Archived

This forum has been archived. Please start a new discussion on GitHub.

Client unable to connect to android server over 3G/4G mobile network

Project Overview:
I am developing a robot that is controlled wirelessly from a base computer. Joystick input is read into base station using C++ ICE client and DirectInput, commands are sent over an ice connection to the ICE server running on my Android Razr phone.

Problem:
The client (C++, base computer connected directly to the internet via Ethernet cable) is unable to find the server (Java, droid phone connected to internet via 3G/4G network). The connection is made without issue over wi-fi, but times out when not on wi-fi. No errors are encountered; the server initializes and begins listening for the client, and the client initializes and begins searching for the server. The client times out after not finding the server, which implies that the ip address I have given the client is invalid. I tried using the ip address provided by multiple apps installed on the phone. When that did not work, I back-traced the ip address using my phone as a client and my computer as a server, then got the appropriate info from the Ice.Current object available on the server. All methods give me consistent ip addresses. Next I tried using the network trace, now running the server on my phone, and the client on my computer, and it gave me three available server endpoint ip addresses. The first was the same as what all the other methods gave. The second was the wired usb connection between my phone and computer. I am not sure what the third one was, but only the wired address worked.

Question:
Since the basic ice setup does not work when connecting to an android server, how should I go about setting up a connection using the phone's wireless network? I am able to connect a client on my phone to a server on my computer using the 4G network, so I have begun looking into using callbacks as a substitute to my original setup. I feel like having a server on the phone is most desirable for continuously sending data to the phone from my computer, but if that is not possible, are callbacks worth pursuing or is there a better way to go?

Client Code (Computer):
void JoystickController::initClient(int argc, char *argv[])
{
try
{
cout << "Searching for Server..." << endl;
ic = Ice::initialize(argc, argv);
Ice::ObjectPrx base = ic->stringToProxy("hello:tcp -h 166.248.32.162 -p 1501");
printer = HelloPrx::checkedCast(base);
if (!printer)
{throw "Invalid proxy";}
else
{
cout << "Server Found!" << endl;
cout << "Sending Message to Server" << endl;
string headerMessage = "Initializing Connection...";
printer->printString(headerMessage, 0);
double i = 0;
while (i++ < 500)
printer->printString("Test: ", i);
}

}
catch (const Ice::Exception& ex)
{cerr << ex << endl; status = 1;}
catch (const char* msg)
{cerr << msg << endl; status = 1;}
}

Server Code (Phone):

private void createProxy()
{
Ice.ObjectAdapter adapter =
_communicator.createObjectAdapterWithEndpoints("SimplePrinterAdapter", "default -p 1501");
Ice.Object object = new HelloI();
adapter.add(object, _communicator.stringToIdentity("hello"));
adapter.activate();
_status.setText("Server initialized. Waiting for data...");
}

private void initializeCommunicator()
{
try
{
Ice.Communicator communicator;
// Ice.InitializationData initData = new Ice.InitializationData();
// initData.properties = Ice.Util.createProperties();

Ice.Properties props = Ice.Util.createProperties();
Ice.InitializationData initData = new Ice.InitializationData();
initData.properties=props;
initData.properties.setProperty("Ice.Trace.Network", "2");

// Only configure IceSSL if we are using Froyo or later.
if(VERSION.SDK_INT >= 8) // android.os.Build.VERSION_CODES.FROYO (8)
{
initData.properties.setProperty("Ice.InitPlugins", "0");
initData.properties.setProperty("IceSSL.Trace.Security", "3");
initData.properties.setProperty("IceSSL.KeystoreType", "BKS");
initData.properties.setProperty("IceSSL.Password", "password");
initData.properties.setProperty("IceSSL.TruststoreType", "BKS");
initData.properties.setProperty("Ice.Plugin.IceSSL", "IceSSL.PluginFactory");
}

communicator = Ice.Util.initialize(initData);

if(VERSION.SDK_INT >= 8) // android.os.Build.VERSION_CODES.FROYO (8)
{
IceSSL.Plugin plugin = (IceSSL.Plugin)communicator.getPluginManager().getPlugin("IceSSL");
//
// Be sure to pass the same input stream to the SSL plug-in for
// both the keystore and the truststore. This makes startup a
// little faster since the plugin will not initialize
// two keystores.
//
java.io.InputStream certs = getResources().openRawResource(R.raw.certs);
plugin.setKeystoreStream(certs);
plugin.setTruststoreStream(certs);
communicator.getPluginManager().initializePlugins();
}

synchronized(this)
{
_communicator = communicator;
if(_cb != null)
{
_cb.onCreate(_communicator);
}
_initialized = true;
}
}
catch(Ice.LocalException ex)
{
synchronized(this)
{
if(_cb != null)
{
_cb.onError(ex);
}
_ex = ex;
_initialized = true;
}
}
}

Comments

  • mes
    mes California
    Hi Eric,

    Welcome to the forum.

    I think you're seeing the expected behavior: on Wifi your phone acts as if it's just another computer in your local network, but on 3G/4G you're phone is limited to what the telco's network allows, and they generally don't allow incoming IP connections to arbitrary ports.

    I recommend using bidirectional callbacks instead, where your Android app must initiate the connection and your PC sends callback requests over this connection.

    Regards,
    Mark
  • Thank you for responding so quickly! I have begun working on a bi-directional callback version of the program, and I will post back when I have it working.

    Thanks,
    Eric