2014-06-19 93 views
0

每当我在标题中的任何编写器(谁在封装OutputStreamWriter)上调用.flush()时,刷新的数据不是发送;但是,在写入器上调用.close()时,它会刷新并且服务器可以读取数据。我不知道我是否错误地拨打.write().readLine(),或者如果由于读取操作已被阻止,那是问题所在?我需要找到一种方法来刷新数据而不关闭套接字(我将在另一个程序中使用它)。在我所有的SSCCE中,都有System.out.println()用于调试。在客户端,它会去“检查4”,并在没有任何事情的时候循环(它在实际的程序中做了更多的读写操作,在示例中不能关闭它)。在服务器中,它将进入“检查2”并在reader.readLine()处阻止。我已经阅读过所有这些,但是我想到的是readLine()对于网络程序来说并不是一个好主意,而且我应该实现我自己的协议;然而,没有一篇文章指向一个很好的教程网站,或者其他任何具有良好网络编码教程的文章。下面是SSCCEs:BufferedWriter/PrintWriter/OutputStreamWriter在调用.close()之前不会刷新缓冲区(通过套接字输出流)

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

} 

回答

1

试着用的PrintWriter自动清空属性,刷新一次数据,新生产线的方法是卡莱。在流中写入任何数据后,不需要调用flush。

不像PrintStream类,如果启用自动刷新,它只会在调用的printlnprintf,或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()); 
+0

谢谢。我一定忽略了Javadoc关于它必须是println,printf或格式方法的一部分。+1 – Levi

1

的 “错误” 是您可以使用它读取数据的循环。 EOF仅在关闭另一侧的流时发送。所以循环似乎挂起,尽管可能已经添加了N个字节到数组。

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

在发件人中,发送数据+提示然后刷新。

在接收器中,读取的数据与您允许的一样多,而不是单个字节多一些。这样,接收器不会阻塞。

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

+0

+1对不起,在Braj的回答中,你不需要在邮件末尾添加换行符,但是,你的回答是正确的;几乎和Braj的一模一样。我不认为我可以添加两个答案。 – Levi

+0

他的回答给出了一个解决方案,我的答案解释了为什么会发生。在这两种情况下你都有一个换行符。 –