java.net.Socket > InputStream > BufferedReader.read(char[]) 阻塞线程
java.net.Socket > InputStream > BufferedReader.read(char[]) blocks thread
我正在尝试使用 BufferedReader.read(char[]) 方法而不是更简单但不太通用的 BufferedReader.readLine() 方法来接收来自服务器的应答。 BufferedReader 与 BufferedOutputStream 并行使用,在下面的代码中,read(char[]) 方法阻塞了所有内容,最后的控制台输出是“new buffer, waiting to read.”。 =16=]
客户:
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());
当服务器接受来自客户端的连接时,它做的第一件事是:
String line = br.readLine();
因此,它会阻塞,直到客户端发送完整的文本行。服务器只有在读取到 EOL 字符或流被客户端关闭时才知道该行已完成。
当客户端启动时,它做的第一件事是
bo.write(message.getBytes());
而message
是一行文字,没有任何EOL。然后客户端做
ix = br.read(c);
所以它等待来自服务器的响应,而服务器本身正在等待来自客户端的 EOL。
您已经实现了网络死锁。
我正在尝试使用 BufferedReader.read(char[]) 方法而不是更简单但不太通用的 BufferedReader.readLine() 方法来接收来自服务器的应答。 BufferedReader 与 BufferedOutputStream 并行使用,在下面的代码中,read(char[]) 方法阻塞了所有内容,最后的控制台输出是“new buffer, waiting to read.”。 =16=]
客户:
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());
当服务器接受来自客户端的连接时,它做的第一件事是:
String line = br.readLine();
因此,它会阻塞,直到客户端发送完整的文本行。服务器只有在读取到 EOL 字符或流被客户端关闭时才知道该行已完成。
当客户端启动时,它做的第一件事是
bo.write(message.getBytes());
而message
是一行文字,没有任何EOL。然后客户端做
ix = br.read(c);
所以它等待来自服务器的响应,而服务器本身正在等待来自客户端的 EOL。
您已经实现了网络死锁。