2009-06-12 11 views
3

J'ai une application client qui devrait envoyer des messages de notification à une application serveur facultative. Le client ne doit pas être influencé par le fait que l'application du serveur existe ou non. Il devrait essayer de se connecter à l'application du serveur et envoyer le message de notification et en cas d'erreurs, il devrait simplement ignorer silencieusement toutes les erreurs et continuer à travailler.Messages unidirectionnels robustes avec Indy

J'utilise Indy pour la communication TCP, mais toutes les tentatives pour éviter l'apparition de messages d'erreur (c'est-à-dire lorsque l'application du serveur se ferme lors de la connexion au client) ont échoué.

Existe-t-il un moyen de rendre ce système vraiment robuste?

code actuel ressemble à ceci:

if (not Client.Connected) then 
    begin 
    Client.Host := ServerName; 
    Client.Port := ServerPort; 
    Client.ConnectTimeout := ConnectTimeout; 
    try 
    Client.Connect; 
    except 
    Exit; 
    end; 
    end 
try 
    Client.IOHandler.WriteLn ('NOTIFYCHANGE "' + Param + '"'); 
    Client.IOHandler.WriteBufferFlush; 
except 
    try 
    Client.Disconnect; 
    except 
    { ignore errors while disconnecting } 
    end; 
    try 
    Client.Connect; 
    except 
    { ignore errors while connecting } 
    end; 
end; 

Répondre

3

-vous vraiment obtenir des messages d'erreur de votre programme? Il est courant que lors du débogage que le débogueur détecte des exceptions et interrompt votre programme, et certaines personnes confondent le message du débogueur pour un message de leur propre programme. Es-tu sûr que ce n'est pas le cas ici? I've written about this situation before. Voici le résumé des façons de l'éviter:

  • Utilisez « points d'arrêt avancées » pour désactiver le comportement exception-interception du débogueur pour une région de code.
  • Configurez le débogueur pour ignorer certaines classes d'exceptions. (Cela est particulièrement commun à faire avec Indy, car il a tendance à jeter beaucoup d'exceptions.)
  • Définissez le débogueur pour ne jamais interrompre le programme sur les exceptions.
  • Désactiver complètement le débogage intégré.

Si le message est vraiment en provenance de votre programme et non le débogueur, puis retourner en arrière et utilisation le débogueur pour savoir où le message vient. Lorsque le message apparaît, mettez le programme en pause et regardez la fenêtre de la pile d'appels pour trouver la zone du code qui affiche le message, car elle n'apparaît clairement pas dans le code que vous avez montré. Le code que vous avez montré supprime complètement (ne gère pas) toutes les exceptions, même celles qui ne sont pas liées à Indy, telles que EAccessViolation et EOutOfMemory.

+0

Salut Rob, merci pour la réponse. Le message apparaît lorsque l'application n'est pas exécutée dans le débogueur. Je l'ai réparé en me connectant et en me déconnectant à chaque notification (ça n'arrive pas trop souvent). Il semble être assez robuste maintenant. – jpfollenius

0

Si possible, envisagez d'utiliser UDP. C'est "sans connexion", donc l'expéditeur enverra simplement le message et l'application réceptrice le recevra s'il écoute le port. Cependant, l'expéditeur ne reçoit aucune confirmation de la livraison à moins que le serveur n'envoie une sorte d'accusé de réception.

+0

Je veux utiliser un protocole de communication existinc et je veux donc rester avec TCP. Merci quand même. – jpfollenius

+0

Indy avait UDP depuis toujours. Ou voulez-vous dire par "protocole de communication existant" que vous vouliez intégrer à ce que votre application fait déjà? –

0

La réponse de Harriv est OK, vous décrivez le comportement d'une connexion UDP. J'utilise dans une situation similaire.

2

Pour une simple tâche de communication TCP, j'ai utilisé le paquet Synapse, ce n'est pas aussi gonflé qu'Indy et je me sens "plus propre" à utiliser.

De mon code récent:

procedure SendMessage(m: string); 
var 
    sock : TTCPBlockSocket; 
    response : string; 
begin 
    Sock := TTCPBlockSocket.Create; 
    try 
    Sock.SetTimeout(200); 
    Sock.Connect(PrinterServerAddr, IntToStr(PrinterServerPort)); 

    Sock.SendString(m); 
    response := Sock.RecvString(1000); 
    finally 
    Sock.Free; 
    end; 
end; 

.. 
try 
    SendMessage(NewMessage); 
except 
//..handle exception.. 
end; 

Wrap que l'intérieur TThread si vous voulez éviter de bloquer votre thread courant.

0

Vous ne dites pas si vous utilisez Indy 9 ou 10. J'utilise 9, moi-même, donc le ci-dessous suppose cela.

Pourquoi pas seulement?:

procedure Send(Target: String; Port: Integer; S: String); 
var 
    C: TIdTcpClient; 
begin 
    C := TIdTcpClient.Create(nil); 
    try 
    try 
     C.Host := Target; 
     C.Port := Port; 
     C.Connect; 
     try 
     C.Write(S); 
     finally 
     C.Disconnect; 
     end; 
    except 
     // Ignore Indy exceptions 
     on EIdException do; 
    end; 
    finally 
    C.Free; 
    end; 
end; 

Il est assez facile de transformer cela en une procédure qui utilise une TIdTcpClient préexistante.

Questions connexes