Java BufferedWriter/PrintWriter/OutputStreamWriter don';t在调用.close()之前刷新缓冲区(通过套接字输出流)
每当我对标题中的任何写入程序(正在包装OutputStreamWriter)调用Java BufferedWriter/PrintWriter/OutputStreamWriter don';t在调用.close()之前刷新缓冲区(通过套接字输出流),java,sockets,inputstream,outputstream,flush,Java,Sockets,Inputstream,Outputstream,Flush,每当我对标题中的任何写入程序(正在包装OutputStreamWriter)调用.flush(),刷新的数据都不会被发送;但是,在writer上调用.close()时,它会刷新,服务器可以读取数据。我不知道我是否调用了.write()或.readLine()错误,或者由于读取操作已被阻止,这就是问题所在?我需要找到一种在不关闭套接字的情况下刷新数据的方法(我将在另一个程序中使用它)。在我拥有的两个SSCCE中,都有用于调试的System.out.println()。在客户机中,它将转到“chec
.flush()
,刷新的数据都不会被发送;但是,在writer上调用.close()
时,它会刷新,服务器可以读取数据。我不知道我是否调用了.write()
或.readLine()
错误,或者由于读取操作已被阻止,这就是问题所在?我需要找到一种在不关闭套接字的情况下刷新数据的方法(我将在另一个程序中使用它)。在我拥有的两个SSCCE中,都有用于调试的System.out.println()
。在客户机中,它将转到“check4”并不执行任何循环(它在实际程序中执行更多的读写操作,只是在示例中无法将其关闭)。在服务器中,它进入“check2”并在reader.readLine()
处阻塞。我已经读了很多书,但是我想到的是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();
}
}
}
调用新行方法后,尝试使用该函数的自动刷新属性刷新数据。在流中写入任何数据后,无需调用flush 与
PrintStream
类不同,如果启用了自动刷新,则仅当调用println
、printf
或format
方法之一时,而不是在输出换行符时,才会执行自动刷新
示例代码:
客户:
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());
调用新行方法后,尝试使用该函数的自动刷新属性刷新数据。在流中写入任何数据后,无需调用flush 与
PrintStream
类不同,如果启用了自动刷新,则仅当调用println
、printf
或format
方法之一时,而不是在输出换行符时,才会执行自动刷新
示例代码:
客户:
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());
“bug”位于用于读取数据的循环中。只有当您关闭另一侧的流时,才会发送EOF。因此,尽管is可能已经向数组中添加了N个字节,但循环似乎仍然挂起
您需要做的是向服务器发送关于客户端将要发送的数据长度的提示。可以是字节数/字符数或终止字符(换行符)
在sender中,发送数据+提示,然后刷新
在接收器中,读取尽可能多的数据,而不是多读一个字节。这样,接收器就不会阻塞
在您的情况下,reader.readLine()
只要在发送方上使用println()
+flush,就应该可以工作。在用于读取数据的循环中存在“bug”。只有当您关闭另一侧的流时,才会发送EOF。因此,尽管is可能已经向数组中添加了N个字节,但循环似乎仍然挂起
您需要做的是向服务器发送关于客户端将要发送的数据长度的提示。可以是字节数/字符数或终止字符(换行符)
在sender中,发送数据+提示,然后刷新
在接收器中,读取尽可能多的数据,而不是多读一个字节。这样,接收器就不会阻塞
在您的情况下,
reader.readLine()
只要在发件人上使用println()
+flush,就应该可以工作。+1对不起,对于Braj的回答,您不需要在邮件末尾添加换行符,但是,您的回答是正确的;几乎和Braj的一模一样。我不认为我可以添加两个答案。他的答案给出了一个解决方案,我的答案解释了为什么会发生。两种情况下你都有换行符。+1抱歉,根据Braj的回答,你不需要在邮件末尾添加换行符,但是,你的答案是正确的;几乎和Braj的一模一样。我不认为我可以添加两个答案。他的答案给出了一个解决方案,我的答案解释了为什么会发生。在这两种情况下,您都有一个线路提要。谢谢。我一定忽略了Javadoc中关于它必须是println、printf或format方法的部分+1谢谢。我一定忽略了Javadoc中关于它必须是println、printf或format方法的部分+1.