Java сокет прерывистый сбой для чтения данных - PullRequest
1 голос
/ 12 апреля 2019

У меня есть интеграционный тест, который отправляет 800 сообщений клиенту. Клиент получает все сообщения в порядке. Проблема в том, что мой тест периодически дает сбой, потому что сокет (ближе к концу сообщений) не читает байтов (-1) из потока, закрывает сокет, снова открывает сокет и получает байты. Тест «завершается» до того, как окончательные байты будут прочитаны (и поэтому не пройдены), но я вижу в журнале, что последние сообщения успешно попадают к клиенту. Это периодически. Это происходит примерно каждые полдюжины пробежек или около того. Другими словами, возможно, 5 прогонов подряд не приведут к ошибкам (сокет никогда не приходилось закрывать / открывать заново), но 6-й прогон будет иметь эту проблему.

До сих пор я пытался увеличить / уменьшить скорость отправки сообщений.

Сервер:

    try
    {
        srvr = new ServerSocket(PORT);
        Socket socket = srvr.accept();
        ...
        OutputStream out = socket.getOutputStream();

        for (String msg : Messages)
        {
            byte[] bytes = new BigInteger(msg, BASE_16).toByteArray();
            out.write(bytes);
            // Delay so client can keep up.
            sleep(SOCKET_CLIENT_DELAY);
        }
    }
    catch (IOException ioe)
    {
        fail(ioe.getMessage());
    }
    finally
    {
        handleClose(srvr);
    }

Клиент:

@Override
public void run()
{
    final long reconnectAttemptWaitTimeMillis = 5_000;

    Socket socket = null;

    while (true)
    {
        try
        {
            socket = new Socket(host, port);
            boolean isConnected = socket.isConnected();

            if (isConnected)
            {
                read(socket);
            }
        }
        catch (ConnectException ce)
        {
            LOGGER.warn(
                "Could not connect to ADS-B receiver/antenna on [" + host + ":" + port
                        + "]. Trying again in 5 seconds...");

            try
            {
                sleep(reconnectAttemptWaitTimeMillis);
            }
            catch (InterruptedException ie)
            {
                LOGGER.error(ie.getMessage(), ie);
                break;
            }

        }
        catch (IOException ioe)
        {
            LOGGER.error(ioe.getMessage(), ioe);
        }

    }

    LOGGER.info("A total of " + totalEnqueued + " ADS-B messages were enqueued.");

}

/**
 * Reads binary ADS-B messages from the {@link Socket}. Assumption is the given {@link Socket} is connected.
 * 
 * @param socket
 *            where to read ADS-B messages from.
 */
private void read(final Socket socket)
{
    LOGGER.info(getName() + " connected to " + host + ":" + port);
    DataInputStream in = null;
    try
    {
        in = new DataInputStream(socket.getInputStream());

        while (true)
        {
            byte[] rawBuffer = new byte[MESSAGE_BUFFER_SIZE];
            int bytesRead = in.read(rawBuffer);
            if (bytesRead == -1)
            {
                LOGGER.warn("End of stream reached.");
                break;
            }

            /*
            * The Mode-S Beast receiver's AVR formatted output for every message begins with 0x1A.
            */
            if (rawBuffer[0] == MODE_S_BEAST_PREFIX_NUM)
            {

                /*
                 * AdsbDecoder will expect a hexadecimal String representation of the ADS-B message
                 * without the prefix and suffix.
                 * 
                 * First, we will convert the raw bytes into a hexadecimal String. 
                 * 
                 * Then, we will remove the Mode-S Beast metadata from the AVR format.
                 * 
                 * For example: 
                 * "1A33000000000000008DA44E325915B6B6A2FACB45988A" will look like "8DA44E325915B6B6A2FACB45988A"
                 * 
                 * Finally, we enqueue the ADS-B hex message.  
                 */

                // 1A33000000000000008DA44E325915B6B6A2FACB45988A
                String modeS = new BigInteger(rawBuffer).toString(BASE_16).toUpperCase();

                // Remove Mode-S Beast info
                final int modesBeastPrefixLength = 18;
                String adsbMessage = modeS.substring(modesBeastPrefixLength, modeS.length());

                LOGGER.info("Message read from receiver/antenna: [" + adsbMessage + "]");

                rawAdsbMessages.offer(adsbMessage);
                ++totalEnqueued;
            }

        }

    }
    catch (

    IOException ioe)
    {
        LOGGER.error("Problem encountered reading from Socket. " + ioe.getMessage());
    }
    finally
    {
        if (Objects.nonNull(in))
        {

            try
            {
                in.close();
            }
            catch (IOException ex)
            {
                LOGGER.error("Problem encountered closing the Socket reader. " + ex.getMessage());
            }

        }
    }

}

Я ожидаю, что значение bytesRead не будет равно -1, и ему придется заново устанавливать соединение, поскольку все это в одном тесте. У меня очень ограниченные знания в области программирования сокетов, так что, возможно, это нереальное ожидание. Если это так, пожалуйста, скажите мне, почему. Может быть, положить в буфер читателя / писателя. ?? Любые предложения будут фантастическими.

...