Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OutputStream.write() successful but the data is not delivered [closed]

I have a very strange behaviour during writing to a socket. In my mobile client I'm using a socket which is initialized as follows:

private void initSocket()
{
    socket = new Socket();
    socket.connect(new InetSocketAddress(host, port));

    os = new DataOutputStream(socket.getOutputStream());
    is = new DataInputStream(socket.getInputStream());
}

then periodically (every 60 seconds) I read and write some data to this socket (the code here is a little bit simplified):

if(!isSocketInitialized())
{
    initSocket();
}

byte[] msg = getMessage();

os.write(msg);
os.flush();

int bytesAvailable = is.available( );
if(bytesAvailable>0)
{
    byte[] inputBuffer = new byte[bytesAvailable];

    int numRead = is.read(inputBuffer, 0, bytesAvailable);
    processServerReply(inputBuffer, numRead);
}

And it works. But... Sometimes (very infrequently, maybe 1 or 2 times per day) my server don't receive data. My client log looks like:

Written A
Written B
Written C
Written D
Written E

and so on. But on the server side it looks like:

Received A
Received E

B,C,D data records were not received, despite of fact that on the client side it looks like all data was sent without any exceptions!

Such gaps can be small (2-3 minutes) which is not very bad, but sometimes they can be very big (1-2 hours = 60-120 cycles) and it is really a problem for my customers.

I really have no idea what can be wrong. The data seems to be sent by client, but it never arrives on the server side. I've checked it also with a proxy.

I have only logs and I can't reproduce this issue (but it happens to my customer more then one time every day) and in logs sometimes I see that the connection is broken with an Exception "sendto failed: ECONNRESET (Connection reset by peer)". After that the program closes the socket, reinitializes it:

// close
is.close();
os.close();
socket.close();

// reinitialize
initSocket();

and tries to write the data again as described above. Then I see the problem: connection established, writing successful, but NO DATA arrived on the server!

May be it has something to do with ECONNRESET may be not, but I want to mention this because may be it is important.

I would be very grateful for any ideas and tips.

P.S. Maybe it plays some role: the client code runs on an Android mobile device which is moving (it is in a car). The internet connection is established through GPRS.


UPD: I can reproduce it! At least partially (the client send A,B,C,D,E and the server receives only A). It happens every time if:

  1. The connection is established, the client reads and writes -> OK

  2. The connection is lost (I turn off my WLAN router :)), I became IOException, I close the streams and socket -> OK

  3. I turn on my router, the connection is back, I initialize the socket again, the program executes write() without exceptions, but... no data arrives at the server.

BTW since the connection is back again available() returns always 0.

like image 282
Valelik Avatar asked Oct 25 '12 19:10

Valelik


2 Answers

Get rid of the available() test. If the peer is suppose to reply, just read it. Otherwise sometimes you will be reading the reply and sometimes you won't, and you will get out of sync. There are very few correct uses of available(), and this isn't one of them.

like image 147
user207421 Avatar answered Oct 28 '22 10:10

user207421


The cause of this strange behavior was a not closed socket on the server side. I could reproduce it with small client and server. Both consist of couple of lines of code, which do the following:

  1. connect to the server
  2. simulate a dead spot (e.g. turn off your WiFi)
  3. close the socket on client side
  4. DON'T CLOSE the socket on server side
  5. turn on your WiFi
  6. establish a new connection from client
  7. write data to this connection

Voila! The client writes data without any errors, but the server doesn't receive it...

But if the server closes the socket too, then the server can read this data. So the solution should be to close the socket after a timeout on the server side.

Unfortunately in my case it is not viable, because the server is a proprietary third-party software.

like image 43
Valelik Avatar answered Oct 28 '22 08:10

Valelik