简体   繁体   中英

How to handle HTTP request using Java Socket?

I am trying to implement sample HTTP server using Java socket and executor service for concurrency. However every 2nd request is failing when I run the test using JMeter with 2 or more requests or browser for example.

How to properly handle the request? Here is the sample source code:

public class Service {
    public static void main(String[] args) throws Exception {
        var serverSocket = new ServerSocket(8080);
        var executors = Executors.newFixedThreadPool(4);
        while(true) {
            try {
                var server = serverSocket.accept();

                executors.submit(() -> {
                    try {
                        var text = "sample";
                        System.out.println("Waiting for client on port " +
                                serverSocket.getLocalPort() + "...");

                        System.out.println("Getting empty request");
                        var response = "HTTP/1.1 200 OK\r\n" +
                                    "Content-Type: text/plain\r\n" +
                                    "Content-Length: " + text.length() + "\r\n\r\n"
                                    + text;
                        server.getOutputStream().write(response.getBytes(StandardCharsets.UTF_8));
                    } catch (Exception e) {
                        System.out.println("Executor error:" + e.toString());
                        e.printStackTrace();
                    } finally {
                        try {
                            System.out.println("Closing server");
                            server.close();
                        } catch (Exception e) {
                            System.out.println("Executor error2: ");
                            e.printStackTrace();
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }

        serverSocket.close();
    }
}

Your first problem lies in your response.

"HTTP/1.1 200 OK\r\n"

That allows for keep-alive, which you're not handling. A basic JMeter sampler tries to use keep alive, that is why you always fail on the second attempt.

You can change it to

"HTTP/1.0 200 OK\r\n"

That does not support keep alive, so you'll get a lot more successes with your current code. For me I only get a couple 1000 responses before JMeter has another error, but I don't know what the error is.

To support keep alive, I need to parse the request. Here is an example.

    int clients = 0;
    while(true) {
        try {
            System.out.println("Waiting for client on port " +
                            serverSocket.getLocalPort() + "...");
            var server = serverSocket.accept();
            final int client_no = clients++;
            System.out.println("handling: " + client_no);
            executors.submit(() -> {
                int sent = 0;
                try {
                    var is = server.getInputStream();
                    var os = server.getOutputStream();
                    
                    var text = "sample";
                    byte[] tb = text.getBytes(StandardCharsets.UTF_8);

                    char[] buffer = new char[256];
                    int cr_count = 0;
                    while( true ){
                        
                        int i=0;
                        int r = is.read();
                        if(r == -1) break;
                        
                        while( r != -1 ){
                            char c = (char)r;
                            if( c == '\n' ){
                                cr_count++;
                            } else if( c != '\r' ){
                                cr_count = 0;
                            }
                            buffer[i++] = c;
                            if(cr_count == 2) break;
                            r = is.read();
                        }
                        //System.out.println("request: " + new String(buffer));
                        var response = "HTTP/1.1 200 OK\r\n" +
                                    "Content-Type: text/plain\r\n" +
                                    "Content-Length: " + tb.length + "\r\n\r\n";
                        os.write(response.getBytes(StandardCharsets.UTF_8));
                        os.write(tb);
                        os.flush();
                        sent++;
                    }
                } catch (Exception e) {
                    System.out.println("Executor error:" + e.toString());
                    e.printStackTrace();
                } finally {
                    try {
                        System.out.println("Closing connection!");
                        server.close();
                    } catch (Exception e) {
                        System.out.println("Executor error2: ");
                        e.printStackTrace();
                    }
                    System.out.println("sent " + sent + " responses to client " + client_no);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            break;
        }
    }

This will run a JMeter test for me. It can use either 1.0 or 1.1 and finish 10's of thousands of requests. If I use keep alive (1.1) each client handles many requests, if I don't use keep alive (1.0) each client handles 1 request.

If I dont read the request header, then the http 1.0 version will stop after a couple thousand requests.

It is also a separate issue from your original "dies after the second request." which is because your are not actually using HTTP 1.1 !

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