2015-01-14 173 views
0

我有一個客戶端和一個服務器,一個經典的例子,試圖以非常簡單的方式模擬http協議。首先,客戶端在服務器打印數據時發送數據,然後發送數據。在下面的代碼中,無論是服務器還是客戶端塊,原因不明。 客戶端向服務器發送數據,服務器接收數據並打印它。但是在打印數據之後它會阻塞。如果關閉客戶端的輸出流(out.close()),則客戶端應該獲取服務器的數據,但是會拋出IOException異常,並顯示消息:Socket關閉。簡單的服務器/客戶端套接字:阻塞 - Java

我的問題是爲什麼它阻止?我是否必須用EOS觸發輸出?

CLIENT

import java.nio.*; 
import java.nio.channels.*; 
import java.net.*; 
import java.util.*; 
import java.io.IOException; 
import java.io.*; 


public class block_client_webclient 
{ 
    public static void main(String [] args) 
    { 
     try{ 

      Socket s = new Socket("localhost", 8080); 

      OutputStreamWriter out = new OutputStreamWriter(s.getOutputStream()); 
      InputStreamReader in = new InputStreamReader(s.getInputStream()); 

      //WRITE 
      out.write("GET/HTTP/1.1\r\nUser-agent: Agent 2.0 Browser\r\nAccept: */*\r\nAccept-Language: en-US,en;q=0.5\r\nConnection: keep-alive\r\n\r\n"); 
      out.flush(); 
      out.close(); 

      if (s.isConnected()==true && s.isClosed()==false) System.out.println("OPEN"); 
      else System.out.println("CLOSED"); 

      char[] bin = new char[400]; 
      int r=0; 

      //READ 
      while((r=in.read(bin))!=-1) { System.out.println("Input data: "+r+" bytes"); System.out.print(bin); bin= new char[400]; }; 
      System.out.println(r); 

      s.close(); 

     } 
     catch (IOException ex) {System.out.println(ex.getMessage());} 
    } 
} 

服務器

import java.nio.*; 
import java.nio.channels.*; 
import java.net.*; 
import java.util.*; 
import java.io.IOException; 
import java.io.*; 


public class block_server_webserver 
{ 
    public static void main(String [] args) 
    { 
     while(true) 
     { 
     try{ 
      ServerSocket server = new ServerSocket(8080); 
      Socket connection = server.accept(); 
      try{ 
      OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream()); 
      InputStreamReader in = new InputStreamReader(connection.getInputStream()); 

      char[] bin = new char[400]; 
      int r=0; 
      int readsofar=0; 

      //READ 
      while((r=in.read(bin))!=-1) { System.out.print(bin); bin= new char[400]; }; 
      System.out.println("END"); 

      //WRITE 
      out.write("Server: BlockServer 1.0\r\nHost: 192.168.1.1\r\n\r\n"); 
      out.flush(); 
      System.out.println("Just written data to "+connection.getRemoteSocketAddress()); 
      connection.close(); 

      } catch (IOException ex) { connection.close();} 
     }catch (IOException ex) {} 
    } 
    } 
} 

回答

2

執行out.close()會導致套接字關閉異常,因爲當關閉輸入/輸出流時,與其關聯的套接字也會關閉。這意味着在您的客戶端程序中,關閉套接字後將無法讀入。

首先,取出out.close()而不是檢查-1,嘗試創建一個「退出」字符串。如果服務器讀取出口字符串,則認識到它需要停止在while循環中並且只是中斷; (可以用簡單的if語句來完成)。此外,通常我會使用緩衝讀取器,String x和readLine()而不是char數組+ read()。

while (true) { 
    in.read(bin); 
    if (bin[0] == '^') { // or something like that 
     break; 
    } 
    System.out.print(bin); 
    bin = new char[400]; 
} 

完全使用套接字時只關閉()流。

2

服務器不應該等待套接字關閉掉(因爲,一旦出現這種情況,就無法回寫)。

而不是讀取,直到它返回-1(關閉),它應該讀取到請求的結尾(在http頭的情況下兩個新行),並開始發送輸出一旦發生,那麼,可能,關閉該連接通知客戶端沒有更多數據(在http中,連接通常保持打開一段時間,客戶端知道在根據內容長度頭接收到足夠的字節後停止讀取)。