2012-10-13 105 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一些数据,它不会总是工作。有时这些数据将作为原始数据传输,例如文件上传。

好运