【问题标题】:java.net.Socket > InputStream > BufferedReader.read(char[]) blocks threadjava.net.Socket > InputStream > BufferedReader.read(char[]) 阻塞线程
【发布时间】:2015-03-09 20:43:54
【问题描述】:

我正在尝试使用 BufferedReader.read(char[]) 方法而不是更简单但通用性较差的 BufferedReader.readLine() 方法来接收来自服务器的答案。 BufferedReader 与 BufferedOutputStream 并行使用,在下面的代码中,read(char[]) 方法会阻塞所有内容,最后一个控制台输出是“新缓冲区,等待读取。

客户:

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();
    }
}

}

服务器:

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();
        }
    }
}

主要:

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();
        }
    }
}

只要不调用 BufferedReader.read,一切正常。但是由于现在的代码,输出似乎没有发送到服务器。

更新

正如@JB Nizet 所回答的,问题在于使用 readLine() 并等待 EOL 字符或连接结束的服务器脚本。因此,在客户端发送的消息中添加“\n”解决了死锁:

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

【问题讨论】:

  • while (ix != -1) 我认为返回的字符为空。尝试重写:while( (ix = br.read() ) != null )
  • 它是否适用于readLine()?如果是这样,请尝试检查循环中是否有InputStream.available() > 0,这样我们就不会无限期地检查流中的下一个char(阻塞进程中的线程)。
  • @thekiwi5000,我希望我可以否决您的评论,ints 不能为空。不过Integers 可以。
  • @MeetTitan thaks,我会记住这一点的。

标签: java multithreading sockets tcp deadlock


【解决方案1】:

当服务器接受来自客户端的连接时,它做的第一件事是:

String line = br.readLine();

因此,它会一直阻塞,直到客户端发送完整的文本行。服务器仅在读取 EOL 字符或客户端关闭流时才知道该行已完成。

当客户端启动时,它做的第一件事就是

bo.write(message.getBytes());

message 是一行文本,没有任何 EOL。然后客户端做

ix = br.read(c);

所以它等待来自服务器的响应,而服务器本身也在等待来自客户端的 EOL。

您已经实现了网络死锁。

【讨论】:

    猜你喜欢
    • 2013-01-05
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 2015-12-04
    • 2016-01-27
    • 1970-01-01
    • 2018-02-16
    相关资源
    最近更新 更多