I have a server which is listening on a particlar IP/Port. The socket they open is persistent and will not close till they get a CLOSE message from client i.e. ZERO bytes.
I have my client code as follows:
java.net.URL url = new java.net.URL(Constants.URL);
urlConnection = (HttpsURLConnection) url.openConnection();
if(WelcomeScreen.mySslContext==null) {
WelcomeScreen.mySslContext = GetsslContext.getSSLSocketFactory(); //reads the CA certificate and return the getSocketFactory context
}
urlConnection.setSSLSocketFactory(WelcomeScreen.mySslContext);
urlConnection.setReadTimeout(1000*15000);
urlConnection.setConnectTimeout(1000*20000);
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setUseCaches (false);
urlConnection.connect();
//Send Stream on server
OutputStream outStream = urlConnection.getOutputStream();
outStream.write(bytes);
outStream.flush();
outStream.close();
//Receive Stream from server
in = urlConnection.getInputStream();
in.close();
urlConnection.disconnect();
Once the above code executes, the server still does not receive a CLOSE message till I actually exit from my Android App.
Can you please suggest what I need to do such that the Server gets a CLOSE message from the client so that they release the connection to some other client?
One other observation is that, when I re-execute the above code i.e. copy-paste and try to send one more request in sequence, I am able to re-use the socket opened the first time. Whereas, if I remove the condition:
if(WelcomeScreen.mySslContext==null)
and force the code to execute:
WelcomeScreen.mySslContext = GetsslContext.getSSLSocketFactory();
then it creates a new socket and does SSL handshake again. Is this normal behavior?
The socket they open is persistent and will not close till they get a CLOSE message from client i.e. ZERO bytes.
You can't get zero bytes on a socket. You either get one or more bytes, or end of stream, or an error (exception in Java). Something seriously wrong with your application protocol here.
when I re-execute the above code i.e. copy-paste and try to send one more request in sequence, I am able to re-use the socket opened the first time
That's HttpURLConnection doing connection pooling.
Related
I am getting java.lang.IllegalStateException:
java.lang.IllegalStateException: Cannot set request property after connection is made error when setRequestProperty method is called after
url.openConnection();
Here is what i am trying:
URL url = new URL("https://49.205.102.182:7070/obsplatform/api/v1/mediadevices/545b801ce37e69cc");
urlConnection = (HttpsURLConnection) url
.openConnection();
urlConnection.setRequestProperty("Content-Type","application/json");
any suggestions please? Thanks in advance.
This usually happens if you have in the debug watchers calls, such as conn.getResponseCode() or anything that queries the request result before the request was actually issued or completed.
This causes, that during debug, a request is performed by the watcher, before having properly set you request, and then it becomes invalid.
I only have this issue while in debugging mode,
Run without debugging (You can print logs) everything should work fine
The obvious thing is to think that you need to add properties before calling open on the URL. this however is not the case. i have seen many samples of settings being set AFTER url has been open (as counter intuitive as that is).
the problem in my case is that i had conn.getResponseCode() added in my watch list. removed that and all good.
... tricky.
please check below code
HttpURLConnection httpcon = (HttpURLConnection) ((new URL("a url").openConnection()));
httpcon.setDoOutput(true);
httpcon.setRequestProperty("Content-Type", "application/json");
httpcon.setRequestProperty("Accept", "application/json");
httpcon.setRequestMethod("POST");
httpcon.connect();
I was getting the same exception on setRequestProperty("Range","byte=" + downloadedSize + "-") .
After adding connection.setChunkedStreamingMode(0); the issue disappeared
I'm having the same issue.
I was observing this issue on Nexus 5. Code of my app constantly fails with the same exception (or its twin brother "cannot set request method ..")
What I've observed that it happens if i leave phone for a while. One it starts failing it fails all the time - but if i restart phone/emulator it's ok once again).
My suspicion is its either some bug in connection pooling on framework side, or somewhere in code resources are leaked.
i found the problem it's about ordering the code, if you are trying to add header and post parameters both, it's important to be careful about this
HttpURLConnection connection = (HttpURLConnection) urlConnection;
//// Add Request Headers
for (NameValuePair nvp :
request[0].getHeaderParams()) {
connection.setRequestProperty(nvp.getName(),nvp.getValue());
}
// done
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
//// Add Post Parameters
OutputStream outputStream = urlConnection.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
List<NameValuePair> params = new ArrayList<>(request[0].getPostParams());
bufferedWriter.write(getQuery(params));
// done
connection.setConnectTimeout(3000);
connection.setReadTimeout(3000);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.flush();
outputStream.close();
connection.connect();
in here, i have added header parameters then set setDoInput and setDoOutput then setRequestMethod and finally you can add POST parameters.
i don't know what is wrong with setRequestMethod but i think its preparing the connection by opening it or something and that's why it throws exception
not invoke setRequestProperty after write byte to OutputStream.
OutputStream os = connection.getOutputStream();
os.write("k=v".getBytes());
os.close();
you should invoke setRequestProperty above the code
To avoid the error:
java.lang.IllegalStateException: Cannot set request property after connection is made
We have to check the connection response before access the request header fields :
URL url = new URL("https://49.205.102.182:7070/obsplatform/api/v1/mediadevices/545b801ce37e69cc");
urlConnection = (HttpsURLConnection) url
.openConnection();
//Check connection
if(urlConnection.getResponseCode() == 200/*Successful*/) {
urlConnection.setRequestProperty("Content-Type","application/json");
...
...
}
HttpURLConnection.getInputStream takes very much time when compared to iPhone App which uses the same server side services.
The following code is used for the service :
date= new java.util.Date();
Log.d("time","Time Stamp before posting "+new Timestamp(date.getTime()));
URL ur= new URL(url);
HttpURLConnection conn = (HttpURLConnection) ur.openConnection();
conn.setRequestProperty("Connection", "close");
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(nameValuePairs));
writer.close();
os.close();
conn.connect();
StringBuffer response=null;
try{
Log.d("time","Time Stamp bfr InputStream "+new Timestamp(date.getTime()));
InputStream is = conn.getInputStream();
date= new java.util.Date();
Log.d("time","Time Stamp aftr InputStream "+new Timestamp(date.getTime()));
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
response.toString();
result=response.toString();
} catch (Exception e) {
}
To check where the service takes time, I put the log entries to print TimeStamp.
The average time for the process is as follows :
Average time for posting to server takes less than 2 Mil seconds
Average time for creating input stream takes almost 5 seconds
Average time for writing response is less than 2 mil seconds.
Any idea on why the input stream takes much time which makes the entire service very slow?
You're not measuring what you think you're measuring. Nothing gets written to the server until you call getInputStream() or getResponseCode(). So you're really measuring:
connection time
transmission time
processing time at the server
when you think you're just measuring getInputStream() time.
The reason is that HttpURLConnection auto-sets the content-length header, by buffering all the output. You can avoid that by using chunked transfer mode. Then at least you will see where the time is really going.
Set urlConnection.setConnectTimeout() to a lower timeout.
The class documentation for URLConnection.setConnectTimeout() says:
Sets the maximum time in milliseconds to wait while connecting. Connecting to a server will fail with a SocketTimeoutException if the timeout elapses before a connection is established. The default value of 0 causes us to do a blocking connect. This does not mean we will never time out, but it probably means you'll get a TCP timeout after several minutes.
Warning: if the hostname resolves to multiple IP addresses, this
client will try each in RFC 3484 order. If connecting to each of these
addresses fails, multiple timeouts will elapse before the connect
attempt throws an exception. Host names that support both IPv6 and
IPv4 always have at least 2 IP addresses.
I originally had mine set to urlConnection.setConnectTimeout(30000); and then changed it to urlConnection.setConnectTimeout(1000). Immediately, I saw quicker results.
Hope this helps!
This may be related to a bug introduced in JDK 7. "HttpServer induces a 1000 ms delay when using the keep-alive cache". See:
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8009548
Depending on your purposes, the suggested workaround is to multi-thread the HttpUrlConnection. For example, if you're using HttpServer you can do:
server.setExecutor( Executors.newFixedThreadPool( 5 ) );
I'm developing this android application which basically uploads images to a webservice.
I have a asynctask where I send the file to the server, using this code:
protected Boolean doInBackground(byte[]... params) {
HttpURLConnection connection = getConnection();
BufferedOutputStream out = new BufferedOutputStream(connection.getOutputStream());
Log.d("OutputStream", "stream created, about to write");
out.write(params[0]);
Log.d("OutputStream", "all bytes written");
out.close();
}
Of course, this block of code is wrapped within a try catch, catching IOExceptions etc.
The problem is that when I interrupt the connection after I see the first logtext, an exception is never thrown or only after a really long time (talking about 20 minutes or so), which doesn't make any sense at all.
The HttpURLConnection is set up like this:
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", this.contentType);
urlConnection.setRequestProperty("User-Agent", String.format("custom-user-agent/%d", R.integer.version_code));
urlConnection.addRequestProperty("SessionID", this.sessionID);
urlConnection.setDoOutput(true);
urlConnection.setConnectTimeout(30000);
urlConnection.setReadTimeout(30000);
urlConnection.setChunkedStreamingMode(0);
urlConnection.setUseCaches(false);
urlConnection.connect();
Funny thing is, this only happens when interrupting a EDGE/3G connection. When I interrupt a wifi connection, the exception is thrown immediately (which, of course, is a lot more convenient).
Any idea on this?
A while ago, we've encountered this problem also, but only on a Samsung Galaxy SII with Android 2.3.4. All other devices did not have this issue. There is no way to program around this issue.
You don't need use urlConnection.connect(): the connection is open implicity when yo do the .getOutputStream().
Also, if you make the .connect(), you can't make it before at the .getOutputStream().
In addition, you must set the Content-Type header:
urlConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
I'm trying around with the HttpURLConnection for quite some time now and I tried several solution posted here and on other places, but nothing seems to work.
I have the following architecture:
A Ruby on Rails Web Service (Rest interface with JSON)
An iPhone Client with RestKit
An Android Client with HttpURLConnection
The iPhone Client works like a charm. It connects to the web service with RestKit.
Now the Android Client is a completely different story. I always get a 401 Unauthorized message from the server (which results in a local FileNotFoundException).
The strange thing is, that the iPhone Client gets the same error, but RestKit somehow manages the handle it by sending the same request again. I tried that of course, but I just get the same error twice.
On the Rails Log Output it looks like this:
Started POST "/api/v1/login" for 127.0.0.1 at 2012-05-03 12:44:56 +0200
Processing by Api::V1::ApiController#session_login as JSON
Parameters: {"device"=>{"model"=>"Simulator", "system"=>"Android", "version"=>"Hugo", "name"=>"Android Simulator"}, "email"=>"florian.letz#simpliflow.com", "api"=>{"device"=>{"model"=>"Simulator", "system"=>"Android", "version"=>"Hugo", "name"=>"Android Simulator"}, "email"=>"florian.letz#simpliflow.com", "action"=>"session_login", "controller"=>"api/v1/api"}}
Filter chain halted as :require_login_from_http_basic rendered or redirected
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms)
The exact same message occurs when the iPhone Client connect's but then suddenly a magical second request occurs and it goes through.
On the Android Client I do the following:
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod(HTTP_POST);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Accept-Encoding", "gzip, deflate");
String userpassword = email + ":" + password;
con.setRequestProperty("Authorization", "Basic " + new String(Base64.encodeBase64(userpassword.getBytes())));
String body = jsonLogin.toString();
byte[] body_bytes = body.getBytes();
con.setRequestProperty("Content-Length", "" + Integer.toString(body_bytes.length));
con.setRequestProperty("Content-Language", "en-US");
con.setInstanceFollowRedirects(false);
con.setUseCaches (false);
con.setDoInput(true);
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream (con.getOutputStream ());
wr.write(body_bytes);
wr.flush ();
wr.close ();
InputStream is = con.getInputStream();
And on the last line the exception occurs.
I've read some things about redirects, but there is no redirect implemented at the server and I do not receive one on the client. I just get the 401 Unauthorized. The code in the web service and the iphone client indicate a quite simple workflow. Just send the data and receive the answer. I don't know where the SECOND login call comes from when the iPhone connects.
Does anyone here have any idea what the problem could be?
Thanks a lot!
EDIT #1:
I have identified the "magical" second request. The RestKit Log shows the following:
Asked if canAuthenticateAgainstProtectionSpace: with authenticationMethod = NSURLAuthenticationMethodDefault
This then results in the second request with quite a buch of headers I cannot make any sense of.
So do you know a way to implement this in Android?
I've encountered a rather strange error. I've written an android application that uploads an simple text file to a server. The code for the connection is as follows:
try {
URL = new URL(myURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="+"---");
DataOutputStream output = new DataOutPutstream(connection.getOutputStream());
output.writeBytes(<my post request>);
output.flush();
output.close();
connection.connect();
}
When I run this method, the post request is never sent over to the server. Nothing shows up on wireshark and if I look in logcat, there are no errors and the connection gets made fine, the POST message is just never sent. However, if I add a simple line right after the connection.connect() such as:
connection.getResponseCode();
Suddenly the POST message gets sent over no problem. What's going on here? Am I required to get a response code in order for the message to get sent over?
Why do you have to call URLConnection#getInputStream to be able to write out to URLConnection#getOutputStream?
In short you must call getInputStream() and close it. getResponseCode() is also working because it requires an established connection.
You do not need to call
connection.connect();
which is redundant.
You can get working sample from here: http://www.xyzws.com/Javafaq/how-to-use-httpurlconnection-post-data-to-web-server/139
You set doInput to true. Maybe the url connection waits for an input because of that. Try to set it to false. But I could also be wrong. It is just a guess.