Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java slow socket.connect()

Tags:

java

sockets

Below is the source code of a client and a server. The client just connects (concurrently) to the server and immediatly closes the connection. When all threads are done, it waits 2 minutes and connects again. I am confused about the fact that sometimes a simple connect needs around 3 seconds! Most of the time a connect needs just around 0-32ms.

Here a typical output from the client:

...
Connect 23 [ms]: 16
Connect 22 [ms]: 32
Connect 21 [ms]: 32
Connect 15 [ms]: 32
Connect 14 [ms]: 16
Connect 13 [ms]: 16
Connect 11 [ms]: 32
Connect 25 [ms]: 3016

This only seems to happen if client and server are on different hosts. Windows and linux comparable behaviour Java 1.6.23

to start the server 2 parameters are needed: [port] [thread pool size]

to start the client 3 parameters are needed: [host] [port] [thread pool size]

for the example i used 150 thread pool size for server and 25 thread pool size for the client.

Can anybody explain this behaviour?

----- server -----

package de.test.server;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ServerApp {

   public static void main(String[] args) throws IOException {
      System.out.println("server running...");

      final int port = Integer.parseInt(args[0]);
      final int threads = Integer.parseInt(args[1]);
      final ExecutorService executorService = Executors
            .newFixedThreadPool(threads);
      ServerSocket serverSocket = new ServerSocket(port);
      while (true) {
         final Socket clientSocket = serverSocket.accept();

         executorService.execute(new Runnable() {
            @Override
            public void run() {
               try {
                  InputStream is = clientSocket.getInputStream();
                  int read = is.read();
                  if (read != -1) {
                     System.out.println("should not happen");
                  }
               } catch (IOException e) {
                  throw new RuntimeException(e);
               } finally {
                  close(clientSocket);
                  System.out.println("connection closed");
               }
            }

            private void close(final Socket connection) {
               try {
                  connection.close();
               } catch (IOException e1) {
                  throw new RuntimeException(e1);
               }
            };
         });
      }
   }
}

----- client -----

package de.test.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;

public class ConnectApp {

   public static void main(String[] args) throws InterruptedException {
      final String host = args[0];
      final int port = Integer.parseInt(args[1]);
      final int THREAD_COUNT = Integer.parseInt(args[2]);

      final ExecutorService executorService = Executors
            .newFixedThreadPool(THREAD_COUNT);
      final AtomicLong threadCounter = new AtomicLong(0);
      while (true) {
         final CountDownLatch doneSignal = new CountDownLatch(THREAD_COUNT);
         for (int i = 0; i < THREAD_COUNT; i++) {
            executorService.execute(new Runnable() {
               @Override
               public void run() {
                  Socket socket = null;
                  try {
                     long start = System.currentTimeMillis();
                     socket = new Socket();

                     socket.setTcpNoDelay(true);
                     socket.connect(new InetSocketAddress(host, port));
                     System.out.println(socket.getTcpNoDelay());
                     long stop = System.currentTimeMillis();
                     System.out.println("Connect "
                           + threadCounter.incrementAndGet() + " [ms]: "
                           + (stop - start));
                  } catch (UnknownHostException e) {
                     throw new RuntimeException(e);
                  } catch (IOException e) {
                     throw new RuntimeException(e);
                  } finally {
                     close(socket);
                     doneSignal.countDown();
                  }

               }

               private void close(Socket socket) {
                  try {
                     if (socket != null)
                        socket.close();
                  } catch (IOException e1) {
                     throw new RuntimeException(e1);
                  }
               }
            });
         }
         doneSignal.await();
         System.out.println("Waiting 2 minutes...");
         Thread.sleep(1000 * 60 * 2);
      }
   }
}
like image 961
coder Avatar asked Nov 05 '22 03:11

coder


1 Answers

All your sockets are trying to connect at once. Since they are all trying to connect to the same single threaded server, one will be accept, 50 (by default) will be in the backlog and the reset may not connect or have to wait a particularly long time.

I suggest trying a 40 ms spacing between attempting to connect to see if this is the problem.

BTW: you only call threadCounter.incrementAndGet() so why is it going up and down? You could just use

for (int i = 0; i < THREAD_COUNT; i++) {
    final int threadCount = i;
like image 161
Peter Lawrey Avatar answered Nov 12 '22 15:11

Peter Lawrey