慎用bufferedWriter的readLine()方法

谁借莪1个温暖的怀抱¢ 2024-02-19 15:45 96阅读 0赞

为什么要慎用呢?

BufferReader的read方法和readLine方法在任何情况下都是阻塞的。readLine方法每次读一行,相对于一个字符/字节地读取、转换、返回来说,它有一个缓冲区,读满缓冲区才返回;一般情况下,都建议使用它们把其它Reader/InputStream包起来,使得读取数据更高效;对于文件来说,经常遇到一行一行的,特别符合情景。 如果不指定buffer大小,则readLine()使用的buffer有8192个字符。在达到buffer大小之前,只有遇到”/r”、”/n”、”/r/n”才会返回,否则一直阻塞。

说来也是惭愧,这个方法用了无数次,却从未注意过这个方法是阻塞的。今天用socket写了聊天小demo,问题出现了,程序走到readLine()这个地方,一直阻塞着不往下走,结果就发现了这个隐藏很久的坑。

解决办法也比较简单粗暴,就是在传输的字符串后面加上换行符。t和曾经做过一个项目现象比较类似,服务端是netty写的,用来接受不同厂商通过网络设备发送来的消息,在接入的过程中很多厂商的设备的消息发送后都没有返回任何消息,后来在分析中发现,由于接入协议中,要求每隔五分钟各个设备要向服务端发送一条消息,消息的格式是字符串,很多厂商在连接后没有关闭连接,消息与消息之间也没有任何标识一条消息结束的标识符号,出现了粘包。解决方法也差不多,1、传输完成后,必须关闭连接2、每条消息结尾加上换行符’\n‘;

下面贴上代码,有兴趣可以关注一下我,一起讨论下:

NetServer.java:

package com.sq.gaox.io.demo2;

import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;

/**

* @Auther: Administrator

* @Date: 2019/1/11 14:45

* @Description:

*/

public class NetServer {

public static void main(String[] args) {

try {

ServerSocket serverSocket=new ServerSocket(7070);

System.out.println(“server is running”);

while (true){

Socket socket= serverSocket.accept();

new Thread(new DoSomeThing(socket)).start();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

DoSomeThing.java:

package com.sq.gaox.io.demo2;

import java.io.*;

import java.net.Socket;

/**

* @Auther: Administrator

* @Date: 2019/1/11 14:47

* @Description:

*/

public class DoSomeThing implements Runnable {

private Socket socket;

public DoSomeThing(Socket socket) {

this.socket = socket;

}

@Override

public void run() {

System.out.println(“连接成功,”+ socket.getInetAddress()+”,当前线程:”+Thread.currentThread().getName());

BufferedReader bufferedReader=null;

// PrintWriter printWriter=null;

BufferedWriter bufferedWriter=null;

try {

bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));

// printWriter=new PrintWriter(socket.getOutputStream());

bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

String receiveMsg=bufferedReader.readLine();

System.out.println(“服务端收到消息:”+receiveMsg.toString());

// printWriter.println(“hello , this is server”);

// printWriter.flush();

bufferedWriter.write(“this is server by bufferedwriter\r”);

bufferedWriter.flush();

} catch (IOException e) {

e.printStackTrace();

}finally {

if(socket!=null){

try {

socket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

// if (printWriter != null) {

// printWriter.close();

// }

if (bufferedReader != null) {

try {

bufferedReader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

NetClient.java:

package com.sq.gaox.io.demo2;

import java.io.*;

import java.net.Socket;

/**

* @Auther: Administrator

* @Date: 2019/1/11 14:51

* @Description:

*/

public class NetClient {

public static void main(String[] args) {

Socket socket = null;

// PrintWriter printWriter = null;

BufferedWriter bufferedWriter=null;

BufferedReader bufferedReader = null;

try {

socket = new Socket(“localhost”, 7070);

// printWriter = new PrintWriter(socket.getOutputStream());

bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

// printWriter.println(“hello , this is client”);

// printWriter.flush();

bufferedWriter.write(“hello , this client by bufferwriter\r”);

bufferedWriter.flush();

String receiveMsg=bufferedReader.readLine();

System.out.println(“服务端收到消息:” + receiveMsg.toString());

} catch (IOException e) {

e.printStackTrace();

}finally {

if(socket!=null){

try {

socket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

// if (printWriter != null) {

// printWriter.close();

// }

if (bufferedReader != null) {

try {

bufferedReader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

发表评论

表情:
评论列表 (有 0 条评论,96人围观)

还没有评论,来说两句吧...

相关阅读

    相关 方法——重载

    前言: 何为重载,类中两个方法同名,但是参数列表不同,称为重载。注意,是参数列表,不是返回值,实际上同名方法同参数列表,但不同返回值是不允许的。 // 重载示例,重载

    相关 Distinct

    大多数情况下,Distinct函数都会导致对最终结果集完成一次排序,因此,这就成为成本最昂贵的排序之一。Distinct一直是SQL语言中成本最高的函数之一。不过,对于DB2V