0

私のプログラミング課題では、クライアントとサーバーの間にプロキシを作成する必要があります。クライアントがプロキシ経由でサーバーにリクエストを送信すると、プロキシはそれを転送し、サーバーからクライアントにレスポンスを返します。

私が取った手順は次のとおりです。

1) クライアントからリクエストを取得し、リクエスト データをバイト配列に格納する

2) バッファリーダーを使用してバイト配列から読み取る

3) Host: ヘッダー フィールドからホスト名を取得し、それを使用して serverSocket を作成します。

4) 要求データを serverSocket 出力ストリームに転送する

5) serverSocket 入力ストリームから別のバイト配列に応答データを取得します。

6) バイト配列の内容を clientSocket 出力ストリームに書き込みます

ただし、ステップ 6 の後、ブラウザーは応答データを表示できません。何か助けはありますか?

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

public class proxy2 {

  public static void main(String args[]) throws Exception
  {
    int port = Integer.parseInt(args[0]);
    File fileSub= new File(args[1]); //fileSub
    File fileRediect = new File(args[2]); //fileRedirect

    ServerSocket listener = new ServerSocket(port);


    while (true) {
      proxy_func(listener.accept());

    }

  }

  public static void proxy_func(Socket clientSocket) throws Exception{

    OutputStream outputToClient = clientSocket.getOutputStream();

    //store clientSocket's inputstream into a buffer
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    int nRead; //start offset in the data
    byte[] data = new byte[16384]; //create byte array
    //read each byte from InputStream and write it to a ByteArrayOutputStream
    while((nRead = clientSocket.getInputStream().read(data, 0, data.length)) != -1) {
      buffer.write(data, 0, nRead); 
    }
    buffer.flush(); //forces any buffered bytes to be written out
    data = buffer.toByteArray(); //retrieve the underlying byte array 
    System.out.println(new String(data));

    //create buffer reader for clientSocket's inputstream
    InputStream inputStream = new ByteArrayInputStream(data);
    BufferedReader readFromClient = new BufferedReader(new InputStreamReader(inputStream));

    String[] strArr;
    String line;
    String hostname = null;

    //get hostname
    while(  (line=readFromClient.readLine()) != null)
    {
      strArr = line.split(" ");
      if(strArr[0].equals("Host:"))
        hostname = strArr[1];
    }
    System.out.println("Host: " + hostname);

    //create server socket
    Socket serverSocket = new Socket(hostname, 80);
    OutputStream outputToServer = serverSocket.getOutputStream();
    InputStream inputFromServer = serverSocket.getInputStream();

    //forward request to server
    System.out.println("forward request to server...");
    outputToServer.write(data);

    //receive data from server and write response back to client
    byte[] receivedData = new byte[16384];
    int size;
    while((size = inputFromServer.read(receivedData)) != -1)
    {
      System.out.println("write response back to client...");
      System.out.println("size: " + size);
      System.out.println(new String(receivedData));
      outputToClient.write(receivedData, 0, size);
    }

    System.out.println("flushing...");
    outputToClient.flush();
    outputToClient.close();
  }
}

したがって、基本的には、I/O の次のレイアウトに従います。

