简体   繁体   English

Java套接字占用太多的CPU和虚拟内存

[英]java socket takes too much cpu% and virtual memory

I have developed a java socket, but it takes too many cpu and virtual memory usages. 我已经开发了一个Java套接字,但是它占用了太多的CPU和虚拟内存。 Can you tell me what is the problem in my code? 您能告诉我代码中的问题是什么吗?

private void listen() {
    try {
        serverSocket = new ServerSocket(port);

        System.out.println("Server socket listening on port: " + port);
        System.out.println("Waiting for connections...");

        while(true) {
            // accept the connection
            Socket socket = serverSocket.accept();
            socket.setSoTimeout(30000);
            System.out.println("Got connection");
            // start processing the connection
            Thread connectionManager = new Thread(new Elevator(socket, socket.getInputStream()));//new Thread(new ConnectionManager(socket, odometer));
            connectionManager.start();
        }
    } catch (IOException exc) {
        System.out.println(Listener.class.getName() + ": " + exc.getMessage());
    }
}

in Elevator class I have this: 在电梯班我有这个:

public class Elevator implements Runnable 
{

private String imei;
private Socket socket;
private InputStream is;
private PrintWriter out;
private OutputStream ds;
private int packetL;
private long timestamp;
dbElevatorManipulate dbElevator;
private String[] allCards = null;
private String[] insCards = null;
private String[] upddelCards = null;
private String[] config = null;


public Elevator(Socket socket, InputStream is) {
    this.socket = socket;
    this.is = is;
    initializeOutputStream(socket);
}

private void initializeOutputStream(Socket socket) {
    try {
        ds = socket.getOutputStream();
    } catch (IOException e) {
        e.printStackTrace();
    }
    out = new PrintWriter(ds, true);
}


@Override
public void run(){

    int codecL = 1;
    int imeiL = 16;

    String codecID = "";
    String imeiFromBoard = "";

    byte[] codecBuffer = new byte[codecL];
    byte[] imeiBuffer = new byte[imeiL];

    try{
        // Read codec ID.
        is.read(codecBuffer, 0, codecL);
        codecID = byteToString(codecBuffer);
        //System.out.println("Codec ID   : " + codecID);

        // Read imei.
        is.read(imeiBuffer, 0, imeiL);
        imeiFromBoard = byteToString(imeiBuffer);

        if (codecID.equals("2")) {

            byte[] crc = new byte[2];
            is.read(crc);

            byte[] cnnpacket = new byte[codecL + imeiL];

            cnnpacket[0] = codecBuffer[0];
            for (int i = 1; i < cnnpacket.length; i++) {
                cnnpacket[i] = imeiBuffer[i-1];
            }

            if(DataLayer.checksum(cnnpacket, crc))
            {

                try {
                    ds.write(1);
                    ds.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            else
            {

                try {
                    ds.close();
                    is.close();
                    dbElevator.disconnect();
                    socket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return;
            }
        }
    }
    catch(Exception ex)
    {
        System.out.println("Error: " + ex.getMessage());
    }

    imeiFromBoard = imeiFromBoard.substring(1, imeiFromBoard.length());
    imei = imeiFromBoard;
    System.out.println("got connection with imei:" + imei);
    dbElevator = new dbElevatorManipulate(imei);
    dbElevator.connect();
    try{
            while(true){        
            byte[] packet = new byte[1024];
            int i = 0;
            int byteread = is.read(packet);

            if(byteread == -1) continue;
            int cmdL = 1;
            int dataLen = 2;
            byte[] cmdBuffer = new byte[cmdL];
            byte[] lengthBuffer = new byte[dataLen];

            // Read and Print cmd.
            cmdBuffer[0] = packet[0];

            if(cmdBuffer[0] > 9 || cmdBuffer[0] < 0){
                continue;
            }

            // Read and Print data length.
            lengthBuffer[0] = packet[1];
            lengthBuffer[1] = packet[2];

            packetL = Integer.parseInt(DataLayer.byteToString(lengthBuffer));

            // Reading a printing the packet .
            byte[] packetBuffer = new byte[packetL];
            int pcnt = 3;
            while(packetL-- > 0)
            {
                packetBuffer[pcnt - 3] = packet[pcnt];
                pcnt++;

            }
            String packetData = DataLayer.byteToString(packetBuffer);
            // Reading and printing crc
            int crcL = 2;
            byte[] crcBuffer = new byte[crcL];
            crcBuffer[0] = packet[pcnt];
            crcBuffer[1] = packet[pcnt + 1];

            if (DataLayer.checksum(packetBuffer, crcBuffer)) {
                System.out.println("Packet: OK");

                switch(cmdBuffer[0])
                {
                    case 0: 
                        int nrOfPackets = dbElevator.getNrOfTotalPackets();
                        int nCrc = DataLayer.crc16(new byte[] {(byte)nrOfPackets});
                        byte[] sendPacket = new byte[3];
                        sendPacket[0] = (byte)nrOfPackets;
                        sendPacket[1] = (byte)((nCrc >> 8) & 0xff); // hight byte of crc
                        sendPacket[2] = (byte)(nCrc & 0xff);        // low byte of crc

                        ds.write(sendPacket);
                        ds.flush();
                        allCards = dbElevator.getTotalCards().split(",");
                        break;
                    case 1: 
                        int PacketNo = Integer.parseInt(packetData);
                        if(allCards != null)
                            sendAllPacket(PacketNo);
                        break;
                    case 2: 
                        int nrOfUpdPackets = dbElevator.getUpdDelCardsNo();
                        int updCrc = DataLayer.crc16(new byte[] {(byte)nrOfUpdPackets});
                        byte[] sendUpdPacket = new byte[3];
                        sendUpdPacket[0] = (byte)nrOfUpdPackets;
                        sendUpdPacket[1] = (byte)((updCrc >> 8) & 0xff); // hight byte of crc
                        sendUpdPacket[2] = (byte)(updCrc & 0xff);       // low byte of crc

                        ds.write(sendUpdPacket);
                        ds.flush();
                        upddelCards = dbElevator.getUpdDelCards().split(",");
                        break;
                    case 3:
                        int updPacketNo = Integer.parseInt(packetData);
                        sendUpdDelPacket(updPacketNo);
                        break;
                    case 4: 
                        int nrOfInsPackets = dbElevator.getInsertedCardsNo();
                        int insCrc = DataLayer.crc16(new byte[] {(byte)nrOfInsPackets});
                        byte[] sendInsPacket = new byte[3];
                        sendInsPacket[0] = (byte)nrOfInsPackets;
                        sendInsPacket[1] = (byte)((insCrc >> 8) & 0xff); // hight byte of crc
                        sendInsPacket[2] = (byte)(insCrc & 0xff);       // low byte of crc

                        ds.write(sendInsPacket);
                        ds.flush();
                        insCards = dbElevator.getInsertedCards().split(",");
                        break;
                    case 5: 
                        int insPacket = Integer.parseInt(packetData);
                        sendInsPacket(insPacket);
                        break;

                    case 6: 
                        insertCheckInIntoDB(packetBuffer);
                        break;
                    case 7:
                        config  = dbElevator.getConfig().split(",");
                        sendConfig(config);
                        break;
                    case 8: //log cards and close connection
                        try {
                                if(insCards != null && insCards.length > 2)
                                {
                                    dbElevator.resetActionForIns(insCards);
                                    dbElevator.LogSent_insCards(insCards);

                                }
                                if(upddelCards != null && upddelCards.length > 2)
                                {   
                                    dbElevator.resetActionForUpd(upddelCards);
                                    dbElevator.LogSent_updCards(upddelCards);
                                }
                                if(allCards != null && allCards.length > 2)
                                {
                                    dbElevator.resetActionForAll(allCards);
                                    dbElevator.LogSent_allCards(allCards);
                                }
                                if(config != null && config.length > 0)
                                {
                                    dbElevator.ConfigSent();
                                }

                                ds.close();
                                is.close();
                                dbElevator.disconnect();
                                System.out.println("database disconnected");
                                socket.close();
                                System.out.println("socket closed.");
                                return;

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        break;
                    case 9:
                        int sendConfig = dbElevator.getSendConfig();

                        int sendConfigCRC = DataLayer.crc16(new byte[] {(byte)sendConfig});
                        byte[] sendConfigConfirm = new byte[3];
                        sendConfigConfirm[0] = (byte)sendConfig;
                        sendConfigConfirm[1] = (byte)((sendConfigCRC >> 8) & 0xff); 
                        sendConfigConfirm[2] = (byte)(sendConfigCRC & 0xff);        
                        ds.write(sendConfigConfirm);
                        ds.flush();
                        break;
                }

            }else{
                //System.out.println("Packet: error");
                ds.write(0x00);
                ds.flush();
            }
            }   
        }catch(IOException e){
            e.printStackTrace();
        }
    finally{
        try {
            ds.close();
            System.out.println("ds closed.");
            is.close();
            System.out.println("is closed.");
            dbElevator.disconnect();
            System.out.println("db disconnected.");
            socket.close();
            System.out.println("socket closed.");
            //break;
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}

private void sendConfig(String[] config) throws IOException {
    byte[] packet = new byte[16*3];
    for(int c = 0, i = 0; c<32; c++)
    {
        if(c<16){
            int temp = Integer.parseInt(config[c],2);
            packet[i++] = (byte)((temp >> 8) & 0xff);
            packet[i++] = (byte)(temp & 0xff);
        }
        else
        {
            packet[i++] = (byte)(Integer.parseInt(config[c]) & 0xff);
        }
    }

    int crc = DataLayer.crc16(packet);

    byte[] txPacket = new byte[3*16 + 2];

    for(int i = 0; i<16*3; i++)
    {
        txPacket[i] = packet[i];
    }

    txPacket[16*3] = (byte)((crc >> 8) & 0xff);
    txPacket[16*3 + 1] = (byte)((crc) & 0xff);
    ds.write(txPacket);
    ds.flush();
}

private void insertCheckInIntoDB(byte[] packetData){

    String values = "";
    try{
        for(int i = 0; i<packetData.length; i+=8)
        {

            byte[] siteCode = new byte[1];
            siteCode[0] = packetData[i];

            byte[] siteNo = new byte[2];
            siteNo[0] = packetData[i + 1];
            siteNo[1] = packetData[i + 2];

            byte[] Floor = new byte[1];
            Floor[0] = (byte)(packetData[i + 3] >> 4 & 0xf);

            byte[] Valide = new byte[1];
            Valide[0] = (byte)(packetData[i + 3] & 0xf);

            byte[] timestamp = new byte[4];
            timestamp[0] = packetData[i + 4];
            timestamp[1] = packetData[i + 5];
            timestamp[2] = packetData[i + 6];
            timestamp[3] = packetData[i + 7];
            if(Long.parseLong(DataLayer.byteToString(timestamp)) < 1410000000)
            {
                continue;
            }
            values += "(" + imei + ",";
            values += DataLayer.byteToString(siteCode) + ",";
            values += DataLayer.byteToString(siteNo) + ",";
            values += DataLayer.byteToString(Floor) + ",";
            values += DataLayer.byteToString(Valide) + ",";
            values += DataLayer.byteToString(timestamp) + "),";
        }
        values = values.substring(0, values.length()-1);
        if(dbElevator.insertCheckIn(values))
        {
            ds.write(1);
            ds.flush();
            return;
        }
        else
        {
            try {
                ds.write(0);
                ds.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }   
    }
    catch(Exception ex){
        try {
            ds.write(0);
            ds.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private void sendUpdDelPacket(int updPacketNo) throws IOException {
    byte[] packet = new byte[38*6];

    for(int i = 0, c = 38*4*updPacketNo; i<38*6; i+=6, c+=4)
    {
        if(c + 3 < upddelCards.length)
        {
            packet[i]   = (byte)Integer.parseInt(upddelCards[c]);

            //System.out.println(upddelCards[c+1]);
            packet[i+1] = (byte)(Integer.parseInt(upddelCards[c+1]) >> 8 & 0xff);
            packet[i+2] = (byte)(Integer.parseInt(upddelCards[c+1]) & 0xff);
            packet[i+3] = (byte)(Integer.parseInt(upddelCards[c+2], 2) >> 8 & 0xff);
            packet[i+4] = (byte)(Integer.parseInt(upddelCards[c+2], 2) & 0xff);
            packet[i + 5]   = (byte)Integer.parseInt(upddelCards[c + 3]);
        }
        else
        {
            packet[i] = 0;
            packet[i+1] = 0;
            packet[i+2] = 0;
            packet[i+3] = 0;
            packet[i+4] = 0;
            packet[i+5] = 0;
        }
    }

    int crc = DataLayer.crc16(packet);

    byte[] txPacket = new byte[38*6 + 2];

    for(int i = 0; i<38*6; i++)
    {
        txPacket[i] = packet[i];
    }
    txPacket[38*6] = (byte)((crc >> 8) & 0xff);
    txPacket[38*6 + 1] = (byte)((crc) & 0xff);
    ds.write(txPacket);
    ds.flush();
}

private void sendInsPacket(int packetNo) throws IOException {

    byte[] packet = new byte[46*5];
    for(int i = 0, c = 46*3*packetNo; i< 46*5; i+=5, c+=3)
    {
        if(c + 2 < insCards.length)
        {
            packet[i]   = (byte)Integer.parseInt(insCards[c]); 

            packet[i+1] = (byte)(Integer.parseInt(insCards[c+1]) >> 8 & 0xff);
            packet[i+2] = (byte)(Integer.parseInt(insCards[c+1]) & 0xff);
            packet[i+3] = (byte)(Integer.parseInt(insCards[c+2], 2) >> 8 & 0xff);
            packet[i+4] = (byte)(Integer.parseInt(insCards[c+2], 2) & 0xff);
        }
        else
        {
            packet[i]   = 0;
            packet[i+1] = 0;
            packet[i+2] = 0;
            packet[i+3] = 0;
            packet[i+4] = 0;
        }

    }

    int crc = DataLayer.crc16(packet);

    byte[] txPacket = new byte[46*5 + 2];

    for(int i = 0; i<46*5; i++)
    {
        txPacket[i] = packet[i];
    }
    txPacket[46*5] = (byte)((crc >> 8) & 0xff);
    txPacket[46*5 + 1] = (byte)((crc) & 0xff);
    ds.write(txPacket);
    ds.flush();
}

private void sendAllPacket(int packetNo) throws IOException {

    byte[] packet = new byte[46*5];
    for(int i = 0, c = 46*3*packetNo; i< 46*5; i+=5, c+=3)
    {
        if(c + 2 < allCards.length)
        {
            packet[i]   = (byte)Integer.parseInt(allCards[c]);

            packet[i+1] = (byte)(Integer.parseInt(allCards[c+1]) >> 8 & 0xff);
            packet[i+2] = (byte)(Integer.parseInt(allCards[c+1]) & 0xff);
            packet[i+3] = (byte)(Integer.parseInt(allCards[c+2], 2) >> 8 & 0xff);
            packet[i+4] = (byte)(Integer.parseInt(allCards[c+2], 2) & 0xff);
        }
        else
        {
            packet[i]   = 0;
            packet[i+1] = 0;
            packet[i+2] = 0;
            packet[i+3] = 0;
            packet[i+4] = 0;
        }

    }

    int crc = DataLayer.crc16(packet);

    byte[] txPacket = new byte[46*5 + 2];

    for(int i = 0; i<46*5; i++)
    {
        txPacket[i] = packet[i];
    }
    txPacket[46*5] = (byte)((crc >> 8) & 0xff);
    txPacket[46*5 + 1] = (byte)((crc) & 0xff);
    ds.write(txPacket);
    ds.flush();
}

private static String byteToString(byte[] buffer) {
    StringBuilder s = new StringBuilder();
    for (byte b : buffer) {
        s.append((char) b);
    }
    return s.toString();
}

What can I do about this problem ? 该问题我该怎么办? Thanks in advance. 提前致谢。

You appear to be doing a lot of small reads directly on a socket's input stream. 您似乎直接在套接字的输入流上进行了许多小读操作。 You should get better performance if you wrap the input stream with a buffered input stream. 如果使用缓冲的输入流包装输入流,则应该获得更好的性能。

The use of buffered streams is discussed in the Oracle Java Tutorial. Oracle Java教程中讨论了缓冲流的使用

The output side looks a bit better. 输出端看起来更好一些。 You are assembling packets, and writing them in large(er) write calls. 您正在组装数据包,并将其写入较大的写入调用中。 However, I'm still suspicious of that ... and the possibility that some of the flush calls are unnecessary. 但是,我仍然对此表示怀疑,并且可能没有必要进行某些flush调用。


As EJP points out, your I/O code is fragile because you don't take account of the possibility that the "other end" has closed the socket. 正如EJP指出的那样,您的I / O代码很脆弱,因为您没有考虑“另一端”已关闭套接字的可能性。 This will cause read and equivalent calls to return without reading anything. 这将导致read和等效调用返回,而不读取任何内容。

Note that the read methods return the number of bytes (or characters) that they have read, or -1 if they detect "end of stream". 请注意, read方法返回已读取的字节(或字符)数,如果检测到“流的末尾”,则返回-1。 Your code is completely ignoring the return value. 您的代码完全忽略了返回值。

It is possible that this is the cause of your performance problems; 这可能是导致性能问题的原因; eg if a thread is repeatedly calling read on a socket that is in "end of stream" state. 例如,如果线程反复调用处于“流结束”状态的套接字上的read


Another possible problem with your code is that your listen method is creating a brand new Thread each time an accept() call succeeds. 代码的另一个可能问题是,每次accept()调用成功时,您的listen方法都将创建一个全新的Thread

  • If you have lots of clients connecting, there will be lots of threads, and this results in lots of resource usage. 如果有很多客户端连接,那么会有很多线程,这会导致大量资源使用。
  • If clients don't disconnect and/or the server doesn't notice that they have disconnected, then the resources will leak, and your server will never give them back. 如果客户端没有断开连接和/或服务器没有注意到它们已断开连接,则资源将泄漏,并且服务器将永远不会将其退还。

If you are leaking threads, and those threads are sitting idle, then they are wasting memory. 如果您正在泄漏线程,而这些线程处于空闲状态,则它们正在浪费内存。 (A thread stack is typically 1Mb or so.) If they are not idle (eg because of a bug in your read code ... like not dealing with the "end of stream" condition properly) then you will be wasting CPU too. (线程堆栈通常为1Mb左右。)如果它们不处于空闲状态(例如,由于读取代码中的错误……例如未正确处理“流的结尾”条件),那么您也将浪费CPU。

@chanjaster suggested using an executor with a fixed sized thread pool. @chanjaster建议使用具有固定大小的线程池的执行程序。 This might help in a couple of respects: 这可能在两个方面有所帮助:

  • It prevents the application using an unbounded number of threads. 它防止应用程序使用无数线程。
  • It recycles the threads after they are no longer active ... which reduces overheads. 在线程不再活动之后,它将回收线程...这减少了开销。

However, if you have a resource leakage problem, a thread pool won't cure this. 但是,如果您遇到资源泄漏的问题,线程池将无法解决此问题。 Indeed, what will probably happen is that new connections just freeze. 确实,可能会发生的是新连接刚刚冻结。 (They go into the task queue waiting for a worker thread to pick them up. And that never happens.) (它们进入任务队列,等待辅助线程将其拾取。这永远不会发生。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM