Как убедиться, что сокет TCP закрыт на другом конце?(как читать сигнал подтверждения) - PullRequest
1 голос
/ 05 марта 2012

рассмотрим приведенный ниже псевдокод Java (клиент открывает сокет для сервера с IP-адресом и портом 23 (telnet):

  static Socket skt = null;   
  skt = new Socket(IP, 23);
  do something
  skt.close()
  ALMOST NO DELAY
  skt = new Socket(IP, 23); // re-opening same socket variable (skt) right after closing it

.. и иногда происходит исключение ниже, потому что мы пытаемсяповторное открытие того же сокета, который еще не полностью закрыт. ОШИБКА: java.io.IOException: сброс соединения

Как я могу убедиться (чтобы проверить) сокет закрыт на другом конце? другими словами, чтобыдождитесь подтверждения от сервера, прежде чем мы продолжим и снова откроем этот сокет в другой части кода - по какой-то причине мы должны снова открыть тот же сокет - также мы не заинтересованы в размещении задержек перед повторным открытием того же самого сокетасокет.

Вкратце: мы хотели бы прочитать подтверждение от сервера (синяя линия)

enter image description here

Ответы [ 3 ]

2 голосов
/ 05 марта 2012

Сокет идентифицируется по IP-адресу и порту на обоих концах, источника и назначения. Ваше второе соединение должно получить другой исходный порт, поэтому сервер будет рассматривать его как отдельное соединение. Убедитесь, что сервер постоянно принимает новые подключения, и с вами все будет в порядке.

1 голос
/ 06 марта 2012

Печатайте локальный порт клиентского сокета каждый раз после его создания. Если вы получаете новый локальный порт для каждого нового клиентского сокета, на самом деле очень маловероятно, что будет проблема с «повторным использованием сокетов», если в стеке TCP не будет ошибки. Кстати, вы явно указываете локальный номер сокета через, например, Socket.bind или Конструктор Socket, который принимает локальный порт ? Вы, вероятно, не должны. Просто позвольте системе выбрать временный порт.


Проблема может быть в сервере, а не в клиенте. У меня нет проблем, когда я закрываю, а затем сразу воссоздаю клиентский сокет на тот же хост и порт. SSCCE сделал это до 130 тыс. Соединений без проблем, прежде чем я ушел. Интерфейс обратной связи может быть более снисходительным, чем реальная сетевая карта, но вы можете легко изменить этот код для работы в реальной сети.

public class TestTcpClientServer
{
    public static final int SERVER_PORT = 10111;

    public static void main(String[] args) throws Exception
    {
        Server server = new Server();
        server.start();

        Thread.sleep(500);

        Client client = new Client();
        client.start();

        System.out.println("Press enter to shutdown...");

        System.in.read();

        client.shutdown();
        client.join();
        server.shutdown();
        server.join();

        System.out.println("Done.");
    }

    public static class Client extends Thread
    {
        private volatile boolean shutdown = false;

        public void run()
        {
            try
            {
                int totalClientConnections = 0;

                while (!shutdown)
                {
                    Socket socket = new Socket("localhost", SERVER_PORT);

                    InputStream inputStream = socket.getInputStream();
                    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

                    OutputStream outputStream = socket.getOutputStream();
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));

                    bw.write("Client saying hello to server");
                    bw.newLine();
                    bw.flush();

                    String readLine = br.readLine();
                    //System.out.println("Client read from server: " + readLine);

                    System.out.println("Socket local port: " + socket.getLocalPort());

                    socket.close();

                    totalClientConnections++;
                    if (totalClientConnections % 10000 == 0)
                    {
                        System.out.println("totalClientConnections=" + totalClientConnections);
                    }

                    Thread.sleep(1000);
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        public void shutdown()
        {
            shutdown = true;
        }
    }

    public static class Server extends Thread
    {
        private volatile boolean shutdown = false;
        private ServerSocket serverSocket = null;

        public void run()
        {
            try
            {
                int totalServerConnections = 0;

                serverSocket = new ServerSocket(SERVER_PORT);

                while (!shutdown)
                {
                    Socket socket = serverSocket.accept();

                    InputStream inputStream = socket.getInputStream();
                    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

                    OutputStream outputStream = socket.getOutputStream();
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));

                    String readLine = br.readLine();
                    //System.out.println("Server read from client: " + readLine);

                    bw.write("Server saying hello to client");
                    bw.newLine();
                    bw.flush();

                    socket.close();

                    totalServerConnections++;
                    if (totalServerConnections % 10000 == 0)
                    {
                        System.out.println("totalServerConnections=" + totalServerConnections);
                    }
                }
            }
            catch (Exception e)
            {
                if (!shutdown)
                {
                    e.printStackTrace();
                }
            }
        }

        public void shutdown()
        {
            shutdown = true;
            try
            {
                serverSocket.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
}
0 голосов
/ 06 марта 2012

.. и исключение ниже иногда случается, потому что мы пытаемся повторно открыть тот же сокет, который еще не полностью закрыт ОШИБКА: java.io.IOException: Сброс соединения

Ваш анализ неверен.Это не причина.Розетка совершенно новая.Связь совершенно новая.Если вы получили «сброс соединения», то это потому, что серверное программное обеспечение решило сбросить соединение.На этом этапе вы ничего не можете с этим поделать, кроме как выяснить причину и при худшем сне и повторить попытку.

Это также не имеет никакого отношения к исчерпанию локальных портов, как предполагают некоторые другие ответы.Если бы это была проблема, вы бы получили BindException.

Тот факт, что ваш клиент отправляет RST, очень любопытен.Вы вызываете некоторые Socket API, которые вы не показывали выше?

...