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?
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.
connectionSocket.setKeepAlive(true);
juste après la ligne Socket connectionSocket = serverSocket.accept();
.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++) {