2

私はしばらくの間、カスタムプロキシを機能させるためにいくつかの異なる方法を試してきましたが、これまでにできた唯一の方法は、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()中にロックアップするようです。理由はよくわかりません。私が渡した元のソケットが有効であり、エラーなしで開かれていることを事実として知っています。さらに、System.outinToOut()関数のinは「読み取り」を出力しますが、そのread()部分を超えることはありません。

提案ありがとうございます!

4

2 に答える 2

1

これはプロキシを書く方法ではありません。HTTP の場合、ターゲット ホストを示す最初の行を処理するだけで済みます。他のすべては、バイトを前後にコピーするだけですが、アップストリーム接続エラーを正しく報告し、シャットダウンを適切に処理するなど、いくつかの小さな改良が必要です。FTP のケースはよりトリッキーであり、完全に個別に処理する必要がありますが、接続フェーズを過ぎると、バイトをコピーするだけです。プロトコルを理解するための努力が減れば減るほど、プロトコルはよりシンプルで優れたものになります。

于 2011-02-01T09:56:56.477 に答える
0

sendAndReceive 関数で、おそらく 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();
}

問題は inToOut 関数にあるようには見えません - inToOut() を使用してみましたが、正常に動作します (実際に似たような問題を解決するのに役立ちました - ありがとう)

于 2011-12-03T16:31:48.170 に答える