Ошибка при чтении входного потока: программное обеспечение вызвало прерывание соединения на java-сервере - программирование
Подтвердить что ты не робот

Ошибка при чтении входного потока: программное обеспечение вызвало прерывание соединения на java-сервере

Я в основном пытаюсь разместить сервер на устройстве Android. Клиентские устройства подключаются к серверу через TCP и отправляют запросы. Сервер выполняет действие, запрошенное клиентом, а затем записывает данные обратно в сокет. Соединение не прерывается сервером, и запросы должны непрерывно считываться через сокет и отвечать.

Примечание. Первые 4 байта каждого сообщения запроса содержат длину фактического сообщения/запроса.

Функция parseXmlInputAndExecuteCmd выполняет различные асинхронные операции в зависимости от содержимого входной XML-строки. Это в конечном итоге приводит к изменению логического значения переменной allowResponse в true и генерируется определенный ответ, который сохраняется в переменной типа String, называемой "response". Когда логический "allowResponse" становится истинным, поток возобновляет выполнение и записывает ответ обратно в сокет OutputStream

Некоторые из этих асинхронных операций включают подключение и отключение от корпоративного VPN. Это может быть причиной ошибки?

Используются некоторые переменные уровня класса:

private volatile boolean allowResponse = false;
private String response;

Код сервера:

    private void startServer() {
    try {
        ServerSocket serverSocket = new ServerSocket(8080);
        while (true) {
            Socket connectionSocket = serverSocket.accept();
            BufferedInputStream bufInpStream = new BufferedInputStream(connectionSocket.getInputStream());
            BufferedOutputStream bufOutStream = new BufferedOutputStream(connectionSocket.getOutputStream());
            ByteArrayOutputStream contentLengthBaos = new ByteArrayOutputStream();
            int c;
            int count = 0;
            while ((c = bufInpStream.read()) != -1) {
                contentLengthBaos.write(c);
                count++;
                if (count == 4) {
                    int contLen = getMessageLength(contentLengthBaos);
                    String content = getMessageContent(bufInpStream, contLen);
                    parseXmlInputAndExecuteCmd(content);
                    count = 0;
                    while (!allowResponse) {
                        Thread.sleep(1000);
                    }
                    allowResponse = false;
                    byte[] responseDataBytes = response.getBytes();
                    int outputContLen = responseDataBytes.length;
                    byte[] contLengthBytes = ByteBuffer.allocate(4).putInt(outputContLen).array();
                    ByteArrayOutputStream o = new ByteArrayOutputStream();
                    o.write(contLengthBytes);
                    o.write(responseDataBytes);
                    byte finalOutPutBytes[] = o.toByteArray();
                    bufOutStream.write(finalOutPutBytes);
                    bufOutStream.flush();
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

@NonNull
private String getMessageContent(BufferedInputStream inFromClient, int contLen) throws IOException {
    ByteArrayOutputStream contentBaos = new ByteArrayOutputStream();
    byte[] contentBytes = new byte[contLen];
    for (int i = 0; i < contLen; i++) {
        contentBaos.write(inFromClient.read());
        ByteArrayInputStream bais = new ByteArrayInputStream(contentBaos.toByteArray());
        bais.read(contentBytes);
    }
    String content = new String(contentBytes);
    Log.d(TAG, "Content : " + content);
    return content;
}

private int getMessageLength(ByteArrayOutputStream contentLengthBaos) {
    byte[] firstFourBytesArr = contentLengthBaos.toByteArray();
    int contLen = new BigInteger(firstFourBytesArr).intValue();
    contentLengthBaos = new ByteArrayOutputStream();
    Log.d(TAG, "Content length: " + contLen);
    return contLen;
}

Сервер запускается с использованием следующих строк кода:

Thread serverThread = new Thread(new Runnable() {
        @Override
        public void run() {
            startServer();
        }
    });
    serverThread.start();

Я получаю следующую трассировку стека ошибок:

W/System.err: java.net.SocketException: Software caused connection abort
                  at java.net.SocketInputStream.socketRead0(Native Method)
                  at java.net.SocketInputStream.socketRead(SocketInputStream.java:114)
W/System.err:     at java.net.SocketInputStream.read(SocketInputStream.java:170)
W/System.err:     at java.net.SocketInputStream.read(SocketInputStream.java:139)
W/System.err:     at java.io.BufferedInputStream.fill(BufferedInputStream.java:248)
W/System.err:     at java.io.BufferedInputStream.read(BufferedInputStream.java:267)
                  at com.example.umathur.myapplication.MainActivity.startServer(MainActivity.java:192)
                  at com.example.umathur.myapplication.MainActivity.access$000(MainActivity.java:61)
                  at com.example.umathur.myapplication.MainActivity$1.run(MainActivity.java:139)
                  at java.lang.Thread.run(Thread.java:764)

Я получаю сообщение об ошибке: java.net.SocketException: Software caused connection abort

Я не уверен, где я ошибаюсь в использовании потока ввода/вывода. Im получает ошибку в следующей строке (номер строки 192, как указано в stacktrace):

while ((c = inputStream.read()) != -1)

В некоторых похожих вопросах о StackOverflow я видел людей, заявляющих, что это может быть проблема конфигурации корпоративного брандмауэра? Это верно? Если да, то как это сделать?

Это может быть проблема с кодом клиента (к которому у меня нет доступа), который не написан правильно?

4b9b3361

Ответ 1

Я не могу воспроизвести вашу проблему локально, и что-то говорит мне, что ваши условия запуска довольно специфичны, но вот несколько вещей, которые помогут вам диагностировать и исправить вашу проблему.

  1. Ваш код: если это ваш код, то существующий код веб-сервера должен работать. Попробуйте код в коде из этой хорошей минимальной средней статьи о том, как создать свой собственный веб-сервер Java.
  2. Брандмауэр: если это брандмауэр, обратитесь к своему администратору/команде в сети и т.д. Если вы не знаете, кто это, просто поговорите с высокопоставленным лицом в вашей компании, которое вам удобно задавать, и они должны иметь возможность направить вы к правильному человеку.
  3. Socket SO_KEEPALIVE Опция: я нашел интересный вопрос SuperUser по этому вопросу и прочитал, что эта проблема может быть вызвана тем, что в вашем соке не установлен флаг SO_KEEPALIVE. Ответ говорит о PuTTY, но я подумал, что стоит попробовать ваш Java-сокет. Это, безусловно, низкий висящий плод, чтобы попробовать. По существу, попробуйте добавить через call connectionSocket.setKeepAlive(true); сразу после Socket connectionSocket = serverSocket.accept(); линия.

Ответ 2

Я пытался запустить ваш код на своем компьютере (не на Android), и он работает хорошо с простым вызовом из браузера в "localhost: 8080".

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

Я отредактировал эти две строки, чтобы избежать долгого ожидания:

byte[] contentBytes = new byte[10];
    for (int i = 0; i < 10; i++) {