2012-10-13 101 views
0
  • 作爲一項任務,我被允許僅使用ServerSocket和Socket類。它也應該是單線程的。

我用Java實現的HTTP代理服務器,首先從客戶端獲取請求,然後推送至服務器,然後推響應返回給客戶端。HTTP代理服務器Java錯誤

問題

的問題是,我已經成功地獲得請求,將其發送到終端服務器,並得到適當的HTTP響應。 我也可以在控制檯中打印出響應。 但是,當我將響應發送到clientServer.outputstream時,它卡住了。 Firefox(請求使用HTTP 1.0,沒有請求保持活動狀態)好像永久加載,沒有任何內容顯示,並且Firefox從我的程序收到的響應也沒有響應。

我檢查什麼調試

每次頁面啓動時加載(FF要求),總有2個客戶端套接字。第一個插座包含空請求,第二個插座包含適當的請求。我期望的是隻有一個來自Firefox的正確的HTTP請求。這是一個奇怪的行爲?

例如:

/0:0:0:0:0:0:0:1:65194 
[null request] 

/0:0:0:0:0:0:0:1:65195 
GET http://www.microsoft.com/ HTTP/1.0 
Host: www.microsoft.com 
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip, deflate 
Connection: close 
Proxy-Connection: close 
Cookie: viewkey=lightweight; WT_FPC=id=269eb0e7618962f93a81347585923074:lv=1349229942007:ss=1349229580158; WT_NVR_RU=0=technet|msdn:1=:2=; omniID=c736269c_f430_4e9b_a42a_23a0c965c60a; MUID=212A1766CFE761423CD014BDCBE76158&TUID=1; MC1=GUID=08600fba7f5c5f409e67980d8a027593&HASH=ba0f&LV=20129&V=4&LU=1347643534618; A=I&I=AxUFAAAAAADGBwAA8ezRtqBBHjk3++mP1Bwj9w!!&V=4&CS=119EQ5002j10100; msdn=L=en-US 

代碼

ServerSocket serverSocket; 
try { 
    serverSocket = new ServerSocket(60000); 
    while (true) { 
      clientSocket = serverSocket.accept(); 
      [...] 
      // Extract request, and push to end-server 
      // Fetch response from end-server to client, using flush() already 
      // Close all input, output 
      // Close all sockets 
} catch {[...]} 

任何幫助,歡迎,謝謝!

的完整代碼的要求,我用的PrintWriter,而是說使用字節沒什麼區別之前(不關心效率)

import java.io.*; 
import java.net.*; 
import java.util.*; 

public class Proxy { 

    static String separator = System.getProperty("line.separator"); 

    public static void main(String args[]) { 
     //int port = Integer.parseInt(args[0]); 
     start(60000); 
    } 

    public static void start(int port) { 
     ServerSocket serverSocket; 
     try { 
      serverSocket = new ServerSocket(port); 
      Socket clientSocket = null; 
      while (true) { 
       clientSocket = serverSocket.accept(); 

       System.out.println(clientSocket.getRemoteSocketAddress() + "\n" + clientSocket.getLocalSocketAddress() + "\n" + clientSocket.getInetAddress()); 

       BufferedReader inStreamFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 

       String inLine; 
       Vector<String> clientRequestHeader = new Vector<String>(); 
       String rawRequest = ""; 

       while ((inLine = inStreamFromClient.readLine()) != null) { 
        if (!inLine.isEmpty()) { 
         clientRequestHeader.add(inLine); 
         rawRequest = rawRequest.concat(inLine + separator); 
        } else break; 
       } 

       while ((inLine = inStreamFromClient.readLine()) != null) 
        rawRequest = rawRequest.concat(inLine + separator); 

       System.out.println(rawRequest); 

       if (!rawRequest.isEmpty()) { 
        handleRequest(clientSocket, clientRequestHeader, rawRequest); 
       } else { 
        //clientSocket.close(); 
            // Not sure how to handle null request 
       } 

      } 
     } catch (Exception e) {e.printStackTrace();} 

    } 

    public static void handleRequest(Socket clientSocket, Vector<String> clientRequestHeader, String rawRequest) { 
     HTTPRequest request = new HTTPRequest(clientRequestHeader, rawRequest); 
     try { 
      //System.out.println(rawRequest); 

      // Send request to end-server 
      Socket endServerSocket = new Socket(request.getHost(), 80); 

      PrintWriter outStreamToEndServer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(endServerSocket.getOutputStream()))); 
      BufferedReader stringReader = new BufferedReader(new StringReader(rawRequest)); 
      String inLine; 
      while ((inLine = stringReader.readLine())!= null) { 
       outStreamToEndServer.println(inLine); 
      } 
      outStreamToEndServer.println(); 
      outStreamToEndServer.flush(); 


      // Read response header from end-server 
      String responseHeader = ""; 
      BufferedReader inStreamFromEndServer = new BufferedReader(new InputStreamReader(endServerSocket.getInputStream())); 
      while (!(inLine = inStreamFromEndServer.readLine()).isEmpty()) { 
       responseHeader = responseHeader.concat(inLine + separator); 
      } 

      // Send response header to client 
      PrintWriter outStreamToClient = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()))); 
      outStreamToClient.println(responseHeader); 
      outStreamToClient.flush(); 

      // Send response body to client 
      String responseBody = ""; 
      while ((inLine = inStreamFromEndServer.readLine()) != null) { 
       responseBody = responseBody.concat(inLine + separator); 
      } 
      outStreamToClient.println(responseBody); 
      outStreamToClient.flush(); 

      endServerSocket.shutdownInput(); 
      clientSocket.shutdownOutput(); 
      clientSocket.close(); 
      endServerSocket.close(); 

      //endServerSocket = null; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 
+0

您是否flush()和close()輸出流? – PeterMmm

+0

FF會從服務器請求更多的東西,例如favicon。 – PeterMmm

+0

我做了flush()。 我的完整代碼在那裏,你可以試試。請注意about:config應將proxy.keep-alive設置爲false,並將代理HTTP版本設置爲1.0 –

回答

0

首先你不應該使用的PrintWriter來傳輸數據,由於HTTP協議的ISN」一個純文本協議的身體可以包含一些像圖像的原始數據。

用以下代碼替換您的答覆轉移代碼。

InputStream in = endServerSocket.getInputStream(); 
OutputStream out = clientSocket.getOutputStream(); 
byte[] buffer = new byte[1024]; 
int bytesRead; 
while ((bytesRead = in.read(buffer)) != -1) 
{ 
    out.write(buffer, 0, bytesRead); 
} 

in.close(); 
out.close(); 

二點,你總是添加作爲線突破

static String separator = System.getProperty("line.separator"); 

這是系統特定的行分隔符。 HTTP爲HTTP標頭定義,並且爲http標頭和主體分隔定義了ctrl換行符字符,因此請更改此內容。

static String separator = "\r\n"; 

通過此更改,您將獲得對瀏覽器的響應。

最後一點你應該改變你的客戶端請求讀取代碼,因爲如果你想POST一些數據,它不會總是工作。有時這些數據將作爲原始數據傳輸,例如文件上傳。

好運