2012-01-10 10 views
1

J'ai rencontré un problème de communication socket sur le système Linux, le processus de communication est comme ci-dessous: client envoie un message pour demander au serveur de faire une tâche de calcul, et Attendez le message de résultat du serveur une fois la tâche terminée. Mais le client raccroche pour attendre le message de résultat si la tâche coûte longtemps, par exemple environ 40 minutes, même si du côté serveur, le message de résultat a été écrit dans le socket pour répondre au client, mais il pourrait normalement recevoir le message de résultat si la tâche coûte peu de temps, comme une minute. En outre, ce problème se produit uniquement sur l'environnement du client, le processus de communication se comporte normalement dans notre environnement de test.ObjectInputStream.readObject() se bloque pendant le processus de communication socket

Je ai soupçonné la cause de ce problème est la valeur de délai d'attente par défaut de socket est différente entre environnement client et environnement de test, mais les valeurs suivantes sont identiques sur ces deux environnement, et client et serveur.

getSoTimeout:0 
getReceiveBufferSize:43690 
getSendBufferSize:8192 
getSoLinger:-1 
getTrafficClass:0 
getKeepAlive:false 
getTcpNoDelay:false 

les codes sur CLient sont comme:

Message msg = null; 
ObjectInputStream in = client.getClient().getInputStream(); 
//if no message readObject() will hang here 
while (true) { 
    try { 
    Object recObject = in.readObject(); 
    System.out.println("Client received msg."); 
    msg = (Message)recObject; 
    return msg; 
     }catch (Exception e) { 
    e.printStackTrace(); 
    return null; 
    } 
} 

les codes sur le serveur sont comme,

ObjectOutputStream socketOutStream = getSocketOutputStream(); 
try { 
    MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile); 
    socketOutStream.writeObject(msgJobComplete); 
    }catch(Exception e) { 
    e.printStackTrace(); 
    } 

afin de résoudre ce problème, j'ai ajouté la chasse et méthode reset , mais le problème existe toujours:

ObjectOutputStream socketOutStream = getSocketOutputStream(); 
try { 
    MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile); 
    socketOutStream.flush(); 
    logger.debug("AbstractJob#reply to the socket"); 
    socketOutStream.writeObject(msgJobComplete); 
    socketOutStream.reset(); 
    socketOutStream.flush(); 
    logger.debug("AbstractJob#after Flush Reply"); 
}catch(Exception e) { 
    e.printStackTrace(); 
      logger.error("Exception when sending MessageJobComplete."+e.getMessage()); 
} 

donc quelqu'un sait ce que les prochaines étapes je devrais faire pour résoudre ce problème. Je suppose que la cause est le paramètre d'environnement, mais je ne sais pas ce que les facteurs d'environnement affecteraient la communication socket?

Et le socket utilisant le protocole Tcp/Ip pour communiquer, le problème est lié à la tâche de longue durée, alors quelles valeurs de tcp affecteraient le délai d'attente de la communication socket? Après mon analyse sur les journaux, j'ai trouvé après que le message est écrit sur le socket, il n'y avait pas d'exceptions sont levées/interceptées. Mais toujours après 15 minutes, il existe des exceptions dans l'extrait de code objectInputStream.readObject() de Server Side qui est utilisé pour accepter la demande du client. Cependant, la valeur de socket.getSoTimeout est 0, il est donc très étrange que l'exception a expiré.

{2012-01-09 17:44:13,908} ERROR java.net.SocketException: Connection timed out 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:146) 
    at sun.security.ssl.InputRecord.readFully(InputRecord.java:312) 
    at sun.security.ssl.InputRecord.read(InputRecord.java:350) 
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:809) 
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:766) 
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:94) 
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:69) 
    at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2265) 
    at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2558) 
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2568) 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1314) 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368) 

alors pourquoi les exceptions de délai de connexion sont-elles levées?

+0

Si le client ne reçoit pas, il est probable que le serveur n'envoie pas. Je confirmerais que vous voyez un message de journal pour l'objet envoyé que le client ne reçoit pas. –

+0

merci, mais le journal a montré que l'objet a été envoyé, et aucune exception n'a été détectée, juste le client se bloque, savez-vous comment vérifier? {2012-01-09 19: 28: 16,416} DEBUG AbstractJob # réponse à la socket {2012-01-09 19: 28: 16,422} DEBUG AbstractJob # après Flush Répondre –

+0

Le printStackTrace n'apparaîtra pas dans les journaux, ils sont écrit sur la console. Si vous n'écrivez pas la console dans un fichier, je m'assurerais que les exceptions sont écrites dans le journal. –

Répondre

2

Ce problème est résolu. en utilisant le tcpdump pour capturer les flux de messages. J'ai trouvé que tandis qu'au niveau de l'application, ObjectOutputStream.writeObject() méthode a été invoquée, dans le niveau de tcp, plusieurs fois [TCP ReTransmission] ont été trouvés.Donc, j'ai conclu que la connexion est probablement morte, bien que l'utilisation de la commande netstat -an l'état de connexion tcp était toujours ESTABLISHED.

J'ai donc écrit une application de test pour envoyer périodiquement des messages de test en tant que messages de cœur battant du serveur. Alors ce problème a disparu.

1

Les read() méthodes de java.io.InputStream sont le blocage des appels., Ce qui signifie qu'ils attendent « pour toujours » si on les appelle quand il n'y a pas de données dans le flux à lire.

Il s'agit d'un comportement complètement attendu et conforme au contrat publié dans javadoc si le serveur ne répond pas.

Si vous souhaitez une lecture non bloquante, utilisez les classes java.nio.*.

+0

remercie votre réponse, mais en réalité le serveur a écrit l'objet à socket pour répondre au client. donc je ne sais pas pourquoi le client ne peut pas recevoir. –

+0

Si le client ne reçoit pas, il est probable que le serveur n'envoie pas. Je confirmerais que vous voyez un message de journal pour l'objet envoyé que le client ne reçoit pas. –

Questions connexes