简体   繁体   中英

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. 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.

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.


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. This will cause read and equivalent calls to return without reading anything.

Note that the read methods return the number of bytes (or characters) that they have read, or -1 if they detect "end of stream". 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.


Another possible problem with your code is that your listen method is creating a brand new Thread each time an accept() call succeeds.

  • 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.

@chanjaster suggested using an executor with a fixed sized thread pool. 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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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