Android - Socket Connected even though it cannot
android, sockets
Solution
This is interesting. I have been testing and can replicate the behaviour you describe.
Firstly, the highest voted answer here provides a good discussion on the Java Socket API:
Java socket API: How to tell if a connection has been closed?
From this, I wondered whether attempting to read a byte from the socket would allow us to check if it is really open
// Endpoint that does not exist
Socket socket = new Socket("1.2.3.4", 1234);
InputStream tmpIn = socket.getInputStream();
int result = tmpIn.read();
Log.i("SocketTest", "read() result: " + result);
In the case that the endpoint is invalid, I have found that the call to `read()` returns -1 after approximately 10 seconds.
In the case that there is a listener on the IP and port, the call to `read()` seems to block indefinitely until something happens, such as actually receiving data from the server, or losing internet connectivity etc.
Based on this difference, I have wrapped this test up into a new class:
public class VerifiedSocket extends Socket {
public VerifiedSocket(String ip, int port, int millisecondTimeout) throws UnknownHostException, IOException{
super(ip,port);
ReadThread tryRead = new ReadThread();
tryRead.start();
try {
tryRead.join(millisecondTimeout);
} catch (InterruptedException e) {
}
if(tryRead.getReadValue()==-1){
// We read -1 so assume endpoint invalid
throw new IOException("Endpoint is invalid");
}
}
private class ReadThread extends Thread{
private int readValue = 512; // Impossible byte value
@Override
public void run(){
try {
InputStream input = getInputStream();
readValue = input.read();
} catch (IOException e) {
}
}
public int getReadValue(){
return readValue;
}
}
}
And then tested it as follows:
try {
VerifiedSocket socket = new VerifiedSocket("1.2.3.4", 1234, 20000);
Log.i("SocketTest", "Endpoint is valid");
socket.close();
} catch (UnknownHostException e) {
Log.e("SocketTest", e.getLocalizedMessage());
} catch (IOException e) {
Log.e("SocketTest", e.getLocalizedMessage());
}
If I use an invalid endpoint on Wifi, the constructor of the `VerifiedSocket` throws an exception with a timeout. If I use an invalid endpoint on mobile data, it throws the IOException with the 'Endpoint is invalid' message. Not perfect, but hopefully it might help you.
Problem
Firstly I know what your thinking, it's a strange question and it seems like it cannot be true but here me out on this one... The project is a project which sends an array of bytes over a socket and also receives data from a socket. I am currently working on protection. I want to make sure that the user knows when the socket can't connect for whatever reason... You can view the connection code below. So I have an android app which connects to a executable on a Windows Server computer in a office elsewhere in the world. The socket connects via the usual IP address and port number. I am testing the app using a Android 5.0 (lollipop) phone... Now enough of the boring stuff: If I close the server and turn it off completely and test this on wi-fi then the socket fails - which is correct. It cannot connect, and it will throw a SocketException. Which is fine and is working as expected. Now if I were to turn wi-fi off and use mobile data (I use o2 here in the sunny United Kingdom!) then an issue arises, using the same code, with the server still turned off, I do not throw a SocketException, instead the code simple thinks it has connected on a socket. The connection thread is below. ``` Thread StartConnection = new Thread() { @Override public void run() { int dstPort = 10600; socket = new Socket(); try { ipaddress = InetAddress.getByName(dstName); } catch (UnknownHostException uhe) { uhe.printStackTrace(); } j = new InetSocketAddress(IPString , dstPort); try { socket.setKeepAlive(true); socket.setReuseAddress(true); socket.setTcpNoDelay(true); socket.setSoTimeout(5000); socket.connect(j, 5000); connected = true; outputstream = socket.getOutputStream(); DataThread(); SocketError = false; } catch (SocketException se) { se.printStackTrace(); } catch (IllegalArgumentException iae) { iae.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }; StartConnection.start(); ``` ``` socket.connect(j, 5000); ``` works fine no socket errors. No timeouts either. ``` outputstream = socket.getOutputStream(); ``` also works. I get a result of "java.net.PlainSocketImpl$PlainSocketOutputStream@48e6f6e" which is also fine. `socket.getInputStream()` returns "java.net.PlainSocketImpl$PlainSocketInputStream@1ea305a5"