Odd behavior with Java socket on Android and IPv6 - android

I have some code that uses sockets. Simple stuff like:
Socket socket = new Socket();
InetSocketAddress endpoint = new InetSocketAddress(host, port);
socket.connect(endpoint, 120000);
For some web addresses it will freeze until it times out but only for some of my users. I finally tracked it down by having the users send me logs and the issue happens when endpoint is an IPv6 address. So just to clarify, if a web address has no IPv6 records, then it will just work for those users with the issue. But if the web address has an IPv6 record then it will timeout for those users. All other users (including myself) have no issue with it.
What is strange is that this issue does not happen if I use OkHttp. Also if the user just loads the page using Chrome on the phone then the issue doesn't happen. I know newer Android versions use OkHttp for the HttpUrlConnection so that might be why.
I have fixed it for some users by using:
java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");
But for other users not even that helps.
I am trying to understand why this is even an issue and why only for a few users? And why on some phones the system properties fix it and on others it just gets ignored.
EDIT: I have found a confirmed solution for the users for whom the system properties don't fix the issue.
Basically my code was:
Socket socket = new Socket();
InetSocketAddress endpoint = new InetSocketAddress(host, port);
try{
socket.connect(endpoint, 120000);
....
Now it is:
Socket socket = new Socket();
InetAddress address = InetAddress.getByName(host);
if (address instanceof Inet6Address) {
Log.w(TAG, "Found ipv6 address, looking for ipv4 " + address);
InetAddress[] inetAddressArray = InetAddress.getAllByName(host);
for (int i = 0; i < inetAddressArray.length; i++) {
if (inetAddressArray[i] instanceof Inet4Address) {
address = inetAddressArray[i];
Log.w(TAG, "Found ipv4 " + address);
break;
}
}
}
InetSocketAddress endpoint = new InetSocketAddress(address, port);
//InetSocketAddress endpoint = new InetSocketAddress(host, port);
try {
socket.connect(endpoint, 120000);
......
Essentially I am forcing the socket to use an IPv4 address if InetAddress.getByName(host) returned an IPv6 address and an IPv4 is available. I'm a little nervous about doing this so I would still prefer if someone has a better solution.

Related

Android tcp connection from client

I'm trying to make my android phone a client to a server I wrote in python. The server works good (I have tried it) but I can't seem to connect the phone with the server.
This is the function that should create the connection:
public String createConnection() throws IOException{
InetAddress serverAddr = InetAddress.getByName(ipString);
clientSocket = new Socket(serverAddr, portNumber);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
outToServer.writeBytes(Client.INIT_HEY.name());
String ans = inFromServer.readLine();
return ans;
}
ipString is the server ip received by the user, portNumber is the port number and they are both correct.
When I try to connect to the server, I receive "null" as the error message.
Any thoughts?
Thanks!
Try it over wifi.
If you can find the phone's IP address, try ping it from your dev system.
If your are on cell network, try access web site from browser, make sure the network connection is working.
The error was because I was running a tcp connection on the main thread.. I could've fixed it by making the class an AsyncTask but I prefered adding this:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Thanks all!

Can not connect to working webservice using android device

I used android device to connect via wifi to localhost of my computer.This is the string i m passing to retrieve values from web service.
I get a error message in logcat OSNEtworkSystem_Connect fail:Timeout. Can any one sugest a solution please.
String tabledata = getServerData[a link]("http://10.0.2.2:52764/Service1.asmx/getTrainTimeTable? FromSt='"+frm+"'"+" ToSt= '" +t+ "'"+" FromTime= '" +t01+ "' "+"ToTime='"+t02+ "'"+" ArriveTime= '" +at+ "'"+" DepartTime= '" +dt+ "'"+" ReachingTime= '" +rt+ "'"+" TrainId= '"+tid+"'" )[a link];
private String getServerData(String url) {// requet and response happens here
String data = null;
try {
// Send GET request to <service>/GetPlates
HttpGet request = new HttpGet(url);
DefaultHttpClient httpClient = new DefaultHttpClient();
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
HttpResponse response = httpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
// Read response data into buffer
char[] buffer = new char[(int) responseEntity.getContentLength()];
InputStream stream = responseEntity.getContent();
InputStreamReader reader = new InputStreamReader(stream);
reader.read(buffer);
System.out.println(new String(buffer));
stream.close();
JSONObject o = new JSONObject(new String(buffer));
data = (String) o.get("d");
System.out.println(data);
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
after changing ip in to pc ip connection timeout eror is gone. now im gettin this error.
Your problem is that you are using 10:0:2:2 to connect to devices. you need to provide PC's IP address when trying the application on real device.
follow the steps:
1- go to CMD and type ipconfig.
2- Search for IPv4 and copy the address.
3- use it in your code.. this is an example of how it should look like:
http://192.168.0.106:52764/Service1.asmx/getTrainTimeTable?.... // you must have similar IP to this.
4- Turn off the firewall and any anti-virus program
hope this will make your application work in a real device. please give me a feedback of what will happen
If you really mean connect localhost via wi-fi
instal a virtual router to your computer. Then via wi-fi connect to your computer with your mobile device.
here is a link for virtual router
when you install it, connect with your mobile device to that virtual wi-fi provider. probably the ip that you should connect will be
http://192.168.1.1:52764/Service1.asmx/getTrainTimeTable? something(to
learn it open cmd-forwindowns enter ipconfig to learn the router device's
ip.
Be careful if you have internet connection
there will be two major ip addresses one is for your
computer that as a client to connect to the internet,
the other one is for the virtual router as a servise host which you need to connect connect

Cannot get http server work on android

I have a http server code (I tried both TJWS or NanoHTTPD), the client from the same application would connect to server running on port 8080 or whatever.
I am starting server object in a separate AsyncTask so it should be okay.
While NanoHTTPD completely failed to start other ways I can see from TJWS logs, it says something like;
server listening on 0.0.0.0/0.0.0.0 port:0 localport:8080
This means server started successfully, first question is 0.0.0.0 bind address acceptable? I mean it should be 127.0.0.1 instead? sorry if that is a noob question.
When I connect to my emulator using adb shell and run netstat, I can see the following lines
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:5037 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN
tcp 0 0 10.0.2.15:5555 10.0.2.2:52132 ESTABLISHED
tcp6 0 0 :::8080 :::* LISTEN
By googling I learned that 0 :::8080 means server is listening on ipv6 and ipv4 both and that is okay.
But from my client code when i tried to access it continues to wait for eternity.
my httpClient Code
try {
URL url = new URL("http://0.0.0.0:"+8080+"/media");
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while((line = br.readLine()) != null){
Log.d("server", line);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
For the server, the address 0.0.0.0 is like a wildcard and means, it is listening on all IP addresses the device has.
For the client, you need to use a real IP address like 127.0.0.1
After debugging a little I found that problem is not where client opens a connection but issue was at where server was starting it never returned onPostExecute() method, but after wrapping my server start code inside a Runnable
new Thread(new Runnable() {
#Override
public void run() {
Log.d("server", "server starting on port: " + port);
srv.serve();
}
}).start();
it Works!!
Server is a infinite loop so does it have to be started from inside thread? I thought AsyncTask can handle that?
Its also worth mentioning that client side connection must also be wrapped inside AsyncTask

Application using socket freezes when it tries to connect to server

I am doing application which send some data from mobile phone to PC. Im using socket to do it. When the server is online it works, but when I try to connect with wrong ip/port or server is not running then application freezes and I cant do nothing. It because client on mobile phone tries to connect to server.
I have main class in which I make:
Thread cThread = new Thread( new TCPClient( ip, port, message, context) );
cThread.start();
There is context in new TCPClient because i need to make Toast when message is sent or when error appears. In TCPClient class there is:
public void run(){
try {
InetAddress serverAddr = InetAddress.getByName(s_ip);
Log.d("TCP", "C: Connecting...");
Socket socket = new Socket(serverAddr, s_port);
When server is online it goes to:
Log.d("TCP", "C: Sending: '" + s_msg + "'");
PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
out.println(s_msg);
Log.d("TCP", "C: Sent.");
Log.d("TCP", "C: Done.");
but when the server is offline or I put wrong ip/port my application freezes. I cant do nothing for a while.
Is there any solution to force stop trying connect to server after some time? For example after 5 second application will go to catch and give me error.
I tried to do this with AsyncTask, then application is working even when Client tries to connect to server, but toast with error appears after not acceptable time for me, so I would like a solution which will give me error when client cannot connect with server in for example 5 seconds.
You can set the connection timeout. You have to use different constructor of Socket class. Insead of:
Socket socket = new Socket(serverAddr, s_port);
use:
Socket socket = new Socket();
socket.connect(new InetSocketAddress(serverAddr, s_port), 5000);
In case of timeout an exception is thrown.
Perhaps you didn't set a timeout connection so it's "0" by default which means that it will never timeout , so you can set the timeout to 1 minute it won't freeze for more than one minute .

Android, problems with SocketAddress and sockets. Reverse lookup?

i have a problem with Android. I am trying to connect to a server with a proxy with no luck.
I have this code that works fine on normal Java. It only defines a proxy server and creates a socket that would connect to google with that proxy. It sends a simple GET request and then shows the response.
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketAddress;
public class Main {
public static void main(String[] args) {
try{
//create the proxy info
SocketAddress socketAddress = new InetSocketAddress("78.137.18.67" , 8364);
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socketAddress);
// create the socket with the proxy
Socket socket = new Socket(proxy);
// connect to some address and send/receive data
socket.connect(new InetSocketAddress("www.google.com", 80));
socket.getOutputStream().write("GET /index.html HTTP/1.1\r\nHost: www.google.com\r\n\r\n".getBytes("UTF-8"));
byte result[] = new byte[1024];
socket.getInputStream().read(result);
socket.close();
System.out.println(new String(result));
}catch(Exception e){
e.printStackTrace();
}
}
}
The problem with android, with a code similar like that, is that the InetSocketAddress is doing something strange. It seems that it does a reverse lookup of the given ip, and then the socket created with the proxy tries to connect with the resolved host name, in this case is 78-137-18-67.dynamic-pool.mclaut.net.
This would not be a problem (except on performance) if the socket could resolve the hostname back to the ip address. The fact is that this hostname cannot be resolved to ip address with my internet connection (i don't know if others can do). So the reverse lookup is working fine but the normal lookups fails, so when the socket tries to connect through the proxy it raises the following exception:
08-25 19:26:46.332: ERROR/Microlog(3526): 40274 SocketConnection
[ERROR] Error establishing connection java.net.SocketException: SOCKS
connection failed: java.net.UnknownHostException:
78-137-18-67.dynamic-pool.mclaut.net
So the question is, why it is trying to connect with the hostname if i gave the ip address? Is there any way to avoid this lookup? I have tried with createUnresolved of InetSocketAddress but in this case the socket hangs on connection.
Is not a waste of time, internet connection, etc, to do a reverse DNS lookup to get the hostname (if any), and later when the socket needs to connect, resolve again the host to an ip address?
NOTE: this code is an example, the real app do not perform any http request in this way. It uses binary data packets.
To prevent a reverse lookup, you can create the InetAddress with getByAddress(byte[]).
Then pass the InetAddress instance into the InetSocketAddress constructor.
Alternatively, use the factory method InetSocketAddress.createUnresolved(String,int)
Yes it seems that the particular constructor of InetSocketAddress does a reverse DNS lookup: http://mailinglists.945824.n3.nabble.com/Android-and-reverse-DNS-lookup-issues-td3011461.html
Also, it seems that this does not happen anymore on Android 2.3.4.
In android you have to do everything with background process so that you do not write code for socket in onCreate method directly you have to do this in background so that your ui does not hangs
something like this
new Thread(new Runnable() {
#Override
public void run() {
try {
client = new Socket(ipaddress, port);
printwriter = new PrintWriter(client.getOutputStream(), true);
InputStream is = client.getInputStream();
printwriter.write(msg);
printwriter.flush();
byte[] buffer = new byte[2046];
int read;
while ((read = is.read(buffer)) != -1) {
final String output = new String(buffer, 0, read);
);
printwriter.close();
}
});
}
Log.e("message", "message send");
} catch (UnknownHostException e2) {
e2.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
Log.d("Time out", "Time");
}

Categories

Resources