【问题标题】:Java Multithreaded Web Server - Not recieving multiple GET requestsJava 多线程 Web 服务器 - 不接收多个 GET 请求
【发布时间】:2011-02-05 22:11:43
【问题描述】:

我有一个非常基本的多线程 Web 服务器的启动,它可以接收所有 GET 请求,只要它们一次来一个。

但是,当多个 GET 请求同时进入时,有时它们都被接收到,而其他时候,一些请求丢失。

我通过创建一个带有多个指向我的网络服务器的图像标签的 html 页面并在 Firefox 中打开该页面来测试这一点。我总是使用 shift+refresh。

这是我的代码,我一定是做错了什么。

public final class WebServer
{
    public static void main(String argv[]) throws Exception
    {
        int port = 6789;

        ServerSocket serverSocket = null;
        try
        {
            serverSocket = new ServerSocket(port);
        }
        catch(IOException e)
        {
            System.err.println("Could not listen on port: " + port);
            System.exit(1);
        }

        while(true)
        {
            try
            {
                Socket clientSocket = serverSocket.accept();
                new Thread(new ServerThread(clientSocket)).start();
            }
            catch(IOException e)
            {

            }
        }
    }
}

public class ServerThread implements Runnable
{
    static Socket clientSocket = null;

    public ServerThread(Socket clientSocket)
    {
        this.clientSocket = clientSocket;
    }

    public void run()
    {
        String headerline = null;
        DataOutputStream out = null;
        BufferedReader in = null;

        int i;

        try
        {
            out = new DataOutputStream(clientSocket.getOutputStream());
            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            while((headerline = in.readLine()).length() != 0)
            {
                System.out.println(headerline);
            }
        }
        catch(Exception e)
        {

        }
}

【问题讨论】:

  • 您可以从真正关注您的异常开始,而不是忽略它们。他们在那里是有原因的;听他们说,你的答案很可能就在里面。

标签: java multithreading http sockets


【解决方案1】:

首先,@skaffman 的评论是正确的。您不应该像您的代码当前正在执行的那样捕获并忽略异常。一般来说,这是一种可怕的做法。在这种情况下,您很可能会丢弃可以告诉您真正问题所在的证据。

其次,我认为您可能误解了服务器的功能。无论你如何实现它,服务器每秒只能处理一定数量的请求。如果您向它提出的请求比这更多,则必须丢弃一些请求。


我怀疑正在发生的事情是您在短时间内发送了太多请求,并且超出了操作系统的请求缓冲区。

当您的代码绑定到服务器套接字时,操作系统会设置一个请求队列来保存绑定 IP 地址/端口上的传入请求。这个队列的大小是有限的,如果有新请求到来时队列已满,操作系统将丢弃请求。这意味着如果您的应用程序无法足够快地处理accept 请求,一些请求将被丢弃。

你能做些什么呢?

  • ServerSocket.bind(...) 的重载允许您指定要保留在操作系统级队列中的请求的backlog。你可以使用这个……或者使用更大的积压。
  • 您可以更改主循环以更快地从队列中拉取请求。您当前代码的一个问题是您正在为每个请求创建一个新线程。线程创建成本很高,您可以通过使用线程池来回收用于先前请求的线程来降低成本。

注意事项

你需要小心一点。您很有可能可以修改您的应用程序以在短期内接受(而不是丢弃)更多请求。但从长远来看,您应该只以实际处理请求的速度接受请求。如果它接受它们的速度比你处理它们的速度快,就会发生一些不好的事情:

  • 所有试图处理请求的线程都会使用大量内存。这会以各种方式增加 CPU 开销。
  • 您可能会增加对内部 Java 数据结构、数据库等的争用,从而降低吞吐量。
  • 您将增加处理和回复单个 GET 请求的时间。如果延迟太长,客户端可能会超时请求......并再次发送。如果发生这种情况,服务器所做的工作将被浪费。

为了保护自己免受这种情况的影响,实际上最好不要急于接受尽可能多的请求。相反,使用有界线程池,并调整池大小(等)以优化吞吐率,同时将处理单个请求的时间保持在合理的限制内。

【讨论】:

  • 我会首先设置系统监控以捕获吞吐量(每秒处理的请求数)和每个请求的平均处理时间。然后我会向上或向下调整调整参数(在实时系统上),看看哪个在峰值负载下提供最佳性能。如果请求处理时间在负载下达到峰值(同时吞吐量下降),请减小池大小。并且通常观察监控图表,以便您了解系统的运行情况。
【解决方案2】:

我实际上发现问题是这样的:

  static Socket clientSocket = null;

一旦我删除了静电,它现在就可以正常工作了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多