简体   繁体   中英

Socket input stream hangs on final read. Best way to handle this?

I'm a bit stumped on how to avoid my socket hanging on read. Here's my code:

    Socket socket = new Socket("someMachine", 16003);
    OutputStream outputStream = socket.getOutputStream();
    InputStream inputStream = socket.getInputStream();
    try {
        outputStream.write(messageBuffer.toByteArray());
        outputStream.flush();
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
        StringBuffer response = new StringBuffer();
        int result;
        while ((result = in.read()) != -1) {
            response.append(Character.toChars(result));
            System.out.println(result);
        }
        System.out.println("Done!");  //never gets printed
     } catch (...) {}

The above code successfully reads all the data from the stream but then hangs. Reading up on the net I was expecting to receive a -1 from the server (which I can't control) to indicate that I had reached the end of stream but instead I get this:

(Lots of data above this point)
57
10
37
37
69
79
70
10

It then hangs. So, my questions are:

1) Have I coded this wrong or is there an issue with the server's response?

2) If there is an issue with the server's response (ie no -1 being returned), how can I work around this (ie to stop reading when it hangs).

Any help appreciated!

The problem with just stopping where read would hang is that this can happen in 2 cases:

1: server doesn't have any more data to send

2: The server has sent more data, but your client has not received it yet due to network overload.

And you only want to really stop reading in the first case, but you want read to block in the second case.

The way to solve this is to make a transfer protocol(Standard) which allows the server to tell the client how much data it expects to send.

If the server knows the total data size in advance, simply start by sending the total number of bytes in the transfer, and then send the data. That way the client knows when it have received all data.

(Or the server can simply close the connection when done. That way read should fail, but this only work if you don't need the connection in the future)

I think you will only get -1 when the server decides to stop the conversation, ie closes its output stream or closes the socket completely. Else, the stream stays open for potential future incoming data.

I'm not a Android expert, but this seems to work just fine on Android:

    try {
        telnetClient = new Socket(server, port);
    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    if (telnetClient.isConnected()) {
        try {
            InputStream instr = telnetClient.getInputStream();
            int buffSize = telnetClient.getReceiveBufferSize();
            if (buffSize > 0) {
                byte[] buff = new byte[buffSize];
                int ret_read = instr.read(buff);
                screen.append(new String(buff, 0, ret_read));
            }
        } catch (IOException e) {
            screen.append("Exception while reading socket:" + e.getMessage());
        }
    }

I've just had this exact same problem. I solved it by setting a timeout straight after creating the socket object... socket.setSoTimeout(10 * 1000);

I found this problem to be pretty formidable. I was trying to execute a windows batch command from java and the process hangs every time trying to read the inputstream from the command getting executed.

I could only fix this inelegantly.

a) By looking for a specific line which I know would signal the end useful information form the stream.
b) Or to start a new Thread that kills the process at the other end of the socket, in this case for me IEDriverServer.exe after a wait time.

String[] cmdArray = {"cmd.exe","/c",cmd+ " 2>&1" };
    InputStream is = new ProcessBuilder(cmdArray).directory(f).start().getInputStream();

        error_buffer = new BufferedReader(new InputStreamReader(is));
        int lines=0;

        while((line=error_buffer.readLine())!=null){
            if(line.startsWith("[INFO] Final Memory: ")) {
                break;
            }

            log.debug("Reading cmd Stream "+line);
            buf.append(line);
            lines++;
        }

尝试:

while ((result = in.read()) != null) {

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM