Java-readLine()阻塞问题及解决过程
作者:昫 灬
文章主要讨论了socket编程中readLine()方法的阻塞问题,在使用readLine()接收消息时,如果没有换行符,则会一直阻塞,解决方法是在发送消息时添加换行符,或者为每个客户端创建独立的转发线程
socket编程中readLine()阻塞问题
readLine()的API说明
- public String readLIne() throws IOException
中文版:
- 读一行文字。 一行被视为由换行符(’\ n’),回车符(’\ r’)中的任何一个或随后的换行符终止。
- 返回:包含行的内容的字符串,不包含任何行终止字符,如果到达流末尾,则为null
英文版:
- Reads a line of text. A line is considered to be terminated by any one of a line feed (’\n’), a carriage return (’\r’), or a carriage return followed immediately by a linefeed.
- Returns:
- A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
遇到的问题:
- 当使用socket写一个双向通信的服务端时,总是接收不到来自用户的消息,和书上比对才发现是readLine()的问题,
- 还有就是客户端和服务端的初始状态问题(一个为初始为“发送”,一个为“接收”)
第一种情况
- 一个客户端,一个服务端。当服务端使用
readLine()读消息时,需要读到一个换行符(‘\n’,或’\r’)才会结束。否则回一直阻塞,主线程就挂在这儿了 - 解决方法:在客户端发送消息的时候,外加一个换行符
//用户发送消息的线程
class SentMessage extends Thread{
private Socket socket;
private BufferedWriter bw;
private BufferedReader mysc;
SentMessage(Socket socket){
this.socket = socket;
try {
bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
mysc = new BufferedReader(new InputStreamReader(System.in));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run(){
try{
while (true){
String mymessage = mysc.readLine();
bw.write(mymessage+"\n");
bw.flush();
if("bye".equals(mymessage)){
break;
}
}
}catch (IOException e){
e.printStackTrace();
}finally {
try{
if(mysc!=null){
mysc.close();
}
if(bw!=null){
bw.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
第二种
- 当用服务器转发来自每个用户的消息到聊天室时,如果就用一个"转发消息"方法也会出现问题,就是使用了readLine()的阻塞
- 思考:一个客户都应有一个自己”转发消息“通道(线程),不和其他客户共用一个”转发通道“(会导致阻塞
- 解决,用一个线程来做转发
//内置线程类用于接收消息,并广播
class AcceptMessage extends Thread{
private Socket clientsocket;
private BufferedReader br;
AcceptMessage(Socket clientsocket){
this.clientsocket = clientsocket;
}
/**
* 服务器将所有接收的消息广播(显示在每一个客户的聊天窗口中
* 注意:如果这里不用线程,会出现问题,思考---其实就是readLine()阻塞的问题
*/
private void tellEveryone(Socket socket){
try{
//先从发送消息的客户读内容
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = br.readLine();
chatArea.append("用户"+socket.getPort()+": "+message+"\n");
//然后将内容广播到每一个客户接口
Iterator<Socket> it = list.iterator();
while (it.hasNext()){
Socket socket2 = it.next();
//对自己就不要广播了
if(socket!=socket2){
bw = new BufferedWriter(new OutputStreamWriter(socket2.getOutputStream()));
bw.write(socket2.getInetAddress().getHostAddress()+": "+message+"\n");
bw.flush();
}
}
}catch (IOException e){
e.printStackTrace();
}
}
@Override
public void run(){
while (true){
//接收并广播
tellEveryone(clientsocket);
}
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
