У меня есть интеграционный тест, который отправляет 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, и ему придется заново устанавливать соединение, поскольку все это в одном тесте. У меня очень ограниченные знания в области программирования сокетов, так что, возможно, это нереальное ожидание. Если это так, пожалуйста, скажите мне, почему. Может быть, положить в буфер читателя / писателя. ?? Любые предложения будут фантастическими.