I'm having an intermittent connectivity issue with Android 4.1.2 and 4.2.2 whereby the HTTP stack seems to completely time-out (DNS Lookup and TCP/IP still works I can check that using ADB SHELL).
These connections are failing over GPRS, not over WiFi.
When checking netstat using SHELL I can see that the connections are sat waiting at SYN_SENT, and when inspecting the firewall on the server, we can see that it has responded to the SYN request but hasn't heard anything back from the device. During this outage it seems that all HTTP traffic fails on the device. Exchange no longer works and you cant request any pages using any of the common browsers (Firefox, Chrome), even though the device reports network and you can make / receive calls.
My application communicates over HTTP and HTTPS and during this outage both fail. POST and GET to my JSON web service, the requests hang and throw:
java.net.SocketTimeoutException: failed to connect to mywebaddress.com/1.1.1.1 (port 443) after 10000ms
This is expected if it's having trouble connecting as it is respecting the timeouts I have set below with the HttpURLConnection.
The code I use is as follows, located in an Async class. This is often contained in a connection loop, depending on how important the message is. This may be called up to 3 times with a 15 second gap in-between each call.
HttpURLConnection conn = null;
BufferedReader reader = null;
try
{
// Uses ConnectivityManager.getActiveNetworkInfo()
// Returns true, the Android OS reports a connection
if(myApp.hasNetworkConnection)
{
conn = (HttpURLConnection)endpoint.openConnection();
conn.setConnectTimeout(10000);
conn.setReadTimeout(20000);
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer strResults = new StringBuffer();
String strLine = "";
while ((strLine = reader.readLine()) != null)
{
strResults.append(strLine);
}
log(strResults.toString());
}
}
catch(Exception ex)
{
log(ex.getMessage());
}
finally
{
if(reader != null)
try
{
reader.Close();
reader = null;
}
catch(Exception ex)
{
ex.printStackTrace();
}
if(connection != null)
{
connection.disconnect();
connection = null;
}
}
I'm wondering if anyone has experienced this in the past, is the method of regularly trying the connection the wrong approach and exhausting the connection pool?
The connections that are created fire regularly and it doesn't (currently) batch connections together.
Just to share a bit more info, this is what netstat shows on the device (ADB Shell) when we experience the outage. The two "ESTABLISHED" connections are TCP connections not HTTP requests. The mobile has signal and the data symbol is showing a connection.
try this
try {
HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
con.setConnectTimeout(5000); //set timeout to 5 seconds
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
} catch (java.net.SocketTimeoutException e) {
return false;
} catch (java.io.IOException e) {
return false;
}
Just thought I would update, in-case this issue is experienced by anyone else.
The problem here is not with Android but the web service that the application is calling. Looking at it, when it was calling the JSON web service, it was taking far longer than expected (up to and over a minute) to return a response (if at all) and that response was always 200/OK.
As we were saturating the Android HTTP Stack with requests, eventually they were not clearing in a good enough time and would freeze up the device.
I added better fault tolerance to my code by setting the connect and read timeouts to more appropriate values rather than "0" (infinite) and we have looked at modifying the web service so that long running processes return a 201/Accepted status so that the device can carry on doing it's own work. We call the device back by other means (Google Cloud Message) once server processing has been completed.
Related
We are developing some internal apps for mobile devices that are connected to internal wifis. We have some problems because we are only checking if the devices are connected using ConnectivityManager. But we need to check not only if there is connection, we need to check that the connection between the device and the server is working.
The problem is that ConnectivityManager tell us that the wifi is connected. But if the device is in an area with little coverage the app have errors trying to connect.
How can we easily check that the connection we have open against the server is still responding correctly? For example, one of the applications the connection is open against a SQL Server. Is there any way to check that we get to the server and it gives us an ok, and that we are not losing the connection and the packages because of the low coverage?
Thanks!!
You can try pinging the server if you receive a NullPointerException or IOException most likely there is no connection or connection timed out.
you can read more here an answer to similar question by syb0rg. Also remember to wrap this piece of code in an AsyncTask or a Thread to prevent your app from crashing.
try {
//replace URL with your domain
URL url = new URL("http://www.google.com");
HttpURLConnection urlConnect = (HttpURLConnection) url.openConnection();
urlConnect.setConnectTimeout(1000);
urlConnect.getContent();
System.out.println("Connection established.");
} catch (NullPointerException np) {
np.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
}
I am currently trying to send some data between two android devices using Bluetooth. I've read plenty of questions regarding bluetooth transfer, sockets, and streams. So far without any luck.
The connection part is working. I get the device address then open a connection using the following :
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(myOtherDeviceAdress);
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(myUUID));
socket.connect();
And then try to send some data using the OutputStream
OutputStream mmout=tmp.getOutputStream();
byte[] toSend="Hello World!".getBytes();
mmout.write(toSend);
mmout.flush();
On the receiving end:
mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("ccv_prototype", UUID.fromString(myUUID));
mBluetoothSocket = mBluetoothServerSocket.accept(3 * 1000);
InputStream is = mBluetoothSocket.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(is));
And then, different version trying to read the buffer, currently:
int c;
StringBuilder response = new StringBuilder();
try {
while ((c = r.read()) != -1) {
//Since c is an integer, cast it to a char. If it isn't -1, it will be in the correct range of char.
response.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
String result = response.toString();
Log.d("MyTag", "Received String: " + result);
My issue here is that if I don't close the OutputStream, the receiving end never receives the EOF, but if I add mmout.close();, it closes before it even had time to read the message I wanted to send. So far, my only idea is to send a specific token as an EOF but this doesn't sound right.
What did I miss ?
Any help appreciated.
The simple answer is yes. You should send a specific token to represent EOF. When you do a read() operation on a Bluetooth socket, it will either return immediately with some data if there's data ready to be read, or otherwise the read() call will block until there is some data, or some IO exception happens (e.g. the connection drops). This is why you must make use of Threads, particularly for Bluetooth socket read and write operations. What you're attempting to do is rely on the BufferedReader returning -1 to indicate "no more data". Sadly, this isn't how it works. The -1 will only happen in the event of some IO exception or the connection closing.
Detection of where your piece of information (i.e. your packet of data) starts and finishes, or indeed determining when an overall communication session is ended, is something that you handle yourself in your own application protocol (or of course an existing protocol) that works over the sockets. This is an important concept with any protocol that works through streaming sockets. A good example to look at is HTTP, which as you know is conventionally used over TCP. Taking a quick look at HTTP will show you (a) how the HTTP protocol uses headers to tell the recipient how many more bytes to expect for the overall HTTP "message", and (b) how HTTP headers are also used to negotiate when the connection should close. What you cannot do is attempt to use methods on the sockets themselves to determine when the sender has finished writing a message. Similarly if one end is to be aware that the other end wants to close the connection, that should be negotiated over the application protocol.
I've written an Android code that tries to access a server over the network upon an incoming call.
Network access is executed once an incoming call is received using a BroadcastReceiver with the intent-filer of READ_PHONE_STATE.
Data communication is performed over GPRS.
Using the logcat I've noticed that the data retrieval time from the network has large distribution, ranging from 1sec to 15sec.
Here is the code for sending a HTTP request and waiting for server response
urlConnection = (HttpURLConnection) url.openConnection();
Log.i("TIMINGS", "Connected to server.");
jsonobj.put("id", id);
String requestContent = jsonobj.toString();
urlConnection.setDoOutput(true); // Will make a POST HTTP request
urlConnection.setFixedLengthStreamingMode(requestContent.length());
urlConnection.setRequestProperty("content-type", "application/json");
urlConnection.setRequestProperty("Connection", "close");
System.setProperty("http.keepAlive", "false");
urlConnection.setDefaultUseCaches(false);
Log.i("TIMINGS", "Sending request...");
// Write the JSON string to the POST request content
DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
out.writeBytes(requestContent);
out.flush();
out.close();
Log.i("TIMINGS", "Request sent.");
Log.i("DEBUG", "Connect response code: " + urlConnection.getResponseCode());
// Get the output from the server
Log.i("TIMINGS", "Extracting data from response...");
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
byte[] bytes = getBytesFromInputStream(in);
if (bytes == null) {
return null;
}
in.close();
Log.i("TIMINGS", "Response extracted");
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (urlConnection != null) {
Log.i("TIMINGS", "Disconnected.");
urlConnection.disconnect();
}
}
When network access is performed via WIFI, results are consistently fast.
Has anyone encountered similar results? Can something be done to achieve consistent fast network access via GPRS when an incoming call is received?
Thanks,
Latency is highly variable on a mobile network primarily due to the science, maths and engineering of capturing and recovering errors on a very poor transmission path (the atmosphere) AND managing the mobililty aspect.
Your device must request available resources from the network and wait until they are granted. On GSM networks voice traffic has priority, so this can take some time (yes 15 seconds is ok) - devices are told to queue the data.
On 3G networks the device is told every 4 milliseconds about the quality of the signal received at the tower. Your device must change the coding rate in accordance with the quality reported. The amount of redundant coding in the transmission is set so that your data can be recovered with a high degree of reliability. The constant variability in the coding rate impacts throughput and latency.
GSM-GPRS degrades like a brick wall, 3G-GPRS (modern) is a shared channel so degrades gracefully
Due to the poor transmission path for WiFi (impacted by water in atmosphere) - it can only exist across the room, so the scope for the variability can be much tighter without sudden degradation.
I'm newbie on Android and Java programming and I'm stuck.
I was able to create a TCP/IP communication client (Over LAN) which sends text messages on a windows based web server. The code is working quite well on my Samsung Galaxy S Advance mobile phone which is currently running on 2.3.6. However trying the apk file on two other devices running Android 4.0 and Android 4.1 the App is running but no message arrives on the PC (test are preformed on the same network).
The function I'm using for sending packets is the following:
public void sednit(String IP,String MSG) {
try {
// Socket s = new Socket ("192.168.128.102",39999);
Socket s = new Socket (ipaddress,39999);
//outgoing stream redirect to socket
OutputStream out = s.getOutputStream();
PrintWriter output = new PrintWriter (out);
output.println(MSG);
output.flush();
BufferedReader input = new BufferedReader (new InputStreamReader(s.getInputStream)));
//read line(s)
String st = input.readLine();
//Close connection
s.close();
} catch (Exception e) {
// Toast.makeText(getApplicationContext(), e.toString(),Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "Unable to communicate with player", Toast.LENGTH_LONG).show();
}
What Am I doing wrong?
Is there any limitation applied on Android 4 and newer or I have messed up my manifest file?
Thank you.
You are most likely getting a NetworkOnMainThread exception. Since Android Honeycomb, you are required to perform network operations in separate threads to improve UI responsiveness. The easiest ways to do this are to use an AsyncTask to manage your network operation if it's short, or to extend java.io.Thread if the connection needs to be maintained.
As Tomislav says in comment use Asynctask to network communication.
Also catch (Exception e) { Is an extremely bad Idea.. Catch the exceptions you are counting on, so that others may be thrown and you can see them. We have no idea what so ever what is going wrong with you program when you are doing this...
So please either do e.printStackTrace(); or remove the try/catch so we can get your logcat and help you.
I am currently working on an Android app to be linked into an existing product for my employer. The system is a device running firmware that is controllable via serial, ethernet, or wi-fi using a .NET Windows program, direct serial communication, or a control webpage. The Android app is meant to auto-connect control webpage so that the device is controllable from a phone without anyone having to manually find IP addresses. In order to do that, I need to be able to find IP addresses and determine whether or not the address corresponds to one of these firmware devices.
Essentially what I want to do is run through all IP addresses that the Android sees and send each one to the method above. This thing should ping the address with a firmware command and see what is sent back to determine whether the address corresponds to a firmware device. I’ve been doing that at the moment by sending a command like "HOME" or "GETINFO" (correctly formatted for the firmware, of course) and comparing what, if anything is sent back with the expected response. Commands like home also have the benefit of causing a physical response, so we know without a microchip debugger if the command has at least been received.
As it stands I have the correct address hardcoded and sent in to this method. I know that the app can load the webpage controls successfully using the same address as a URL, so it must be correct and the connection must be good, but direct communication to the device is not working. No physical response is observed and no information is sent back—the Input stream just times out and returns -1. What’s stumping me so badly about this is that as far as I can tell, I’m sending information exactly the same way as the .NET Windows controls, and yet it isn’t working.
One further note: I’m aware that sending the IP Address string to the socket constructor as a hostname probably should not work, but since no UnknownHostException is thrown, I know that the socket can resolve it to an IP Address. Correct?
My code is as follows:
private class NetworkTask extends AsyncTask<String, Boolean, Boolean> {
protected Boolean doInBackground(String... addr){
try {
String message = "<FHGETHUBINFO>";
byte[] input = new byte[8];
//addr is an array of string parameters containing a single IP address string. E.g. addr[0]=”192.168.199.108”
Socket s = new Socket(addr[0],80);
//outgoing stream redirect to socket
OutputStream out = s.getOutputStream();
out.write(message.getBytes());
Log.v(TAG, "output sent. Waiting for input.");
InputStream in = s.getInputStream();
//Skip the exclamation mark and newline. Verified that nothing is received even without a skip.
in.skip(2);
int numBytes = in.read(input,0,8);
Log.v(TAG, "Input received: "+numBytes);
String st = input.toString();
//Close connection
s.close();
if(st != "HUB INFO"){
return true;
}
else{
return false;
}
}
catch (UnknownHostException e) {
Log.v(TAG,"UnknownHostException: "+e.getMessage());
e.printStackTrace();
}
catch (IOException e) {
Log.v(TAG,"IOException: "+e.getMessage());
e.printStackTrace();
}
return false;
Thanks for any help you can give, I really appreciate it!
Agreed that I should be calling isReachable on the socket just for verification purposes, so thanks for the tip! However, it turned out the problem was that the device is not communicating on port 80, so the fact that I have the wrong port is definitely the source of the problem. Thank you for the advice, regardless.