Lucas Batistussi
Lucas Batistussi

Reputation: 2343

Is there any performance issue allocate ByteBuffer with one position?

I was wondering if there is any performance issue related to read just one byte from AsynchronousSocketChannel. I am implementing a simple HTTP server and parsing a request where I need read byte per byte:

    ByteBuffer dst = ByteBuffer.allocate(1);

    int end = 0;

    int br = 0;
    int bread = 0;

    StringBuilder sb = new StringBuilder();

    while(bread < RCV_BUF){

        br = client.read(dst).get();

        //End of stream and nothing :(
        if(br == 0){
            return null;
        }

        dst.flip();

        bread += br;

        byte b = dst.get();

        dst.clear();

        if((end == 0 && b == '\r') || (end == 1 && b == '\n') || (end == 2 && b == '\r')){
            end++;
        }
        else 
            if(end == 3 && b == '\n'){
                break;
            }
            else
            {
                end = 0;
            }

        sb.append((char)b);

    }

Can a Java expert explain me if that practice is bad or not in terms of performance?

Upvotes: 0

Views: 696

Answers (2)

Lucas Batistussi
Lucas Batistussi

Reputation: 2343

Well! I found a more efficient way to deal with this! I allocated ByteBuffer with a min size! The bad thing is that I introduced some complexity in the parser. But anyway...

    int RCV_BUF = client.getOption(StandardSocketOptions.SO_RCVBUF);

    ByteBuffer dst = ByteBuffer.allocate(256);

    int end = 0;

    int br = 0;
    int bread = 0;

    StringBuilder sb = new StringBuilder();

    boolean endr = false;
    boolean cr = false;

    //Try parse headers
    while(!endr && bread < RCV_BUF){

        br = client.read(dst).get();

        //End of stream and nothing :(
        if(br == 0){
            return null;
        }

        dst.flip();

        bread += br;

        while(dst.hasRemaining()){

            byte b = dst.get();

            if(end == 0 && b == '\r'){      
                end++;
                continue;
            }

            // Possible header...
            if(end == 1){

                      // We got a header!
                if(b == '\n'){

                    // Reached the end of headers!
                    if(cr){
                        endr = true;
                        break;
                    }

                    cr = true;

                    end = 0;

                    System.out.println(sb.toString());

                    sb = new StringBuilder();

                    continue;
                }

                //Bad request (send a 400 status code...)!
                return null;
            }

            if(cr){
                cr = false;
            }

            sb.append((char)b);

        }

        dst.clear();

    }

Upvotes: 0

mikera
mikera

Reputation: 106361

Normally you would try to read in as many bytes as possible into the buffer, all at once. This is significantly more efficient: ByteBuffers are highly optimised for reads and writes of big sequential chunks of bytes.

However, you can still make ByteBuffers work with a buffer size of one. If the volume of byte reads is smallish (say, 100,000 bytes per second or less) then I doubt it will make any noticeable difference. Your code looks fine for handling that sort of volume. As always, you should benchmark if you think it is a real concern, but there's little point optimising code if it is already fast enough for your needs.

But more seriously, I would question why you are writing this kind of code at all? Why not use a well tested library like (e.g. Netty) which should do all of this sort of stuff for you?

Upvotes: 2

Related Questions