SerialPort.Leggere(…) non rispetto ReadTimeOut

Ha un bug nel codice legacy che comunica con un terminale di pagamento.

Appena prima di un nuovo pagamento viene avviato, il codice tenta di cancellare l’interno del buffer di lettura di SerialPort.

Mi ha rifilato il codice al minimo indispensabile. Utilizza la .NET SerialPort tipo. Un timeout di lettura di 50ms è impostato. Quindi, legge 512 byte e continua a farlo fino a quando non più di byte letti o fino a quando un TimeoutException è gettato.

Abbiamo aggiunto un sacco di registrazione, e ha mostrato che la chiamata per la prima Lettura(…) il metodo a volte prende 10 – 15 minuti, anche con un timeout di 50ms. Poi un TimeoutException è buttato e l’applicazione continua. Ma durante la Lettura(…) l’applicazione si blocca.

Questo non sempre accade, Windows 2000 macchine sembrano più inclini a questo errore per qualche motivo.

public class Terminal
{
    private SerialPort _serialPort = new SerialPort();

    public void ClearReadBuffer()
    {
        try
        {   
            _serialPort.ReadTimeout = 50;
            int length;
            do
            {
                var buffer = new byte[512];
                length = _serialPort.Read(buffer, 0, 512);
            } while (length > 0);
        }
        catch (TimeoutException) {}
    }
}

Ogni aiuto è apprezzato.

PS: la Maggior parte delle segnalazioni di errore sono provenienti da W2K macchine in cui il dispositivo è collegato a un EdgePort, che simula un mucchio di porte COM virtuali. Il suo driver crea un gruppo (8) locale porta COM.

Ma ci sono anche le segnalazioni da Windows 7. Possiamo anche riprodurre il problema, se vogliamo collegare direttamente il dispositivo al PC (non EdgePort). Tuttavia non così spesso e quando succede il ritardo è di 10 minuti, ma per 1 – 2 minuti.

Aggiornamento: Provato un sacco di cose per risolvere questo problema. Era difficile da riprodurre, ma si è verificato molto spesso in campo perché c’è distribuito su migliaia di Pc. Effettivamente sostituito il .NET 2.0 SerialPort tipo con un’altra versione open source. Ha funzionato senza problemi su un PC dove abbiamo potuto riprodurre come il 60 – 70% del tempo. Ma, ahimè, durante un test pilota in produzione i problemi che ancora oggi continuano a verificarsi.

Il codice per il terminale di pagamento è stato scritto un paio di anni prima e ho fatto il port di anonther applicazione. Durante la porto io ri-presi un po ‘ di codice, ma hanno mantenuto la funzionalità originale. Quando la comunicazione con il terminale il codice sarebbe:

  1. Sparare un altro thread dal pool
  2. Inviare il messaggio al dispositivo
  3. Leggere dalla seriale fino a quando una risposta ricevuto o un errore di timeout.

Nel frattempo il thread principale aveva un ciclo while che conteneva un Thread.Sonno(50) e un’Applicazione.DoEvents() chiamata (puah!). Ho riscritto tutto questo “ciclo di attesa” e si è avvalso di una WaitHandle (AutoResetEvent /ManualResetEvent). Ho aspettato fino a questa maniglia. Ha funzionato senza problemi, ma su alcuni Pc porta seriale di comunicazione potrebbe congelare per minuti fino a quando qualcosa ha innescato. Ri-abilitato l’Applicazione.DoEvents() modo di lavorare e i problemi sono spariti.

È ancora lì, purtroppo, un enigma per me perché è necessario qui e perché provoca gravi effetti collaterali. Le applicazioni supporta 5 altri tipi di periferiche di porta seriale. La comunicazione con questi dispositivi non hanno bisogno di qualcosa come questo.

Non so se hai visto questo articolo: social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/… . Ogni probabilità, hardware/specifiche del fornitore?
Avrei pensato che questo è il driver relativi più che altro. È il comportamento sicuramente legata al sistema operativo? O è solo che il tuo win2000 macchina può avere una dubbia UART + driver?
No, anche i rapporti da Windows 7 macchine. Quindi, probabilmente, non è legato al sistema operativo. Ma tutti gli usi lo stesso EdgePort hardware / driver.
Forse la classe SerialPort utilizza i messaggi di Windows (wndproc), e che pertanto ha bisogno DoEvents se è possibile bloccare il thread principale? In quel caso (o forse, in ogni caso) la soluzione corretta sarebbe quella di non bloccare il thread principale.

OriginaleL’autore Christophe Geers | 2012-07-05

One Reply
  1. 7

    forse l’aggiunta di un test sulla porta “byte da leggere’ può aiutare a evitare di mal codificati driver:

    length = (_serialPort.BytesToRead > 0) ? _serialPort.Read(buffer, 0, 512) : 0;

    meglio ancora, utilizzare

    _serialPort.DiscardInBuffer();

    invece!

    Mi sarei aspettato DiscardInBuffer per risolvere questo, essere buono per scoprire se lo fa.
    Riscritto il ClearBufferMethod. Prima cancellato il driver di Windows buffer (DiscardInBuffer), quindi SerialPort buffer interno (se non altro era presente). Questo non è più bloccato, poiché la maggior parte del tempo le Leggi(…) il metodo non è stato chiamato. Tuttavia SerialPort istanza ancora congelato per 5 – 10 minuti in una successiva Write(…). Roba strana, in realtà, di liquidazione sostituzione .NET (2.0) SerialPort tipo. Ora funziona bene.
    Geers ho lavorato con un problema che suona un po ‘ come questo. Vuoi dire che finalmente ri-scritto la .NET porta seriale tipo con la propria implementazione? Avete ulteriori approfondimenti per condividere su cosa esattamente è stato il problema o che le parti dovevano essere cambiate?
    Vedere l’aggiornamento, la mia domanda per ulteriori dettagli.

    OriginaleL’autore zeFrenchy

Lascia un commento