简体   繁体   English

BufferedWriter / PrintWriter / OutputStreamWriter不会刷新缓冲区,直到调用.close()为止(通过套接字输出流)

[英]BufferedWriter/PrintWriter/OutputStreamWriter don't flush buffer until .close() is called (over socket outputstream)

Whenever I call .flush() on any of the writers in the title (who are wrapping an OutputStreamWriter), the flushed data is not sent; 每当我对标题中的任何编写器(正在包装OutputStreamWriter)调用.flush()时,都不会发送刷新的数据; however, when .close() is called on the writer, it flushes and the server can read the data. 但是,在.close()时,它将刷新并且服务器可以读取数据。 I don't know if I am calling .write() or .readLine() incorrectly, or if, since the read operation has already blocked, that is the problem? 我不知道我是错误地调用了.write()还是.readLine() ,还是因为读取操作已经被阻止,这是问题所在吗? I need to find a way to flush the data without closing the socket (I'll be using this in another program). 我需要找到一种无需关闭套接字即可刷新数据的方法(我将在另一个程序中使用它)。 In both of the SSCCE's I have, there are System.out.println() 's for debugging. 在我拥有的两个SSCCE中,都有用于调试的System.out.println() In the client, it will go to "check 4" and loop on nothing (it does more read and writing in the actual program, just can't have it close in the example). 在客户端中,它将转到“ check 4”并不执行任何循环(它在实际程序中执行更多读取和写入操作,只是在示例中无法关闭它)。 In the server, it gets to "check 2" and blocks at reader.readLine() . 在服务器中,它“检查2”并在reader.readLine()reader.readLine() I've read around on SO, but all I've come up with is that readLine() isn't a good idea for network programs, and that I should implement my own protocol; 我已经阅读了SO的书,但是我想出的是, readLine()对于网络程序来说不是一个好主意,我应该实现自己的协议。 however none of the posts point to a good tutorial site, or anything else with good network coding tutorials. 但是,这些帖子都没有指向良好的教程网站,也没有指向具有良好网络编码教程的其他内容。 Here are the SSCCEs: 以下是SSCCE:

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

}

Server SSCCE 服务器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();
        }
    }

}

Try with auto flush property of PrintWriter that flush the data once new line methods are calle. 尝试使用PrintWriter的 auto flush属性,该属性会在调用新行方法后刷新数据。 There is no need to call flush after writing any data in the stream. 在流中写入任何数据后,无需调用flush。

Unlike the PrintStream class, if automatic flushing is enabled it will be done only when one of the println , printf , or format methods is invoked, rather than whenever a newline character happens to be output. PrintStream类不同,如果启用了自动刷新,则仅在调用printlnprintfformat方法之一时才执行此操作,而不是在碰巧输出换行符时才执行。

Sample code: 样例代码:

Client: 客户:

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

Server: 服务器:

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

The "bug" is in the loop which you use to read the data. “错误”位于您用来读取数据的循环中。 EOF is only sent when you close the stream on the other side. 仅当您在另一端关闭流时才发送EOF。 So the loop seems to hang despite the fact that is has probably added N bytes to the array already. 因此,尽管事实似乎已经将N个字节添加到数组中,但循环似乎仍然挂起。

What you need to do is to send a hint to the server about the length of data that the client is about to send. 您需要做的是向服务器发送有关客户端将要发送的数据长度的提示。 That can be the number of bytes/characters or a termination character (line a line feed). 这可以是字节数/字符数或终止字符(换行符)。

In the sender, send the data+hint and then flush. 在发送者中,发送数据+提示,然后刷新。

In the receiver, read just as much data as you are allowed and not a single byte more. 在接收器中,读取的数据与允许的一样多,而不是一个字节。 That way, the receiver will not block. 这样,接收器将不会阻塞。

In your case, reader.readLine() should work as long as you use println() + flush on the sender. 就您而言,只要您在发送方上使用println() + flush, reader.readLine()应该可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM