web-dev-qa-db-fra.com

Erreur lors de la lecture du flux d'entrée: le logiciel a provoqué une interruption de la connexion 'dans le serveur Java

J'essaye fondamentalement d'héberger un serveur sur un appareil Android. Les périphériques clients se connectent au serveur via TCP et envoient des demandes. Le serveur exécute l'action demandée par le client, puis réécrit les données dans le socket. Le serveur ne met pas fin à la connexion et les demandes doivent être lues en permanence sur le socket et y répondre.

Remarque: les 4 premiers octets de chaque message de requête contiennent la longueur du message/de la requête.

La fonction parseXmlInputAndExecuteCmd exécute diverses opérations asynchrones en fonction du contenu de la chaîne XML d'entrée. Cela entraîne éventuellement une modification de la valeur booléenne de la variable 'allowResponse' en true et une certaine réponse est générée qui est stockée dans la variable de type String appelée 'réponse'. Une fois que la valeur 'allowResponse' booléenne devient vraie, le thread reprend l'exécution et écrit la réponse dans le OutputStream du socket.

Certaines de ces opérations asynchrones incluent la connexion et la déconnexion du VPN de l'entreprise. Cela pourrait-il être une cause de l'erreur?

Certaines variables de niveau de classe utilisées sont:

private volatile boolean allowResponse = false;
private String response;

Code serveur:

    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;
}

Le serveur est démarré en utilisant les lignes de code suivantes:

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

Je reçois la trace de pile d'erreur suivante:

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)

Je reçois une erreur appelée: Java.net.SocketException: Software caused connection abort

Je ne sais pas trop où je me trompe dans l'utilisation du flux d'entrée/de sortie. J'obtiens l'erreur à la ligne suivante (numéro de ligne 192 comme indiqué dans le stacktrace):

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

Dans des questions similaires sur StackOverflow, j'ai vu des personnes dire qu'il pourrait s'agir d'un problème de configuration du pare-feu d'entreprise. Est-ce exact ? Si oui, comment puis-je le réparer?

Cela pourrait-il être un problème avec le code client (auquel je n’ai pas accès) qui n’est pas écrit correctement?

14
Umang Mathur

Je ne peux pas reproduire votre problème localement, et quelque chose me dit que vos conditions de déclenchement sont assez spécifiques, mais voici quelques conseils pour vous aider à diagnostiquer et à résoudre votre problème.

  1. Votre code: Si c'est votre code, le code du serveur Web existant devrait fonctionner. Essayez le code dans le code de cet Nice article moyen minimal sur la façon de créer votre propre serveur Web Java .
  2. Le pare-feu: S'il s'agit du pare-feu, contactez votre administrateur/administrateur réseau, etc. Si vous ne le connaissez pas, parlez-en à une personne aussi importante que possible dans votre entreprise et avec qui vous vous sentez à l'aise. demander et ils devraient pouvoir vous diriger vers la bonne personne.
  3. Socket SO_KEEPALIVE Option: J'ai trouvé une question intéressante sur le superutilisateur sur le sujet } et lu que ce problème peut être causé par le fait que vous n'avez pas SO_KEEPALIVE ensemble de drapeaux sur votre socket. La réponse parle de PuTTY, mais j’ai pensé que cela valait la peine d’essayer sur votre socket Java. C'est certainement un fruit à portée de main à essayer. En tant que tel, essayez d'ajouter via l'appelant connectionSocket.setKeepAlive(true); juste après la ligne Socket connectionSocket = serverSocket.accept();.
1
entpnerd

J'ai essayé d'exécuter votre code dans mon ordinateur (pas dans Android) et cela fonctionne bien avec un simple appel du navigateur à «localhost: 8080».

Je pense que vous pouvez faire la même chose dans votre appareil pour savoir s'il s'agit d'un problème client.

J'ai édité ces deux lignes pour éviter une longue attente: 

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