2012-10-13 8 views
0
  • 할당으로 ServerSocket 및 Socket 클래스 만 사용할 수 있습니다. 또한 단일 스레드 여야합니다.

Java에서 HTTP 프록시 서버를 구현하고 있습니다. 먼저 클라이언트에서 요청을 가져온 다음 서버에 푸시 한 다음 클라이언트에 응답을 푸시합니다.HTTP 프록시 서버 Java 오류

문제

문제는, 내가이 성공적으로 요청을 얻을 최종 서버로 전송하고 적절한 HTTP 응답을 얻을. 콘솔에서 응답을 인쇄 할 수도 있습니다. 그러나 응답을 clientServer.outputstream에 보낼 때 막혔습니다. 파이어 폭스 (HTTP 1.0 사용 요청, keep-alive 요청 없음)는 영원히로드되고 아무것도 표시되지 않으며 파이어 폭스도 내 프로그램에서 수신하지 않았다.

는 (FF 요청을)로드 매번

페이지의 시작을 디버깅 할 때 나는 검사 무엇 항상 2 클라이언트 소켓이 있습니다. 첫 번째 소켓 에는 null 요청이 있고 두 번째 소켓 에는 적절한 요청이 들어 있습니다. 내가 기대하는 것은 파이어 폭스의 유일한 적절한 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는 서버에서 몇 가지 더 많은 것을 요청할 것입니다. 파비콘. – PeterMmm

+0

나는 flush()를했다. 전체 코드가 이미 있습니다. 시도해 볼 수 있습니다. about : config는 proxy.keep-alive를 false로 설정하고 프록시 HTTP 버전을 1.0으로 설정해야합니다. –

답변

0

은 먼저, 데이터를 전송하는 PrintWriter를 사용해서는 안 HTTP 프로토콜 ISN 때문에 ' 순수한 텍스트 프로토콜 t 몸은 이미지와 같은 일부 원시 데이터를 포함 할 수 있습니다.

응답 코드를 아래 코드로 바꿉니다. 라인이이 시스템의 특정 라인 구분자 인

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

휴식으로

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(); 

두 번째 포인트는, 당신은 항상 추가 할 수 있습니다. HTTP는 HTTP 헤더를 정의하고 http 헤더와 본문 분리에 ctrl 줄 바꿈 문자를 정의하므로이 값을 변경하십시오.

static String separator = "\r\n"; 

이렇게 변경하면 브라우저에 응답 할 수 있습니다.

마지막 포인트는 클라이언트 요청 읽기 코드도 변경해야합니다. POST에서 일부 데이터를 원할 경우 항상 작동하지 않기 때문입니다. 때때로이 데이터는 예제 파일 업로드에 의해 원시 데이터로 전송됩니다.

행운을 빌어 요.