2011-02-01 4 views
1

나는 사용자 정의 프록시를 작동시키는 데 몇 가지 다른 방법을 시도해 왔으며, 지금까지 할 수 있었던 유일한 방법은 Apache의 HttpClient를 사용하는 것이다. 그러나 알을 위해, 내가 아래에있는 내 자신의 프록시 핸들 구현에 문제가 있어요 왜 궁금 : 간단히 말해서자바에서 프록시 입출력 스트림 문제


public void processProxyRequest (Socket client, String request) throws Exception { 

     if (!request.equals("")) { 

      String[] requestHeaders = request.split("\\r\\n"); 
      Pattern p = Pattern.compile("([A-Z]*)\\s*([^:\\/]*):\\/\\/([^\\s]*)\\s*(?:HTTP.*)"); 
      Matcher m = p.matcher(requestHeaders[0]); 

      if (m.matches()) { 
       String method = m.group(1).toUpperCase(); 
       String proto = m.group(2).toLowerCase(); 
       String[] requestInfo = m.group(3).split("\\/", 2); 

       String host = requestInfo[0]; 
       host = (host.split("\\.").length < 3) ? "www." + host : host; 
       String page = "/"; 
       if (requestInfo.length == 2 && !requestInfo[1].equals("")) { 
        page += requestInfo[1]; 
       } 

       int remotePort = 80; 

       if (proto.equals("https")) { 
        remotePort = 443; 
       } 
       else if (proto.equals("ftp")) { 
        remotePort = 21; 
       } 
       this.sendAndReceive(client, request, host, remotePort); 
      } 
     } 

    } 

    public void sendAndReceive (Socket client, String request, String host, int port) throws Exception { 
     Socket target = new Socket(host, port); 
     System.out.println("Connected to server"); 

     ByteArrayInputStream inStream = new ByteArrayInputStream(request.getBytes()); 

     this.inToOut(inStream, target.getOutputStream()); 
     System.out.println("Sent"); 
     this.inToOut(target.getInputStream(), client.getOutputStream()); 
     System.out.println("Received"); 
     target.close(); 
    } 

    public void inToOut (InputStream input, OutputStream output) throws IOException { 
     byte[] buffer = new byte[1024]; // Adjust if you want 
     int bytesRead; 
     System.out.println("reading"); 
     while ((bytesRead = input.read(buffer)) != -1) { 
      output.write(buffer, 0, bytesRead); 
     } 
    } 

을 (그리고 결함을 분석하는 내 요청 헤더를 무시), 위의 코드는 컴파일 그러나 실행하면 inToOut() 메서드가 약간 어려움을 겪고 input.read() 중에 잠기는 것처럼 보입니다. 그 이유는 확실하지 않습니다. 내가 전달하는 원래 소켓이 유효하고 오류없이 열렸다는 사실을 알고 있습니다. 또한 inToOut() 함수의 System.out은 "읽기"를 인쇄하지만 read() 부분을 지나치지 않습니다.

의견을 보내 주셔서 감사합니다.

답변

1

이렇게하면 프록시를 작성할 수 없습니다. HTTP의 경우 첫 번째 행만 처리하면 대상 호스트가 알려줍니다. 그 밖의 모든 것은 업스트림 연결 오류를 올바르게보고하고 올바르게 종료를 처리하는 것과 같은 몇 가지 사소한 수정을 전제로 바이트를 앞뒤로 복사하는 것입니다. FTP 경우가 더 까다 롭고 완전히 별도로 처리해야하지만 연결 단계를 지나면 다시 바이트를 복사합니다. 적은 노력으로 프로토콜을 이해하는 것이 더 쉽고 간단합니다. 실제로 (그것을 내가 inToOut을 (사용 해봤)와 그것을 잘 작동합니다 - 당신의 sendAndReceive 기능에

+0

나는 requestline이 실제로 processRequest() 메소드에 이미 전달되어 있기 때문에 이해합니다. 특정 요청 및 응답 헤더 속성을 추적하고 싶지만 나중에 기능을 로깅하기 위해 몇 가지 추가 구문 분석을 수행했습니다. 앞뒤로 바이트의 "간단한"복사에 관해서는, 위의 잘못된 것? 나는 그것이 클라이언트의 스트림을 대상의 아웃 스트림으로 복사 한 다음 스트림의 대상에서 스트림의 클라이언트로 복사하여 수행 한 작업임을 확신했습니다. 그러나 여전히 성공하지 못했습니다. – jerluc

+0

복사 코드를 보지 않고도 댓글을 달 수 없습니다. NIO를 사용하지 않는 한 연결 당 두 개의 스레드가 필요합니다. 각 스레드는 각 방향으로 복사해야합니다. 두 가지 모두 동일한 코드입니다. EOS 때까지 바이트를 읽고 씁니다. – EJP

+0

이미 코드가 있습니다. 즉, 클라이언트의 입력 스트림에서 대상 서버의 출력 스트림으로 바이트를 복사하려고 시도하는'inToOut()'메소드가 있습니다. 물론 두 스레드를 별도의 스레드에 배치하지 못했지만 지금은 스레드를 사용하려고 시도한 다음 나중에 NIO를 사용하려고 시도했지만 두 방법 모두 대상 서버에 데이터를 쓰는 것 같습니다 (테스트의 경우 google.com 만 사용).)하지만 응답을 읽으려고하면 항상 고정됩니다. – jerluc

0

, 아마도 문제는 inToOut 기능에 될 것 같지 않습니다의 DataInputStream과 DataOutputStream에

public void sendAndReceive (Socket client, String request, String host, int port) throws Exception { 
    Socket target = new Socket(host, port); 
    System.out.println("Connected to server"); 

    this.inToOut(new DataInputStream(client.getInputStream()), new DataOutputStream(target.getOutputStream())); 
    System.out.println("Sent"); 
    this.inToOut(new DataInputStream(target.getInputStream()), new DataOutputStream(client.getOutputStream())); 
    System.out.println("Received"); 
    target.close(); 
} 

를 사용해보십시오 비슷한 문제가 생긴 문제를 해결하는 데 도움이되었습니다. - 감사합니다.