Java套接字服务器应用程序:长时间延迟后获取数据包

时间:2014-07-13 13:14:32

标签: java linux sockets port smpp

我有一个套接字服务器(Java SMPP服务器),大量客户端连接并提交请求。 当有大量并发数据包发送到套接字服务器时会出现问题,尽管机器在'X'时间收到请求(从tcpdump捕获),请求到达应用程序 在x + n(秒)之后。将积压设置为更高的值也没有帮助。

不知道我哪里错了。是否存在机器在端口上接收请求但在长时间延迟后接收该端口的端口上运行的套接字服务器的情况?如果是这样,需要在应用程序(java)端完成哪些调优,LINUX机器端

感谢任何帮助。

private void listen()
{
    try {
        Connection connection = null;
        serverConn.setReceiveTimeout(getAcceptTimeout());
        connection = serverConn.accept();


        if (connection != null) {
            --start the session thread (run method below--
                    Thread thread = new Thread(session);
            thread.start();
        } else {
            debug.write(Simulator.DSIMD2, "no connection accepted this time.");
        }
    } catch (InterruptedIOException e) {
        debug.write("InterruptedIOException accepting, timeout? -> " + e);
    } catch (IOException e) {
        keepReceiving = false;
    }
}

public Connection accept()
throws IOException
{
    IOException exception = null;

    Connection newConn = null;
    if (connType == CONN_SERVER) {
        try {
            receiverSocket.setSoTimeout((int)getReceiveTimeout());
        } catch (SocketException e) {
            // don't care, we're just setting the timeout
        }
        Socket acceptedSocket = null;
        try {
            acceptedSocket = receiverSocket.accept();
        } catch (IOException e) {
        }
        if (acceptedSocket != null) {
            try {
                newConn = new TCPIPConnection(acceptedSocket);
                address = acceptedSocket.getInetAddress().getHostAddress();
                try {
                    System.out.println("Acceptedsocket  Address " + address);
                    System.out.println("ReceiverSocket Address " + receiverSocket.getInetAddress().getHostAddress());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                ((TCPIPConnection)newConn).setAddress(address);
            } catch (IOException e) {
                debug.write("IOException creating new client connection "+e);
                event.write(e,"IOException creating new client connection");
                exception = e;
            }
        }
    } else if (connType == CONN_CLIENT) {
        debug.write("Attempt to receive data from client type connection.");
    } else {
        debug.write("Unknown connection type = " + connType);
    }

    debug.exit(DCOMD,this);
    if (exception != null) {
        throw exception;
    }
    return newConn;
}

    public void run() 
{
    PDU pdu = null;
    while (keepReceiving)
    {

        pdu = receiver.receive(getReceiveTimeout());

        if (pdu != null) {
            --- DO SOME PROCESSING ----
        }
        }
 }

public ByteBuffer receive()
throws IOException
{
    debug.enter(DCOMD,this,"receive");
    IOException exception = null;

    ByteBuffer data = null;
    if (connType == CONN_CLIENT) {
        data = new ByteBuffer();
        long endTime = Data.getCurrentTime() + getReceiveTimeout();
        //int bytesAvailable = 0;
        int bytesToRead = 0;
        int bytesRead = 0;
        int totalBytesRead = 0;

        try {
            socket.setSoTimeout((int)getCommsTimeout());
            bytesToRead = receiveBufferSize;
            debug.write(DCOMD,"going to read from socket");
            debug.write(DCOMD,"comms timeout="+getCommsTimeout()+
                        " receive timeout="+getReceiveTimeout()+
                        " receive buffer size="+receiveBufferSize);
            do {
                bytesRead = 0;
                try {
                    bytesRead = inputStream.read(receiveBuffer, 0, bytesToRead);
                } catch (InterruptedIOException e) {
                    // comms read timeout expired, no problem
                    debug.write(DCOMD,"timeout reading from socket");
                }
                if (bytesRead > 0) {
                    debug.write(DCOMD,"read "+bytesRead+" bytes from socket");
                    data.appendBytes(receiveBuffer,bytesRead);
                    totalBytesRead += bytesRead;
                }
                bytesToRead = inputStream.available();
                if (bytesToRead>0) {
                    debug.write(DCOMD,"more data ("+bytesToRead+" bytes) remains in the socket");
                } else {
                    debug.write(DCOMD,"no more data remains in the socket");
                }
                if (bytesToRead > receiveBufferSize) {
                    bytesToRead = receiveBufferSize;
                }
                if (totalBytesRead+bytesToRead > maxReceiveSize) {
                    // would be more than allowed
                    bytesToRead = maxReceiveSize - totalBytesRead;
                }
            } while (((bytesToRead!=0) && (Data.getCurrentTime()<=endTime))
                     && (totalBytesRead < maxReceiveSize));

            debug.write(DCOM,"totally read "+data.length()+" bytes from socket");
        } catch (IOException e) {
            debug.write("IOException " + e);
            event.write(e,"IOException receive via TCPIPConnection");
            exception = e;
        }
    } else if (connType == CONN_SERVER) {
        debug.write("Attempt to receive data from server type connection.");
    } else {
        debug.write("Unknown connection type = " + connType);
    }

    debug.exit(DCOMD,this);
    if (exception != null) {
        throw exception;
    }
    return data;
}

谢谢和问候 Raaghu.K

1 个答案:

答案 0 :(得分:0)

即使没有看到调用它的循环,你的accept()代码也会发生太大的事情。接受厕所应该是这样的:

while (true)    // or other condition
{
    new Thread(new TCPIPConnection(ServerSocket.accept())).start();
}

错误处理等省略。你在这个循环中花费的时间越长,你就越会延迟后续的客户。

相比之下,您的代码会对每个客户端进行潜在的昂贵且延迟的DNS查找,这实际上完全是冗余的,因为只要需要,客户端就可以通过Socket使用该地址。

还有太多的日志记录,或者至少是在错误的地方登录,并且代码结构非常糟糕,catch块位于错误的位置,通常是空的,后面跟着应该在try块内的代码。修复它也将消除所有那些空测试的需要。

另一个例子是,每次调用accept时都不需要继续重置接受超时。在不同方法中存在两个accept()调用也表示错误或前一次代码迭代的遗留。

似乎还有一些尝试在此级别共享客户端和服务器代码,这是无稽之谈。客户端不接受连接,它们通常从发送请求开始,而不是接收它们。或者,如果他们以接收开始,则服务器必须以发送开始。你无法分享这些东西。您可以共享实际的I / O代码,例如准序列化代码,但不是发送/接收逻辑,当然也不是接受连接的代码。

你的帖子和评论也表现出很多混乱。接受连接:读取数据。不接受数据。代码中也存在同样的混淆。清晰的思维导致清晰的代码。

您需要注意所有这些,以及TCPIPConnection的构造函数中发生的事情。消除任何耗时或可能阻塞的操作,尤其是网络I / O:将其移至run()方法的开头。