0

I am having a socket listener program running(eclipse) on a mac machine and iOS client app is sending image to it in Bytes format. Normally, Image bytes will be 40 K and above. I am facing a strange issue while reading the image bytes in socket. I have checked many links, they are suggesting to use like below code for reading all the bytes. The issue is, its reading all the bytes and NOT coming out of 'While' loop. After reading all the bytes, just struck inside the while loop only. I don't know what to do? Could someone please help me to solve this issue?

InputStream input = socket.getInputStream();

ByteArrayOutputStream baos = new ByteArrayOutputStream();    
byte[] bufferr = new byte[1024];
int read = 0;
long numWritten = 0;
try { 
    // Tried both the below while conditions, both are giving same issue     
    // while ((read = input.read(bufferr, 0, bufferr.length)) != -1) 

    while ((read = input.read(bufferr)) > 0) {
        baos.write(bufferr, 0, read);

        numWritten += read;
        System.out.println("numWritten: " + numWritten);      
    }
} catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}  
try {
    baos.flush();
} catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}   
byte[] data = baos.toByteArray();

The below is my iOS code. I am closing the stream, still the same issue.

    -(void) shareImage
{
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    UIGraphicsBeginImageContext(appDelegate.window.bounds.size);
    [appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData * data = UIImagePNGRepresentation(image);
    //[data writeToFile:@"screenshot.png" atomically:YES];

    NSLog(@"[data length] %i: ", [data length]);
    self.sentPing = YES;

    int num = [self.outputStream write:[data bytes] maxLength:([data length])];
    if (-1 == num) {
        NSLog(@"Error writing to stream %@: %@", self.outputStream, [self.outputStream streamError]);
    }else{
        NSLog(@"Wrote %i bytes to stream %@.", num, self.outputStream);
        [self.outputStream close];

        //NSTimer *myRegularTime = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(ShareNextScreen:) userInfo:nil repeats:NO];
    }

}
Stella
  • 1,728
  • 5
  • 41
  • 95
  • 1
    possible duplicate of [java inputstream read blocking](http://stackoverflow.com/questions/611760/java-inputstream-read-blocking) – Michael J. Gray Feb 12 '14 at 17:45
  • I'll be downvoting this since it's a duplicate of more than two. Here's a second one: https://stackoverflow.com/questions/20552223/socket-inputstream-blocks-on-available-read – Michael J. Gray Feb 12 '14 at 17:51
  • or you can have a look @ http://stackoverflow.com/questions/8679112/read-image-file-through-java-socket – pratikch Feb 12 '14 at 17:52
  • 1
    Hello Michael, You can't down vote this. That links doesn't give the answer what I need. Even after closing the stream, i couldn't get the while loop thru. – Stella Feb 12 '14 at 17:55
  • @Catherine Actually I can downvote it for any reason, even a not so legitimate one. But, whether or not that's reasonable is subjective. People do it all that time, but I choose not to. Based on the original content of your post, you did not explain that you were closing the connection on the server side and client side in an attempt to start a mutual teardown of the TCP connection. I will retract my downvote because you have updated your question. – Michael J. Gray Feb 12 '14 at 18:00

2 Answers2

0

input.read(buffer) will block until data is received. If the stream is closed, it will return -1 as you are testing for. But, since the stream is still open and is waiting for data to arrive, it'll block.

Since you did update your question, I will update my answer. Closing a stream is not the same as terminating a TCP session.

Closing a stream will put the connection into FIN_WAIT_1 or FIN_WAIT_2 and it needs to finish and reset to be fully closed. You need to tell your server that you're shutting down your client and then shut down, or tell the client you're shutting down the server, and then close. Basically, both sides need to close when they wish to terminate the connection. Closing also may, depending on your environment, not even do anything but release references.

In most implementations of low level socket APIs, you have socket_shutdown(2) which actually sends the FIN TCP packet for a mutual shutdown initiation.

Basically both parties need to close, or the connection will be stuck in a waiting state. This is a defined behavior in various RFCs. An explanation can be found here.

From the post I linked, you can review the diagram here.

Michael J. Gray
  • 9,784
  • 6
  • 38
  • 67
  • No..Please check my updated question. I am closing the stream after writing it, still the same issue. – Stella Feb 12 '14 at 17:52
  • @MichaelJ.Gray Your edit isn't correct. The peer only has to close and therefore issue a FIN for the read to unblock and return -1. The local application won't normally close *until* that has happened. Your recommendation doesn't make sense. – user207421 Feb 12 '14 at 18:02
  • @EJP Close or shutdown? Most implementations I have dealt with will treat close as a release of resources only and will not actually teardown the session, it'll simply prevent the system from reading data and will result in the remote host timing out the connection after a while. Shutting down a socket will immediately send the correct responses out to start the process of tearing down the session. Both sides have to agree to shutdown at some point, and usually when they disagree, a `RST` will be sent by one of the parties. Go try setting up a session and use tcpdump, you'll see! – Michael J. Gray Feb 12 '14 at 18:09
  • Hi All, I want to keep sending such images from iOS app to Socket. If I close the socket after sending one image, How can i send it again with the same session? – Stella Feb 12 '14 at 18:11
  • @Catherine In your application layer protocol you will need to decide how to handle that behavior. Usually this is done by marking the end of your image or prefixing a message with the length of the image, etc. – Michael J. Gray Feb 12 '14 at 18:13
  • oh ok..Good idea.. Lets say, If thats the case, i can append like "[data appendBytes:"END" length:3];" end of each image byte data and send to socket. In the socket, When I read all bytes, if i found that this "END", i can break the while loop programmatically. Can i do like this? – Stella Feb 12 '14 at 18:20
  • @Catherine Yep! You can do that. I would use binary instead of text, but the principle is the same. – Michael J. Gray Feb 12 '14 at 18:21
  • @MichaelJ.Gray I have never dealt with such an implementation, and I doubt that you have either. Every implementation I have ever used since about 1983 issues a FIN when you call close() (unless the socket FD has been inherited and is still open in a related process, or if it has already been issued by calling shutdown for output). Your recommendation doesn't make sense and isn't even implementable. Where exactly in the OP's code should the close or shutdown be issued? The only possible place is after the read loop has exited. According to your recommendation this point is unreachable. – user207421 Feb 12 '14 at 18:21
  • @EJP When the protocol processor encounters a terminal condition or operation it should invoke `shutdown` and then `close`, one right after another if it wants. That should cause any blocked operations to unblock and return with `-1` or their appropriate result for that kind of situation. Also, your "doubts" detract from the discussion I believe, so please keep them to yourself. You're free to voice your opinion if you wish, but it's just not very professional to basically call someone a liar in an open forum without any evidence. – Michael J. Gray Feb 12 '14 at 18:27
  • Your idea of appending bytes and detecting that on the socket to break, is working fine. Thanks Michael a lot! – Stella Feb 12 '14 at 19:21
0

You are reading to end of stream but the peer hasn't closed the connection. So, you block.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • No..Please check my updated question. I am closing the stream after writing it, still the same issue. – Stella Feb 12 '14 at 17:54
  • If you were closing the connection, the loop would unblock. Ergo you aren't. This is a fact of TCP. I don't know anything about IOS coding so I can't advise you how to close the connection. – user207421 Feb 12 '14 at 18:00