3

I'm pretty new to Java sockets and I'm having problems using the same socket to send and receive data.

The server is on an Android device:

    ServerSocket listenSocket = null;
    OutputStream dataOutStream = null;
    Socket socket = null;
    InputStream dataInputStream = null;

    // Listen
    System.out.println("Start listening");
    try {
        listenSocket = new ServerSocket(4370);
        socket = listenSocket.accept();
        System.out.println("Connection accepted");
        dataInputStream = socket.getInputStream();
        dataOutStream = socket.getOutputStream();
        while (dataInputStream.read() != -1);
    } catch (IOException e) {
        e.printStackTrace();
        close(listenSocket, socket);
        return;
    }

    // Answer
    System.out.println("Answering...");
    byte[] answer = {(byte) 0x82, (byte) 0xf8, 0, 0};
    try {
        dataOutStream.write(answer);
    } catch (IOException e) {
        e.printStackTrace();
        close(listenSocket, socket);
        return;
    }

    close(listenSocket, socket);
    System.out.println("Finished");

The client runs on a Linux machine with Java 6:

    Socket socket = new Socket("192.168.1.33", 4370);
    OutputStream dataOutputStream = socket.getOutputStream();
    InputStream dataInputStream = socket.getInputStream();
    byte[] bufferOut = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    dataOutputStream.write(bufferOut);
    System.out.println("Sent");

    while (dataInputStream.read() != -1);       
    socket.close();
    System.out.println("Finished");

The problem here is that the server gets stuck while (dataInputStream.read() != -1); line. Looks like the client never closes the sending.

If I do dataOutputStream.close() in the client part (after writing, of course), then it does work but then the client dies on while (dataInputStream.read() != -1); saying the socket has been closed.

I want to keep the whole socket open for more data interchange over this same socket until a closing command is sent.

I'm obviously doing something wrong here, any insights? Thanks in advance!

m0skit0
  • 25,268
  • 11
  • 79
  • 127

3 Answers3

12

You neither close the socket nor the outputstream. You do a shutdownOutput() in the client side:

...
dataOutputStream.write(bufferOut);
System.out.println("Sent");
socket.shutdownOutput();
...

This is called a half close, since it closes only one direction and leaves the other direction open.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • What happens if dataOutputStream.close() is called? Will it still be a half close? – sgp15 Oct 15 '12 at 17:11
  • @sgp15 This is already in the question above: "If I do dataOutputStream.close() ... then the client dies on while (dataInputStream.read() != -1); saying the socket has been closed. – Olaf Dietsche Oct 15 '12 at 17:15
  • Searching after the fact. See also: [Java socket problems half closing](http://stackoverflow.com/questions/3626401/java-socket-problems-half-closing) and [Does closing the inputstream of a socket also close the socket connection?](http://stackoverflow.com/questions/3956163/does-closing-the-inputstream-of-a-socket-also-close-the-socket-connection) – Olaf Dietsche Oct 15 '12 at 17:18
  • Will try this, but actually I want to keep the whole socket open for more data interchange over this same socket until a closing command is sent. Any ideas? – m0skit0 Oct 15 '12 at 18:19
  • 2
    Testing for `stream.read() != -1` means EOF. If you don't want to (half) close the stream, you must test for some other end marker, as @Pyranja already suggested. – Olaf Dietsche Oct 15 '12 at 18:39
  • Developer's bow to you! – Prince Bansal Sep 29 '16 at 23:27
2

edit : Olaf showed a built-in way to realize the request-response scenario in the question.

Closing a stream obtained from a socket also closes the socket (see also).On the other hand it is impossible for the InputStream obtained from a socket to see if all the data was sent as long as the stream/socket is open(there could be more bits on its way!). A 2-way communication can not work this way, unless using Olafs example. That allows to wait for the server response.

What you can do is define an end-signal yourself (e.g. the string "END") and either side listens until that end signal is read, then writes. But that comes with all sorts of other problems you will encounter for sure (what if the sent text contains the end signal? what if the partner dies before sending end? timeouts?...). see also

I would try and look at SOAP or RESTful services that are well supported in Java (but I don't know how well on Android). Generally there are many libraries that tackle these problems for you and relieve you from the low level networking. It almost always pays off to use an existing solution.

Community
  • 1
  • 1
Pyranja
  • 3,529
  • 22
  • 24
  • If length of message can be determined beforehand one can also send first few bytes (e.g. 4 bytes) to indicate length of payload to follow. – sgp15 Oct 15 '12 at 17:13
  • Thanks for the answer, but I cannot use anything besides TCP. This is for an already implemented protocol over TCP. – m0skit0 Oct 15 '12 at 18:18
  • Technically speaking SOAP and REST do use TCP... (: But using a header containing the length of following data as @sgp15 suggested is also a viable alternative. Could simplify error handling. Generally speaking you have to somehow define a communication protocol that clearly marks the bounds of exchanged messages if you want to use on socket connection. – Pyranja Oct 15 '12 at 19:31
  • Absolutely right. I completely forgot that the custom protocol on top of TCP has start-end markers. Thanks! – m0skit0 Oct 15 '12 at 21:36
0

Try flushing the OutputStream by doing dataOutStream.flush()

Pradeep Pati
  • 5,779
  • 3
  • 29
  • 43
  • on the client, i was doing `outStream.write(outPacket);` then reading, but the server wasn't receiving the packet correctly. flushing after writing worked for me! – wrapperapps Mar 01 '16 at 17:45