简体   繁体   中英

java.net.Socket > InputStream > BufferedReader.read(char[]) blocks thread

I'm trying to use BufferedReader.read(char[]) method instead of the easier, but less versatile BufferedReader.readLine() method for receiving an answer from a Server. BufferedReader is used in parallel with BufferedOutputStream and, in the code below, the read(char[]) method blocks everything, the last console output is " new buffer, waiting to read. "

Client:

public class MessageSender extends Thread {
private String message;
MessageSender(String message) {
    this.message = message;
}

public void run() {
    try {
        Socket sk = new Socket("192.168.1.4", 3000);
        BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
        bo.write(message.getBytes());
        bo.flush();

        char[] c = new char[100];

        BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
        StringBuffer sb = new StringBuffer();
        System.out.println("new buffer, waiting to read.");
        int ix = 0;

        while (ix != -1) {
            ix = br.read(c);
            sb.append(new String(c));
        }

        String message = sb.toString();

        System.out.println("reply: " + message);

        sk.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

Server:

public class MessageReceiver extends Thread {
    public void run() {
        try {
            ServerSocket ss = new ServerSocket(3000);
            System.out.println("server socket open");
            while (true) {
                Socket sk = ss.accept();
                System.out.println("new connection");
                BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
                String line = br.readLine();
                System.out.println("received line: " + line);
                BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
                bo.write("ack".getBytes()); bo.flush(); //bo.close();
                sk.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Main:

public class Main {

    public static void main(String[] args) {
        MessageReceiver mr = new MessageReceiver();
        mr.start();
        while (true) {
            String msg = new Scanner(System.in).nextLine();
            MessageSender ms = new MessageSender(msg+"");
            ms.start();
        }
    }
}

Everything works fine as long as the BufferedReader.read is not called. But as the code is right now, the output doesn't seem to get sent to the server.

UPDATE

As answered by @JB Nizet, the problem lies in the server script that uses readLine() and waits for either EOL character or the connection end. Therefore, adding "\\n" to the message sent from the client side solved the deadlock:

bo.write((message+"\n").getBytes());

When the server accepts a connection from the client, the first thing it does is:

String line = br.readLine();

So, it blocks until the client sends a complete line of text. The server only knows the line is complete if it reads an EOL character, or if the stream is closed by the client.

When the client starts, the first thing it does is

bo.write(message.getBytes());

And message is a line of text, without any EOL. Then the client does

ix = br.read(c);

so it waits for a response from the server, which is itself waiting for an EOL from the client.

You have implemented a networked deadlock.

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