Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
I';当必须接受许多连接时,我在客户机/服务器类型的应用程序中遇到Java套接字问题_Java_Performance_Sockets_Objectoutputstream_Objectinputstream - Fatal编程技术网

I';当必须接受许多连接时,我在客户机/服务器类型的应用程序中遇到Java套接字问题

I';当必须接受许多连接时,我在客户机/服务器类型的应用程序中遇到Java套接字问题,java,performance,sockets,objectoutputstream,objectinputstream,Java,Performance,Sockets,Objectoutputstream,Objectinputstream,首先,谢谢你的阅读。这是我第一次以用户身份使用stackoverflow,尽管我经常阅读它并找到有用的解决方案:D。顺便说一句,如果我解释得不够清楚,我很抱歉,我知道我的英语不是很好 我的基于套接字的程序有一个奇怪的行为和一些性能问题。客户机和服务器通过以多线程方式将序列化对象读/写到对象输入和输出流中来相互通信。让我向您展示代码的基础知识。我已将其简化为更具可读性,并有意添加完整的异常处理(例如)。服务器的工作原理如下: private SSLSocket socket; @

首先,谢谢你的阅读。这是我第一次以用户身份使用stackoverflow,尽管我经常阅读它并找到有用的解决方案:D。顺便说一句,如果我解释得不够清楚,我很抱歉,我知道我的英语不是很好

我的基于套接字的程序有一个奇怪的行为和一些性能问题。客户机和服务器通过以多线程方式将序列化对象读/写到对象输入和输出流中来相互通信。让我向您展示代码的基础知识。我已将其简化为更具可读性,并有意添加完整的异常处理(例如)。服务器的工作原理如下:

    private SSLSocket socket;

    @Override
    public void run() {
        LjProtocol protocol = new LjProtocol();
        try {
            socket = (SSLSocket) SSLSocketFactory.getDefault()
                     .createSocket(InetAddress.getByName("here-goes-hostIP"),
                                                                       4444);
        } catch (Exception ex) {

        }
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
        out = new ObjectOutputStream(new BufferedOutputStream(
                                         socket.getOutputStream()));
        out.flush();
        in = new ObjectInputStream(new BufferedInputStream(
                                          socket.getInputStream()));
        LjPacket output;
        // As the client is which starts the connection, it sends the first 
        //object.
        out.writeObject(/* First object */);
        out.flush();
        while (true) {
            output = protocol.processMessage((LjPacket) in.readObject());
            out.writeObject(output);
            out.flush();
            out.reset();
        }
        } catch (EOFException ex) {
            // If all goes OK, when server disconnects EOF should happen.
            System.out.println("suceed!");
        } catch (Exception ex) {
            // (...)
        } finally {
            try {
                // FIRST STRANGE BEHAVIOUR:
                // I have to comment the "out.close()" line, else, Exception is
                // thrown ALWAYS.
                out.close();
                in.close();
                socket.close();
            } catch (Exception ex) {
                System.out.println("This shouldn't happen!");
            }
        }
    }
}
服务器:

// (...)

public void serve() {
    if (serverSocket == null) {
        try {
            serverSocket = (SSLServerSocket) SSLServerSocketFactory
                                    .getDefault().createServerSocket(port);
            serving = true;
            System.out.println("Waiting for clients...");
            while (serving) {
                SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
                System.out.println("Client accepted.");
                //LjServerThread class is below
                new LjServerThread(clientSocket).start();
            }
        } catch (Exception e) {
            // Exception handling code (...)
        }
    }
}

public void stop() {
    serving = false;
    serverSocket = null;
}

public boolean isServing() {
    return serving;
}
LjServerThread类,每个客户端创建一个实例:

private SSLSocket clientSocket;
private String IP;
private long startTime;

public LjServerThread(SSLSocket clientSocket) {
        this.clientSocket = clientSocket;
        startTime = System.currentTimeMillis();
        this.IP = clientSocket.getInetAddress().getHostAddress();
}

public synchronized String getClientAddress() {
    return IP;
}

