【问题标题】:BufferedWriter/PrintWriter/OutputStreamWriter don't flush buffer until .close() is called (over socket outputstream)BufferedWriter/PrintWriter/OutputStreamWriter 在调用 .close() 之前不会刷新缓冲区(通过套接字输出流)
【发布时间】:2014-08-10 07:39:18
【问题描述】:

每当我在标题中的任何作者(正在包装 OutputStreamWriter)上调用 .flush() 时,都不会发送刷新的数据;然而,当 .close() 在 writer 上被调用时,它会刷新并且服务器可以读取数据。我不知道我是不是错误地调用了.write().readLine(),或者由于读取操作已经阻塞,这就是问题所在?我需要找到一种在不关闭套接字的情况下刷新数据的方法(我将在另一个程序中使用它)。在我拥有的两个 SSCCE 中,都有System.out.println() 用于调试。在客户端,它将转到“检查 4”并且什么都不循环(它在实际程序中做更多的读取和写入,只是在示例中不能关闭它)。在服务器中,它会进入“检查 2”并阻止 reader.readLine()。我已经阅读了 SO,但我想出的只是readLine() 对于网络程序来说不是一个好主意,我应该实现自己的协议;然而,没有一篇文章指向一个好的教程网站,或者任何其他有好的网络编码教程。以下是 SSCCE:

客户 SSCCE

package testClient;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class Client {

    public static void main(String[] args) {
        try {
            Socket s = new Socket("127.0.0.1",48878);
            System.out.println("check 1");
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
            System.out.println("check 2");
            pw.write("Hello StackOverFlow.");
            System.out.println("check 3");
            pw.flush();
            System.out.println("check 4");
            while(true){}
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

服务器 SSCCE

package testServer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {


    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(48878);
            Socket client = ss.accept();
            System.out.println("check 1");
            BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(),"UTF-8"));
            System.out.println("check 2");
            byte[] buffer = new byte[20];
            int i = 0;;
            int x;
            while((x=reader.read())!=-1) {
                buffer[i] += (byte)x;
                i = i++;
            }
            String text = new String(buffer,"UTF-8");
            System.out.println("check 3");
            System.out.println(text);
            client.close();
            ss.close();
        } catch (IOException  e) {
            e.printStackTrace();
        }
    }

}

【问题讨论】:

    标签: java sockets inputstream outputstream flush


    【解决方案1】:

    尝试使用 PrintWriterauto flush 属性,在调用新行方法后刷新数据。在流中写入任何数据后无需调用flush。

    PrintStream 类不同,如果启用了自动刷新,它将仅在调用printlnprintfformat 方法之一时完成,而不是在恰好输出换行符时执行.

    示例代码:

    客户:

    PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"),true);
    pw.println("Hello StackOverFlow.");
    

    服务器:

    BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(),"UTF-8"));
    System.out.println(reader.readLine());
    

    【讨论】:

    • 谢谢。我一定忽略了 Javadoc 中关于它必须是 println、printf 或格式方法的部分。 +1
    【解决方案2】:

    “错误”在您用来读取数据的循环中。仅当您关闭另一侧的流时才会发送 EOF。因此,尽管它可能已经向数组添加了 N 个字节,但循环似乎挂起。

    您需要做的是向服务器发送有关客户端将要发送的数据长度的提示。这可以是字节数/字符数或终止字符(换行符)。

    在sender中,发送data+hint,然后flush。

    在接收器中,尽可能多地读取数据,而不是一个字节。这样接收方就不会阻塞了。

    在您的情况下,reader.readLine() 应该可以工作,只要您在发件人上使用 println() + flush。

    【讨论】:

    • +1 抱歉,根据 Braj 的回答,您不需要在消息末尾添加换行符,但是,您的回答是正确的;几乎和Braj一样。我不认为我可以添加两个答案。
    • 他的回答给出了解决方案,我的回答解释了为什么会发生。在这两种情况下都有换行符。
    猜你喜欢
    • 2012-06-05
    • 2016-01-22
    • 2018-04-17
    • 2020-09-02
    • 1970-01-01
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多