【问题标题】:Proxy server can not send response back to client代理服务器无法将响应发送回客户端
【发布时间】:2018-12-20 13:09:04
【问题描述】:

我正在使用 Java 创建代理服务器,而我的客户端和服务器都是用 NodeJS 编写的。由于客户端可以发送多个请求,所以我为每个客户端请求创建线程到代理服务器。现在,当我从服务器(整数值)得到响应时,我想从我的代理服务器将相同的数据发送回客户端。但我的代理服务器无法这样做。

客户端期望在 100 毫秒内得到响应。所以我设置了连接和读取超时属性。如果我在这段时间内没有收到响应,我想用整数 0 响应客户端。

SocketServer.java

private int portNo;
private ServerSocket serverSocket = null;

public SocketServer(int portNo) {
    this.portNo = portNo;
    try {
        serverSocket = new ServerSocket(this.portNo);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void runServer() {
    while(true) {
        try {
            Socket clientSocket = serverSocket.accept();
            new Thread(new Task(clientSocket)).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public static void main(String args[]) {
    SocketServer socketServer = new SocketServer(3000);
    socketServer.runServer();
}

Task.java

public class Task implements Runnable {

    Socket socket = null;

    public Task(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            String dataFromClient = in.readLine(); // this is the url from client
            String partOfLink = dataFromClient.substring(5, 9);

            URL url = new URL("http://localhost:3001/" + partOfLink);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setDoOutput(true);
            conn.setConnectTimeout(80);
            conn.setReadTimeout(80);

            // Get the response
            BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = rd.readLine()) != null) {
                out.write(line);
            }

        } catch (IOException e) {
            //e.printStackTrace();
            try {
                BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                out.write(0);
            } catch (IOException e1) {
                e1.printStackTrace();
            }   
        }
    }
}

【问题讨论】:

  • 100 毫秒对于 TCP 之上的协议来说可能不是一个合理的超时时间,因为 TCP 本身在内部使用接近超时时间(聚合数据和 ACK)。另外,你真的没有描述问题。您说代理服务器无法将数据发送回客户端,但这是什么意思?客户端与代理使用什么协议?它是否专门编码以了解零的含义?您是否希望这可以与没有特殊客户端代码的常规 HTTP 客户端一起使用,以了解如何查询代理并了解其错误处理?
  • @DavidSchwartz 也许你是对的,100ms 可能是一个问题。但是如果发生超时,那么我想将 0 作为响应发送给客户端(参见 catch 块)。因此,为了向客户端发送响应,我在这里通过套接字输出流使用 BufferedWriter。尽管如此,我的客户没有从这个代理服务器得到任何响应。简而言之,代理服务器无法响应客户端
  • 如果客户端期待一个 HTTP 响应,它不会得到一个。客户是否了解如何理解该零?这样做有点尴尬,因为客户端可能会收到 HTTP 响应或可能会收到零,因此它需要一个可以处理这两种情况的成帧器、解析器和解码器。这是一件非常奇怪的事情,我敢打赌,客户没有这样做或做得不对。 (糟糕的设计,IMO。总是很难处理没有简单区分的两种可能的协议。这里,检查必须在收到原始数据之后和框架之前进行。呸。)
  • 我无法控制客户端。但是客户端通过 HTTP 与代理通信。那么有没有什么方法可以不使用 HTTP 而只使用套接字连接将数据发送回客户端呢?

标签: java multithreading sockets tcp-ip http-proxy


【解决方案1】:

您现在遇到的具体问题可能是客户端收到零并说“这不是一个完整的 HTTP 回复,我期待一个完整的 HTTP 回复,因此必须有更多数据”,所以它等待更多数据

由于客户端只使用 HTTP,而您在超时情况下没有向客户端发送 HTTP,您为什么希望它能够工作?

即使在成功的情况下,您实际上也没有这样做!您已将 HTTP 解码器附加到出站连接,并将 decoded 输出中继到客户端。但是客户端需要 raw HTTP。

有很多方法可以咬你。假设代理的响应标头指示分块编码。您要么需要修改这些标头,要么也需要使用分块编码将数据发送到客户端,因为接收代理响应的代码会解码分块编码。这个代码在哪里?

您需要正确处理 HTTP 连接持久性。您需要检测客户端是否支持它以及代理的回复是否与它兼容,以了解代理回复后如何处理客户端连接。你应该关闭它吗?您是否应该尝试在同一连接上接收另一个回复?这取决于几个因素——正确做出此决定的代码在哪里?

您的代码还有很多其他问题。您应该查看现有 HTTP 代理的工作代码并了解它们的工作方式。您必须解决大量问题才能让真正的 HTTP 代理正常工作,而您还没有解决这些问题。

有一些可能的 hack 可能会使这种方法看起来足够有效,以至于您可以将其作为完成的方式传递出去。但是,如果这是一个必须可靠的重要应用程序,那么这是错误的方法。 HTTP 代理是大而复杂的东西。这段代码不是一个。

寻找最简单的代码,让您可以使用真正的 HTTP 代理。阅读 HTTP 规范并仔细查看代理的要求。这是一个雷区,您确实应该从已知可以工作的 HTTP 代理开始,并根据需要对其进行修改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    相关资源
    最近更新 更多