by running netstat on the server:
UNTIL A FEW DAYS AGO: I could see the connection being ESTABLISHED only for about a second, and then it would disappear from the list
NOW: it stays as ESTABLISHED for about 10 seconds, then it goes into FIN_WAIT1 and FIN_WAIT2
the Android code is the same, the server is still the same
is it possible that some kind of Android update might have changed things?
I can't really explain it.
I report the code below. The urlConnection.disconnect() gets executed, but the connection remains established on the server.
HttpURLConnection urlConnection = null;
System.setProperty("http.keepAlive", "false");
try {
URL url = new URL(stringUrl);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream instream = new BufferedInputStream(urlConnection.getInputStream());
...
instream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection!=null) {
urlConnection.disconnect();
}
}
The moment all data on input stream is consumed, the connection is released automatically and added to the connection pool. The underlying socket connection is not released, assuming the connection will be reused in near future. It is a good practice to call disconnect in finally block, as it takes care of connection release in case of exceptions.
Here is the implementation of read method of FixedLengthInputStream:
#Override public int read(byte[] buffer, int offset, int count) throws IOException {
Arrays.checkOffsetAndCount(buffer.length, offset, count);
checkNotClosed();
if (bytesRemaining == 0) {
return -1;
}
int read = in.read(buffer, offset, Math.min(count, bytesRemaining));
if (read == -1) {
unexpectedEndOfInput(); // the server didn't supply the promised content length
throw new IOException("unexpected end of stream");
}
bytesRemaining -= read;
cacheWrite(buffer, offset, read);
if (bytesRemaining == 0) {
endOfInput(true);
}
return read;
}
When bytesRemaining variable becomes 0, endOfInput is called which will futher call release method with true parameter, which will ensures the connection is pooled.
protected final void endOfInput(boolean reuseSocket) throws IOException {
if (cacheRequest != null) {
cacheBody.close();
}
httpEngine.release(reuseSocket);
}
Here is the release method implementation. The last if check ensures whether connection need to be closed down or added to the connection pool for reuse.
public final void release(boolean reusable) {
// If the response body comes from the cache, close it.
if (responseBodyIn == cachedResponseBody) {
IoUtils.closeQuietly(responseBodyIn);
}
if (!connectionReleased && connection != null) {
connectionReleased = true;
// We cannot reuse sockets that have incomplete output.
if (requestBodyOut != null && !requestBodyOut.closed) {
reusable = false;
}
// If the headers specify that the connection shouldn't be reused, don't reuse it.
if (hasConnectionCloseHeader()) {
reusable = false;
}
if (responseBodyIn instanceof UnknownLengthHttpInputStream) {
reusable = false;
}
if (reusable && responseBodyIn != null) {
// We must discard the response body before the connection can be reused.
try {
Streams.skipAll(responseBodyIn);
} catch (IOException e) {
reusable = false;
}
}
if (!reusable) {
connection.closeSocketAndStreams();
connection = null;
} else if (automaticallyReleaseConnectionToPool) {
HttpConnectionPool.INSTANCE.recycle(connection);
connection = null;
}
}
}
Note: I had previously answered couple of SO questions related to HttpURLConnection, which can help you in understanding the underlying implementation. Here are the links : Link1 and Link2.
As per how the TCP protocol works, when you close a connection, it doesn't automatically disappear from within your socket list.
When you send the termination signal to the other part, there starts a protocol (a procedure, morelike), where the first step is precisely your intention of closing the connection. You send a signal to the other node and that would involve the FIN_WAIT1 status.
When the user has received that signal, the next step is to acknowledge it from the remote side. This means that the opposite server sends you another signal symbolizing that the node is ready to close the connection too. That would be the FIN_WAIT2 status.
Between these two steps, it might happen that the remote node hasn't responded yet (so you're not been acknowledged that you want to close the connection). In that time, you would be in an intermediate state called CLOSE_WAIT (resuming: once you've sent the FIN signal to the remote server and they haven't responded yet).
The TIME_WAIT state would mean that you are giving some graceful time to the server before definitely closing it to receive some packets. You do this because connection anomalies might happen, and the remote server could have not received the 'disconnection' message and send you some packet. So when that happens, instead of creating a new socket between both nodes, you associate it to the one you have in the TIME_WAIT state and simply discard that packet because probably the sequence number will not be ordered.
There are some other states you might see, but according to the way you describe it, it seems pretty normal to me, unless when you call the .disconnect() method, the ESTABLISHED status would last. In that case something's not working as expected (it might be related to some kind of overloading or non-optimized code which might make your execution very slow).
You have to disconnect your open UrlConnection
HttpURLConnection urlConnection = null;
System.setProperty("http.keepAlive", "false");
try {
URL url = new URL(stringUrl);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream instream = new BufferedInputStream(urlConnection.getInputStream());
...
instream.close();
urlConnection.disconnect(); //HERE
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection!=null) {
urlConnection.disconnect();
}
}
Related
According to technical guide from Oracle Java, we should consume HttpURLConnection's error stream when IOException thrown
http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html
What can you do to help with Keep-Alive? Do not abandon a connection
by ignoring the response body. Doing so may results in idle TCP
connections. That needs to be garbage collected when they are no
longer referenced.
If getInputStream() successfully returns, read the entire response
body.
When calling getInputStream() from HttpURLConnection, if an
IOException occurs, catch the exception and call getErrorStream() to
get the response body (if there is any).
Reading the response body cleans up the connection even if you are not
interested in the response content itself. But if the response body is
long and you are not interested in the rest of it after seeing the
beginning, you can close the InputStream. But you need to be aware
that more data could be on its way. Thus the connection may not be
cleared for reuse.
Here's a code example that complies to the above recommendation:
Here's the code example
try {
URL a = new URL(args[0]);
URLConnection urlc = a.openConnection();
is = conn.getInputStream();
int ret = 0;
while ((ret = is.read(buf)) > 0) {
processBuf(buf);
}
// close the inputstream
is.close();
} catch (IOException e) {
try {
respCode = ((HttpURLConnection)conn).getResponseCode();
es = ((HttpURLConnection)conn).getErrorStream();
int ret = 0;
// read the response body
while ((ret = es.read(buf)) > 0) {
processBuf(buf);
}
// close the errorstream
es.close();
} catch(IOException ex) {
// deal with the exception
}
}
Does this applicable to Android platform? As I don't see such technique in most of the Android code example.
If you are not interested in displaying the error message to the user, close the InputStream or invoke disconnect on HttpURLConnection in finally block without reading the error message. This is what you see in most of the examples.
I came across following comment in one of the source code, while browsing the implementation of HttpURLConnection. That could be the reason why connections are closed without reading all data.
This should be invoked when the connection is closed unexpectedly to
invalidate the cache entry and to prevent the HTTP connection from
being reused. HTTP messages are sent in serial so whenever a message
cannot be read to completion, subsequent messages cannot be read
either and the connection must be discarded.
According to Android's implementation of HttpURLConnection, in case of exception:
If error is not read and the InputStream is closed, the connection will be considered as not reusable and closed down.
If you read the error and then close the InputStream, connection is considered as reusable and is added to the connection pool.
You can see in the below image, variable connection & connectionReleased are set to null and true respectively, as soon as all data is read. Note that getErrorStream returns the InputStream, so it is valid in exception scenario also.
Code analysis : Let's look at the FixedLengthInputStream one of the specialized InputStream implementation. Here is the close method implementation:
#Override public void close() throws IOException {
if (closed) {
return;
}
closed = true;
if (bytesRemaining != 0) {
unexpectedEndOfInput();
}
}
Instance variable bytesRemaining contains byte count still available on the InputStream to be read. Here is the unexpectedEndOfInput method implementation:
protected final void unexpectedEndOfInput() {
if (cacheRequest != null) {
cacheRequest.abort();
}
httpEngine.release(false);
}
Here is the release method implementation. Calling disconnect on HttpURLConnection instance leads the call to this release method with false as parameter.
The last if check ensures whether connection need to be closed down or added to the connection pool for reuse.
public final void release(boolean reusable) {
// If the response body comes from the cache, close it.
if (responseBodyIn == cachedResponseBody) {
IoUtils.closeQuietly(responseBodyIn);
}
if (!connectionReleased && connection != null) {
connectionReleased = true;
// We cannot reuse sockets that have incomplete output.
if (requestBodyOut != null && !requestBodyOut.closed) {
reusable = false;
}
// If the headers specify that the connection shouldn't be reused, don't reuse it.
if (hasConnectionCloseHeader()) {
reusable = false;
}
if (responseBodyIn instanceof UnknownLengthHttpInputStream) {
reusable = false;
}
if (reusable && responseBodyIn != null) {
// We must discard the response body before the connection can be reused.
try {
Streams.skipAll(responseBodyIn);
} catch (IOException e) {
reusable = false;
}
}
if (!reusable) {
connection.closeSocketAndStreams();
connection = null;
} else if (automaticallyReleaseConnectionToPool) {
HttpConnectionPool.INSTANCE.recycle(connection);
connection = null;
}
}
}
The code shared by you, in which the IOException is handled, error stream is read and then closed, ensures the Connection is reusable and is added to the connection pool. The moment all data is read from InputStream the Connection is added to the connection pool. Here is the read method implementation of FixedLengthInputStream :
#Override public int read(byte[] buffer, int offset, int count) throws IOException {
Arrays.checkOffsetAndCount(buffer.length, offset, count);
checkNotClosed();
if (bytesRemaining == 0) {
return -1;
}
int read = in.read(buffer, offset, Math.min(count, bytesRemaining));
if (read == -1) {
unexpectedEndOfInput(); // the server didn't supply the promised content length
throw new IOException("unexpected end of stream");
}
bytesRemaining -= read;
cacheWrite(buffer, offset, read);
if (bytesRemaining == 0) {
endOfInput(true);
}
return read;
}
When bytesRemaining variable becomes 0, endOfInput is called which will futher call release method with true parameter, which will ensures the connection is pooled.
protected final void endOfInput(boolean reuseSocket) throws IOException {
if (cacheRequest != null) {
cacheBody.close();
}
httpEngine.release(reuseSocket);
}
If it's documented for Java it's binding for the Android platform.
I am using an asyncTask which runs for every 1 sec.
I must check a condition every 1 sec that the socket connection is available or not before asyncTask starts.
I used socket.isConnected() -> it always returning true.
How to do this.
Please help..
Once a connection is made, isConnected() will always return true.
To check if the connection is still avaialble, you can:
Use socket.getInputStream().Read(). This will block until either some data arrives or the connection closes in which case it will return -1. Otherwise it will return the received byte. If you use socket.setSoTimeout(t) and then call Read(), 3 things can happen:
a) The connection closes and Read() returns -1;
b) Some data arrives and Read() returns the read byte.
c) Read() will block for t miliseconds and throw SocketTimeoutException which means no data was received and the connection is okay.
If you want to ckeck the connection quickly, set the timeout to 1. If you set it to 0, it will block indefinitely which is the default.
Use socket.getInetAddress().isReachable(int timeout).
Its too late but it may help someone else all you need to do is just check for your socket if it is not null and then in case if it is not null just disconnect your socket else create new socket and connect that
if(socket != null)
{
socket.disconnect();
}
else
{
socket.createSocket();
socket.connect();
}
here create socket is method in which you can create your socket
Hope it may help someone.
public class CheckSocket extends AsyncTask<String,String,String>{
#Override
protected String doInBackground(String... strings) {
try {
socket = new Socket("192.168.15.101", 23);
} catch (IOException e) {
e.printStackTrace();
}
if(socket.isConnected()){
Log.d(TAG, "doInBackground: connected");
}else {
Log.d(TAG, "doInBackground: not connected");
}
return null;
}
}
So I have TCP server in Windows that is programmed in C++ and a client in JAVA, Android 4.0.4.
In Android, I connect like this:
public boolean sendConnectRequest()
{
while (isSocketConnected == false)
{
try {
if(comSocket == null)
comSocket = new Socket("192.168.0.1",1531);
isSocketConnected = comSocket.isConnected();
if (isSocketConnected) {
out = comSocket.getOutputStream();
in = comSocket.getInputStream();
}
else
comSocket.close();
}
catch (IOException ex)
{
Log.e("TCP Error", ex.getLocalizedMessage());
}
}
return true;
}
I typically have no problems with this code on the first connection to the server.
When i disconnect from the server, I call this:
public void closeConnection() {
if (comSocket != null)
{
try {
comSocket.close();
isSocketConnected = false;
if (out != null)
out.close();
if (in != null)
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
So here is the problem... I hit the home button on the smartphone, which places the program in pause. I start the program again and it calls the resume function in activity, which in turn starts the process toward reconnection. The connection is attempted and i get no errors. However, my Windows server records no connection. In Windows, I know that I am still blocked at:
SOCKET connectionSocket = accept(tcpNetworkData->socket, (struct sockaddr*)&from, &fromlen);
I believe this is normal. When I am in debug mode on the Android side, I notice that it returns immediately from the line: comSocket = new Socket("192.168.0.1",1531); This should indicate to me that a connection is made.
If you follow me so far... I should also say that if I shut the server down, the client resets by closing the connection and opening a new one. This time the comSocket = new Socket("192.168.0.1",1531) does not block as it should and the execution keeps going. This is obviously wrong. I think it is a resource release problem but why? With Winsock you can solve this problem with this line of code:
int so_reuseaddr = TRUE;
setsockopt(networkData->socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&so_reuseaddr,sizeof(so_reuseaddr));
Can you do something similar with Android or do you have to? Thank you for your help!
According to the javadoc the connection is established once you call the constructor.
Socket(InetAddress address, int port)
Creates a stream socket and connects it to the specified port number at the specified IP address.
When you press the home button, your app goes in background but it does not get killed immediately, so your comSocket might be not null when you get back to your application. In that case you are not calling the constructor again, thus you are not reconnecting to the server. What you should do is
if(comSocket == null){
comSocket = new Socket("192.168.0.1",1531);
}else{
comSocket.connect(new InetSocketAddress("192.168.0.1",1531));
}
(and please please place the curly brackets :-) )
Something to keep in mind is that the isConnected() method isn't very reliable for detecting when the remote side has closed the connection, (here is an example).
You have to figure this out by reading or writing on the associated Input/Output Streams.
Try using PrintWriter.checkError(), which will return true as soon as the client can no longer connect to the server.
This is a continuation of this question because it my orginal question was answered, but it did not solve the bug.
Question:
How do I fix the code hanging on this line inStream.readline()
My Intent:
This is in a thread that will loop through checking if there is an outMessage, if there is, it will send the message.
Next it will check it if there is anything in the in-stream, if there is, it will send it to the handler in my main activity.
Lastly, it will sleep for 1 second, then check again.
This should allow me to read/write multiple times without needing to close and open the socket.
Problem:
It is reading and writing better, but still not working properly
What is happening now:
If outMessage is initialized with a value, upon connection with the server, the socket:
writes and flushes the value (server receives & responds)
updates value of outMessage (to null or to "x" depending on how i have it hard-coded)
reads and shows the response message from the server
re-enters for the next loop
IF i set outMessage to null, it skips over that if statements correctly then hangs; otherwise, if i set outMessage to a string (lets say "x"), it goes through the whole if statement, then hangs.
The code it hangs on is either of the inStream.readline() calls (I currently have one commented out).
Additional info:
- once connected, I can type in the "send" box, submit (updates the outMessage value), then disconnect. Upon re-connecting, it will read the value and do the sequence again until it get stuck on that same line.
Changes since the referenced question:
- Made outMessage and connectionStatus both 'volatile'
- added end-of-line delimiters in neccesary places.
Code:
public void run() {
while (connectionStatus != TCP_SOCKET_STATUS_CONNECTED) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (connectionStatus == TCP_SOCKET_STATUS_CONNECTED) {
try {
if (outMessage != null){
OutStream.writeBytes(outMessage + "\n");
OutStream.flush();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "OUT TO SERVER: " + outMessage);
outMessage = "x";
}
Thread.sleep(100);
// if (InStream.readLine().length() > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
// }
Thread.sleep(1000);
} catch (IOException e) {
connectionLost();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The thread that makes the socket:
public void run() {
setName("AttemptConnectionThread");
connectionStatus = TCP_SOCKET_STATUS_CONNECTING;
try {
SocketAddress sockaddr = new InetSocketAddress(serverIP, port);
tempSocketClient = new Socket(); // Create an unbound socket
// This method will block no more than timeoutMs. If the timeout occurs, SocketTimeoutException is thrown.
tempSocketClient.connect(sockaddr, timeoutMs);
OutStream = new DataOutputStream(tempSocketClient.getOutputStream());
InStream = new BufferedReader(new InputStreamReader(tempSocketClient.getInputStream()));
socketClient = tempSocketClient;
socketClient.setTcpNoDelay(true);
connected();
} catch (UnknownHostException e) {
connectionFailed();
} catch (SocketTimeoutException e) {
connectionFailed();
} catch (IOException e) {
// Close the socket
try {
tempSocketClient.close();
} catch (IOException e2) {
}
connectionFailed();
return;
}
}
Server:
public static void main(String[] args) throws IOException {
String clientSentence;
String capitalizedSentence;
try {
ServerSocket welcomeSocket = new ServerSocket(8888);
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n Listening on IP: " + SERVERIP +"\n\n");
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
while(true)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clientSentence = inFromClient.readLine();
System.out.println("clientSentance == " + clientSentence);
String ip = connectionSocket.getInetAddress().toString().substring(1);
if(clientSentence != null)
{
System.out.println("In from client ("+ip+")("+ System.currentTimeMillis() +"): "+clientSentence);
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence + '\n');
System.out.println("Out to client ("+ip+"): "+capitalizedSentence);
}
}
} catch (IOException e) {
//if server is already running, it will not open new port but instead re-print the open ports information
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n");
System.out.println("Listening on IP: " + SERVERIP +"\n\n");
}
}
Thanks in advance!
Edits:
added the server code after updating
I tried messing around with setting the SoTimout for the socket but took that back out
Your server is specifically designed to receive exactly one line from a client and send exactly one line back. Look at the code:
while (true) {
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(
connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
String ip = connectionSocket.getInetAddress().toString()
.substring(1);
System.out.println("In from client (" + ip + "): "
+ clientSentence);
if (clientSentence != null) {
capitalizedSentence = clientSentence.toUpperCase() + '\n';
System.out.println("Out to client (" + ip + "): "
+ capitalizedSentence);
outToClient.writeBytes(capitalizedSentence + "\n");
}
Notice that inside the loop it accepts a new connection, reads exactly one line, and then writes exactly one line. It doesn't close the connection. It doesn't sanely end the conversation. It just stops reading.
A client that worked with this server would have to connect, send exactly one line, read exactly one line back, and then the client would have to close the connection. Your client doesn't do that. Why? Because you had no idea that's what you had to do. Why? Because you had no design ... no plan.
So that's your specific issue. But please, let me urge you to take a huge step back and totally change your approach. Before you write a single line of code, please actually design and specify a protocol at the byte level. The protocol should say what data is sent, how messages are delimited, who sends when, who closes the connection, and so on.
Otherwise, it's impossible to debug your code. Looking at the server code above, is it correct? Well, who knows. Because it's unclear what it's supposed to do. When you wrote the client, you assumed the server behaved one way. Was that assumption valid? Is the server broken? Who knows, because there's no specification of what the server is supposed to do.
You need to check if there is data available:
if (InStream.available > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
}
But to be honest, even that is not ideal because you have no gurantee that the eond-of-line will have been received. If the server sends a few bytes but never sends the end-of-line then you will still be blocking forever. Production socket code should never rely on readLine but instead read into a buffer and check that buffer for end-of-line (or whatever criteria your protocol needs).
Didn't read closely enough, I thought InStream was an InputStream instance. InputStream has available. InputStreamReader has ready (which in turn calls InputStream.available. As long as you keep a refernce to either of these then you can see if data is available to be read.
I need to have a "stable" connection to a server.
The client tries to connect to the server every 5 (10, N)-seconds.
After having connected successfully the client receives data from the server.
In case of service interruption (server shutdown, for example), go to step #1.
How I test:
I start the server
I start the client (to be sure that client gets data from the server)
I stop the server
I wait for about 200 client attempts to connect to the server.
I restart the server.
The server sends data, but the client doesn't get it.
socket.connect(...) is sucessfull, but
socket.getInputStream().read(byte[]) is not: the Thread blocks on input.read(..).
If I uncomment this line:
//socket.setSoTimeout(500);
then input.read(..) throws a TimeoutException.
But the server receives data from the client.
Where is my wrong?
Thanks.
Part of client code:
private void initSocket() {
try {
if (socket == null || socket.isClosed() == true
|| socket.isConnected() == false) {
socket = new Socket();
// socket.setSoTimeout(500);
InetSocketAddress socketAddress = new InetSocketAddress("192.168.1.3"
, 12344);
notifyDataListener(4);
socket.connect(socketAddress, 500);
notifyDataListener(5);
}
} catch (Throwable t) {
System.err.println(t);
}
}
private void closeSocket() {
try {
if (socket != null && socket.isClosed() == false) {
socket.close();
}
} catch (Throwable t) {
System.err.println(t);
}
}
private byte[] buffer = new byte[1024];
public void run() {
while (isActive) {
try {
notifyDataListener(1);
initSocket();
InputStream input = socket.getInputStream();
int length = input.read(buffer);
if (length < 0) {
throw new EOFException("Was got -1");
}
notifyDataListener(2);
} catch (Throwable t) {
closeSocket();
notifyDataListener(3);
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
}
}
}
}
On J2SE the same code works fine. Connection repairs after many wrong attempts.
It looks like Android has limit slosts of sockets (FileDescriptior?), takes them, but don't release after.
Your likely running out of file descriptors, i'm sure the limit is much lower on android than on a typical desktop configuration but the specific values will vary.
With the way you've coded this, the socket will hang around until its garbage collected, additionally on some platforms, the OS level sockets do not close instantly but hang around for a period of time to clean up any hanging data.
The first thing you should do is move your socket.close() code to finally {} statements which will free the socket immediately rather than waiting for garbage collection.