【问题标题】:java.net.ServerSocket does not catch all connectionsjava.net.ServerSocket 不捕获所有连接
【发布时间】:2015-02-16 22:28:43
【问题描述】:

我正在尝试在 java 中实现一个 Web 代理服务器,它将在我的浏览器和 Web 之间中继请求和响应。在当前设置中,我让浏览器将所有页面请求发送到指定端口上的 localhost,并且我的代理正在该端口上侦听传入请求。

整个事情都是线程化的,因此可以同时处理多个请求,这就是我的代码的样子:

   private void startProxy(int serverPort){

    try {
        // create a socket to listen on browser requests
        ServerSocket servSocket = new ServerSocket(serverPort);

        while(true) {
            // create a thread for each connection
            ProxyThread thread = new ProxyThread(servSocket.accept());
            thread.start();
        }
    } catch (IOException e) {}
   }

   class ProxyThread extends Thread {

    private Socket client;
    private Socket server;

    public ProxyThread(Socket client) {
        this.client = client;
        server = new Socket();
    }

    public void run() {
        // passes on requests and responses here
    }

我注意到,当我尝试加载包含 20 个不同 html/css/js 请求的页面时,有时只创建 18-19 个线程,在此过程中丢失了一些请求。大多数情况下,对 js 资源或图像的请求都会被丢弃,而且它们绝不是浏览器发出的最后一个请求,因此这不是资源耗尽的问题。

使用wireshark,我能够确定丢失的请求确实通过了本地主机,因此由于某种原因 ServerSocket.accept() 实际上并不接受连接。是否有任何特殊原因导致这种情况发生?或者也许我的代码在某些方面是错误的?

编辑

这是run()的主体

     try {
            BufferedReader clientOut = new BufferedReader(
                    new InputStreamReader(client.getInputStream()));
            OutputStream clientIn = client.getOutputStream();

            // assign default port to 80
            int port = 80;
            String request = "";
            // read in the first line of a HTTP request containing the url
            String subRequest = clientOut.readLine();
            String host = getHost(subRequest);

            // read in the rest of the request
            while(!subRequest.equals("")) {
              request += subRequest + "\r\n";
              subRequest = clientOut.readLine();
            }
            request += "\r\n";
            try {
                server.connect(new InetSocketAddress(host, port));
            } catch (IOException e) {
                String errMsg = "HTTP/1.0 500\nContent Type: text/plain\n\n" + 
                "Error connecting to the server:\n" + e + "\n";
                 clientIn.write(errMsg.getBytes());
                 clientIn.flush();
            }

            PrintWriter serverOut = new PrintWriter(server.getOutputStream(), true);
            serverOut.println(request);
            serverOut.flush();

            InputStream serverIn = server.getInputStream();

            byte[] reply = new byte[4096];
            int bytesRead;
            while ((bytesRead = serverIn.read(reply)) != -1) {
               clientIn.write(reply, 0, bytesRead);
               clientIn.flush();
            }


            serverIn.close();
            serverOut.close();

            clientOut.close();
            clientIn.close();

            client.close();
            server.close();
        } catch(IOException e){
            e.printStackTrace();
        }

【问题讨论】:

  • 您的代码看起来不错。 (虽然我不知道还有什么要看的)
  • 抛出了什么异常?如果请求通过了,为什么不发布处理它们的代码?
  • 你是怎么得出只创建了18-19个线程的结论的?
  • 你怎么知道?使用该代码,您不可能知道这一点。您的代码忽略 IOExceptions。而且您需要澄清请求是否通过:您已经说明了两者;并且您需要发布缺少的代码。对您来说,它可能看起来很标准,但它不起作用。
  • 换句话说,这不是真正的代码。在这种情况下发布它是浪费时间。

标签: java serversocket webproxy


【解决方案1】:

对于一个有 10 个请求的网页,我得到 10 个 HTTP GET、6 个 SYN 和 SYN、ACK,其中 7 个请求成功通过代理,3 个被卡住。

因此,您有 6 个单独的连接,但有 10 个请求,并且每个连接只处理一个请求。您忘记了实现 HTTP keepalive。请参阅 RFC 2616。每个连接可能会到达多个请求。您需要为每个请求读取与 content-length 标头定义的字节数或块的总和(无论存在什么)完全相同的字节数,然后您需要返回并尝试返回而不是仅仅关闭套接字阅读另一个请求。如果这让您结束了流,请关闭套接字。

或者将您的响应以 HTTP 1.0 或 Connection: close 标头发送回客户端,因此它不会尝试将连接重用于另一个请求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-02
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 2023-04-08
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多