{
    OutputStream outputToClient = clientSocket.getOutputStream();
    BufferedReader readFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

    //step 1
    //get the HTTP request header from your firefox
    String line = readFromClient.readLine();

    //if the Content_Length within the HTTP header exists and not equals to 0
    char [] buffer = new char [#];
    readFromClient.read(buffer, 0, Content_Length); //get the body message

    OutputStream outputToServer = serverSocket.getOutputStream();
    InputStream inputFromServer = serverSocket.getInputStream();
    //step 2
    outputToServer.write(Bytes[])  //forword the HTTP requests to server host.

    //step 3
    byte[] data = new byte[#];
    while ((size = inputFromServer.read(data)) != -1)   //get the response data from server
    {
        //step 4
        outputToClient.write(data, 0, size);    //forward the data to your firefox
    }
}
4

3 に答える 3

1

最後の部分に問題があります:

byte[] receivedData = new byte[16384];
int size;
while((size = inputFromServer.read(receivedData)) != -1)
{
  System.out.println("write response back to client...");
  System.out.println("size: " + size);
  System.out.println(new String(receivedData));
}
outputToClient.write(receivedData);

したがって、サーバーが 100 万バイトを送り返したとします。receivedDataループはそれらを 16384 バイトのチャンクで読み取り、すべてのチャンクを読み取った後、最後の読み取り後にバッファーに残っていたものを送り返します。したがって、ブラウザは、サーバーから送信された 1,000,000 バイトのうち 16384 バイトのみを受信します。

サーバーから読み取ったすべてをブラウザに送信する必要があります。

byte[] receivedData = new byte[16384];
int size;
while((size = inputFromServer.read(receivedData)) != -1)
{
  System.out.println("write response back to client...");
  System.out.println("size: " + size);
  System.out.println(new String(receivedData));
  outputToClient.write(receivedData, 0, size);      
}
于 2013-10-06T14:00:36.790 に答える
0

わかりました、問題の原因がわかりました。HTTP 要求の終了を検出しなかったため、while ループがブロックされました。この回答は私の問題を簡潔に解決します: https://stackoverflow.com/a/9542710

この問題に出くわして道に迷った人のために、ここに投稿してください。

これが機能する更新されたコードです (HTTP 要求の終了を検出するメソッドを追加したことに注意してください)。

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

public class proxy2 {

  public static void main(String args[]) throws Exception
  {
    int port = Integer.parseInt(args[0]);
    File fileSub= new File(args[1]); //fileSub
    File fileRediect = new File(args[2]); //fileRedirect

    //create listener socket to listen for requests from browser
    ServerSocket listener = new ServerSocket(port);

    while (true) {
      proxy_func(listener.accept());
    }

  }

  public static void proxy_func(Socket clientSocket) throws Exception{

    OutputStream outputToClient = clientSocket.getOutputStream();
    InputStream inputFromClient = clientSocket.getInputStream();

    //store clientSocket's inputstream into a buffer

    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    int nRead; //start offset in the data
    byte[] data = new byte[16384]; 
    //read each byte from InputStream and write it to a ByteArrayOutputStream
    while((nRead = inputFromClient.read(data, 0, data.length)) != -1) {
      System.out.println("reading from client...");
      buffer.write(data, 0, nRead);
      //if reached end of HTTP request, break out of this loop
      if(endOfRequest(data) == true)
        break;
    }
    buffer.flush(); //forces any buffered bytes to be written out
    data = buffer.toByteArray(); //retrieve the underlying byte array 
    System.out.println(new String(data));

    //create buffered reader for byte array input stream (request data)
    InputStream inputStream = new ByteArrayInputStream(data);
    BufferedReader readFromClient = new BufferedReader(new InputStreamReader(inputStream));

    String[] strArr;
    String line;
    String hostname = null;

    //get hostname
    while(  (line=readFromClient.readLine()) != null)
    {
      strArr = line.split(" ");
      if(strArr[0].equals("Host:"))
        hostname = strArr[1];
    }
    System.out.println("Host: " + hostname);

    //create server socket
    Socket serverSocket = new Socket(hostname, 80);
    OutputStream outputToServer = serverSocket.getOutputStream();
    //InputStream inputFromServer = serverSocket.getInputStream();

    //forward request to server
    System.out.println("forward request to server...");
    outputToServer.write(data);

    //receive data from server and write response back to client
    DataInputStream inputFromServer = new DataInputStream(serverSocket.getInputStream());
    byte[] receivedData = new byte[1024];
    int size;
    while((size = inputFromServer.read(receivedData, 0, receivedData.length)) != -1)
    {
      System.out.println("write response back to client...");
      System.out.println(new String(receivedData));
      outputToClient.write(receivedData, 0, size);
      outputToClient.flush();
    }

    System.out.println("done sending");
    outputToClient.close();
  }

  //method to detect end of HTTP request
  //return true if detected, otherwise false
  public static boolean endOfRequest(byte[] data) throws Exception
  {
    System.out.println("parsing request..");
    BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data)));
    String line;

    while( (line=br.readLine()) != null) {
      if (line.equals(""))
        return true;
    }
    return false;
  }
}
于 2013-10-07T09:28:11.347 に答える
0

あなたはこれをすべて間違っています。HTTP プロキシは、CONNECT コマンドを読み取り、それを実行するだけで済みます。その後、可能な限り高速に同時に双方向にバイトをコピーするだけです。プロキシの HTTP プロトコルを理解しようとすればするほど、バグが発生します。

于 2013-10-07T10:00:30.500 に答える