@Override
public void run() {
    ObjectInputStream in = null;
    ObjectOutputStream out = null;
    //This is my protocol handling object, and as you will see below,
    //it works processing the object received and returning another as response.
    LjProtocol protocol = new LjProtocol();
    try {
        try {
            in = new ObjectInputStream(new BufferedInputStream(
                                     clientSocket.getInputStream()));
            out = new ObjectOutputStream(new BufferedOutputStream(
                                    clientSocket.getOutputStream()));
            out.flush();
        } catch (Exception ex) {
            // Exception handling code (...)
        }
        LjPacket output;
        while (true) {
            output = protocol.processMessage((LjPacket) in.readObject());
            // When the object received is the finish mark, 
            // protocol.processMessage()object returns null.
            if (output == null) {
                break;
            }
            out.writeObject(output);
            out.flush();
            out.reset();
        }
        System.out.println("Client " + IP + " finished successfully.");
    } catch (Exception ex) {
        // Exception handling code (...)
    } finally {
        try {
            out.close();
            in.close();
            clientSocket.close();
        } catch (Exception ex) {
            // Exception handling code (...)
        } finally {
            long stopTime = System.currentTimeMillis();
            long runTime = stopTime - startTime;
            System.out.println("Run time: " + runTime);
        }
    }
}
客户是这样的:

    private SSLSocket socket;

    @Override
    public void run() {
        LjProtocol protocol = new LjProtocol();
        try {
            socket = (SSLSocket) SSLSocketFactory.getDefault()
                     .createSocket(InetAddress.getByName("here-goes-hostIP"),
                                                                       4444);
        } catch (Exception ex) {

        }
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
        out = new ObjectOutputStream(new BufferedOutputStream(
                                         socket.getOutputStream()));
        out.flush();
        in = new ObjectInputStream(new BufferedInputStream(
                                          socket.getInputStream()));
        LjPacket output;
        // As the client is which starts the connection, it sends the first 
        //object.
        out.writeObject(/* First object */);
        out.flush();
        while (true) {
            output = protocol.processMessage((LjPacket) in.readObject());
            out.writeObject(output);
            out.flush();
            out.reset();
        }
        } catch (EOFException ex) {
            // If all goes OK, when server disconnects EOF should happen.
            System.out.println("suceed!");
        } catch (Exception ex) {
            // (...)
        } finally {
            try {
                // FIRST STRANGE BEHAVIOUR:
                // I have to comment the "out.close()" line, else, Exception is
                // thrown ALWAYS.
                out.close();
                in.close();
                socket.close();
            } catch (Exception ex) {
                System.out.println("This shouldn't happen!");
            }
        }
    }
}
如您所见,LjServerThread类在服务器端处理接受的客户机,它测量所需的时间。。。通常,需要75-120毫秒(其中x为IP):

  • 客户端x已成功完成
  • 运行时间:82
  • 客户端x已成功完成
  • 运行时间:80
  • 客户端x已成功完成
  • 运行时间:112
  • 客户端x已成功完成
  • 运行时间:88
  • 客户端x已成功完成
  • 运行时间:90
  • 客户端x已成功完成
  • 运行时间:84
但突然之间,没有可预测的模式(至少对我来说):

  • 客户端x已成功完成
  • 运行时间:15426
有时达到25秒! 局部地,一小群线程运行得稍微慢一点,但这并不让我太担心:

  • 客户端x已成功完成
  • 运行时间:239
  • 客户端x已成功完成
  • 运行时间:243
为什么会这样?这可能是因为我的服务器和客户端在同一台机器上,具有相同的IP吗?(为了进行此测试,我在同一台机器上执行服务器和客户端,但它们通过internet连接,使用我的公共IP)

我就是这样测试的,我在main()中向服务器发出如下请求:

for(int i=0;i<400;i++){
试一试{
新的LjClientThread().start();
睡眠(100);
}捕获(例外情况除外){
// (...)
}
}
如果我在循环中不使用“Thread.sleep(100)”,就会出现一些连接重置异常(400个连接中重置了7个或8个连接,或多或少),但我想我理解了为什么会发生这种情况:当serverSocket.accept()接受连接时,只需花费很少的时间就可以再次访问serverSocket.accept()。在此期间,服务器无法接受连接。可能是因为这个吗?若否,原因为何?很少有400个连接同时到达我的服务器,但这可能发生。如果没有“Thread.sleep(100)”,则计时问题也会更严重

提前谢谢


更新:

多么愚蠢,我在本地主机上测试了它。。。它不会给任何问题!不管有没有“Thread.sleep(100)”,都没关系,它工作得很好!为什么?所以,正如我所看到的,我关于为什么会抛出连接重置的理论是不正确的。这让事情变得更加奇怪!我希望有人能帮我。。。再次感谢!:)


更新(2):

我在不同的操作系统中发现了明显不同的行为。我通常在Linux中开发,我解释的行为是关于我的Ubuntu 10.10中发生的事情。在Windows7中,当我在连接之间暂停100毫秒时,一切正常,所有线程都很快,没有人需要超过150毫秒左右(没有慢连接问题!)。这不是Linux中正在发生的事情。但是,当我删除“Thread.sleep(100)”时,不是只有一些连接得到连接重置异常,而是所有连接都失败并抛出异常(在Linux中,只有部分连接失败,400个连接中大约有6个失败)


呸!我刚刚发现,不仅操作系统,JVM环境也有一点影响!没什么大不了的,但值得注意。我曾在Linux中使用OpenJDK,现在使用Oracle JDK,我发现随着连接之间睡眠时间的减少,它会更早地出现故障(使用50毫秒的OpenJDK可以正常工作,不会引发异常,但是使用Oracle的一个50毫秒的睡眠时间,而使用100毫秒的睡眠时间可以正常工作).

服务器套接字有一个队列,用于保存传入的连接尝试。如果队列已满,客户端将遇到连接重置错误。如果没有
Thread.sleep(100)
语句,您的所有客户端都会尝试相对同时地连接,这会导致其中一些客户端遇到连接重置错误。

服务器套接字有一个队列,用于保存传入的连接尝试。如果队列已满,客户端将遇到连接重置错误。没有<代码>线程。睡眠(100)语句,所有的客户端都试图同时连接,这导致它们中的一些遇到连接复位错误。

两点,我认为您可以进一步考虑研究。对不起,这里有点含糊,但我是这么想的。 1) 在tcp级别,很少有依赖于平台的东西控制通过套接字发送/接收数据所需的时间。不一致的延迟可能是由于tcp\u syn\u重试等设置造成的。你可能有兴趣看看这里


2)您的计算执行时间不仅是完成执行所花费的时间,而且包括完成定稿之前的时间,当对象已准备好完成时,它不能保证立即发生。

< P2 >我认为您可以进一步考虑研究。对不起,这里有点含糊,但我是这么想的。 1) 在后台,在tcp级别,很少有依赖于平台的东西控制数据量