2017-08-17 1 views
0

J'écris un programme qui envoie et reçoit des messages à une autre application. Certains messages doivent être envoyés à certains intervalles. Par exemple, j'ai quatre messages qui sont envoyés, un devrait être envoyé toutes les 8 secondes, deux doivent être envoyés toutes les 0,5 secondes et un devrait être envoyé toutes les secondes.Événements ne se produisant pas à l'intervalle de temps correct C# timers

Les messages semblent bien envoyer, mais ils sont tous envoyés en même temps. J'ai utilisé un horodatage pour déterminer qu'ils semblent tous être envoyés toutes les 11 secondes. Voici le code que j'ai implimented:

Voici où les minuteries sont déclarés:

System.Timers.Timer statusTimer = new System.Timers.Timer(1000); 
    System.Timers.Timer heightTimer = new System.Timers.Timer(500); 
    System.Timers.Timer keepAliveTimer = new System.Timers.Timer(8000); 
    System.Timers.Timer longHeightTimer = new System.Timers.Timer(500); 

Et ici dans la fenêtre principale, ils sont mis en marche (ce qui est un projet WPF):

statusTimer.Start(); 
heightTimer.Start(); 
keepAliveTimer.Start(); 
longHeightTimer.Start(); 

    statusTimer.Elapsed += delegate { sendStatusMessage(); }; 
    heightTimer.Elapsed += delegate { sendHeightMessage(); }; 
    keepAliveTimer.Elapsed += delegate { sendKeepAliveMessage(); }; 
    longHeightTimer.Elapsed += delegate { sendLongWarpMessage(); }; 

Voici un exemple d'une méthode qui devrait être déclenchée quand le temps est écoulé (il n'y a pas grand intérêt à les montrer tous car ils sont tous fondamentalement les mêmes):

public void sendStatusMessage() 
    { 
     sendMessage(status_msg.TranslateToMessage()); 
     Dispatcher.Invoke(DispatcherPriority.Normal, (System.Action)delegate //change the priority so you can use UI 
     { 
      statusMsgLbl.Content = "Status Msg Sent: " + DateTime.Now.ToLongTimeString(); 
     }); 

    } 

Et enfin ce la méthode qui envoie le message, sous forme d'octets, à l'autre application à l'aide d'un flux réseau:

public void sendMessage(byte[] toSend) 
    { 
     try 
     { 
      lock (NSLock) 
      { 
       for (int i = 0; i < toSend.Length; i++) 
       { 
        nwStream.WriteByte(toSend[i]); 
        nwStream.Flush(); 
       } 
      } 
     } 
     catch { MessageBox.Show("Unable to send message"); } 
    } 
+2

En note, il semble extrêmement inefficace d'écrire et de vider chaque octet dans un flux, quand vous pouvez écrire tout le tableau d'octets avec un seul ['Write (toSend, 0, toSend.Length)'] (https: // msdn.microsoft.com/en-us/library/system.io.stream.write(v=vs.110).aspx) appel. Il peut également être judicieux d'utiliser la classe DispatcherTimer pour éviter d'appeler Dispatcher.Invoke. – Clemens

+0

@Clemens merci pour les conseils! –

Répondre

1

Vous pouvez essayer d'utiliser un DispatcherTimer avec un gestionnaire d'événements Tick async:

DispatcherTimer statusTimer = new DispatcherTimer 
{ 
    Interval = TimeSpan.FromSeconds(1.0) 
}; 

... 

statusTimer.Tick += async (s, e) => 
{ 
    var message = status_msg.TranslateToMessage()); 

    await nwStream.WriteAsync(message, 0, message.Length); 

    statusMsgLbl.Content = "Status Msg Sent: " + DateTime.Now.ToLongTimeString(); 
}; 

statusTimer.Start(); 
+0

cela a fonctionné parfaitement merci! Je n'ai jamais vu une minuterie impliquée de cette façon auparavant, pourriez-vous expliquer la partie aysnc (s, e) juste pour mieux comprendre? –

+1

Voir [Programmation asynchrone] (https://docs.microsoft.com/en-us/dotnet/csharp/async). – Clemens

+0

Merci! @Clemens –

0

La date est le même parce que sa date de l'exécution de code à Invoke, vous devez date de capture avant d'appeler:

public void sendStatusMessage() 
{ 
    sendMessage(status_msg.TranslateToMessage()); 
    var text = "Status Msg Sent: " + DateTime.Now.ToLongTimeString(); 
    Dispatcher.Invoke(() => statusMsgLbl.Content = text); 
+0

Est-ce que cela expliquerait 11 secondes au lieu de 0,5? – Clemens

+0

@Clemens, peut-être combiné 'TranslateToMessage' pour tous les messages prend autant. – Sinatr

+0

Salut @Sinatr il semble toujours envoyer toutes les 11 secondes. Lorsque j'ai essayé votre code pour la première fois, je n'ai pas ajouté accidentellement la ligne supérieure, donc aucun message n'a été envoyé et la minuterie s'affichait correctement, ce qui peut indiquer que l'erreur se situe quelque part dans la méthode d'envoi et non dans le minuteur. –