Несколько не одновременных клиент-серверных подключений Java, использующих всегда один и тот же порт - PullRequest
2 голосов
/ 17 октября 2011

Я пытаюсь протестировать сценарий, в котором один сервер принимает соединения (по одному каждый раз) от одного клиента, используя всегда одни и те же порты (на сервере и на стороне клиента).

Цель состоит в том, чтобы 1 клиентское приложение отправляло небольшие фрагменты данных со скоростью, превышающей 100 в минуту. Совершенно очевидным решением было бы иметь всегда подключенную связь между клиентом и сервером, но это производственный материал, и это потребовало бы больших изменений в коде, который уже реализован. С решением, которое мы внедрили сегодня, у нас всегда есть + -1K соединений в TIME_WAIT, и я хочу избавиться от них.

Я реализовал простой тестер, а код:

public class Server {
    public static void main(String[] args) {
        ServerSocket ssock = null;
        try {
            ssock = new ServerSocket();
            ssock.bind(new InetSocketAddress(Common.SERVER_PORT));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        while(true){
            try{
                Socket cSock = ssock.accept();

                BufferedReader reader = new BufferedReader(new InputStreamReader(cSock.getInputStream()));
                reader.readLine();

                PrintWriter writer = new PrintWriter(cSock.getOutputStream());
                writer.println(Common.SERVER_SEND);
                writer.flush();

                reader.close();
                writer.close();
                cSock.close();

            }catch (Exception e) {
                System.out.println(e.getClass().getName() + ": " + e.getMessage());
            }
        }
    }
}


public class Client {

    public static void main(String[] args) throws Exception {
        InetSocketAddress cliAddr = new InetSocketAddress(
                InetAddress.getByName(args[0]), 
                Common.CLIENT_PORT);

        InetSocketAddress srvAddr = new InetSocketAddress(
                InetAddress.getByName(args[1]), 
                Common.SERVER_PORT);

        for(int j=1;j<=50;j++){
            Socket sock = null;
            try{
                sock = new Socket();
                sock.setReuseAddress(true);
                sock.bind(cliAddr);
                sock.connect(srvAddr);

                PrintWriter writer = 
                        new PrintWriter(
                                sock.getOutputStream());

                writer.println(Common.CLIENT_SEND);
                writer.flush();

                BufferedReader reader = 
                        new BufferedReader(
                                new InputStreamReader(
                                        sock.getInputStream()));
                reader.readLine();

            }catch (Exception e) {
                System.out.println(e.getClass().getName() + ": " + e.getMessage());
                System.exit(-1);
            }finally{
                if(sock!=null) sock.close();
                System.out.println("Done " + j);
            }
        }
    }
}

public class Common {
    public static final int SERVER_PORT = 9009;
    public static final int CLIENT_PORT = 9010;
    public static final String CLIENT_SEND = "Message";
    public static final String SERVER_SEND = "OK";
}

При выполнении клиента и сервера, на хостах Windows, при выполнении одного клиента я всегда получаю

java.net.ConnectException: Connection timed out

При выполнении клиента и сервера на хостах Linux, на некоторых клиентских выполнениях я получаю

java.net.NoRouteToHostException: Cannot assign requested address

Я убивал себя из-за этого поведения. Может кто-то сказать, пожалуйста, можно ли делать то, что я хочу, и что я делаю неправильно?

1 Ответ

0 голосов
/ 17 октября 2011

Если вы хотите избавиться от состояния TIME_WAIT, не будьте партнером, который получает закрытие. Будьте пэром, который инициирует закрытие. В этом случае закройте соединение сразу после прочтения ответа и заставьте сервер циклически искать другой запрос, чтобы он считывал EOF, а не просто закрывал соединение сразу после отправки ответа. Однако это только усугубит проблему, поскольку все состояния TIME_WAIT будут накапливаться на сервере, а не на клиенте. С другой стороны, сервер теперь структурирован для приема нескольких запросов на соединение, поэтому все, что вам нужно сделать, это настроить клиентов для использования пула соединений, и все ваши проблемы будут решены.

...