2014-06-19 94 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

他的回答給出了一個解決方案,我的答案解釋了爲什麼會發生。在這兩種情況下你都有一個換行符。 –