Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Lettura NetworkStream in .NET ritorna dati disordinati

Linguaggi e sistemi

Moderatori: Foto UtentePaolino, Foto Utentefairyvilje

0
voti

[1] Lettura NetworkStream in .NET ritorna dati disordinati

Messaggioda Foto Utenteboiler » 15 gen 2021, 13:57

Ciao a tutti

Ho un problema curioso.
Sto usando la classe NetworkStream per comunicare con un dispositivo remoto.
Si tratta di piccoli pacchetti di dati e sul sitema di test che sto usando ottengo nel 99% dei casi il pacchetto corretto, che è questo:
Codice: Seleziona tutto
0a 01 06 ff 1f 21 f8 3f 00 c8 6c


Di tanto in tanto però, ricevo pacchetti come questi:
Codice: Seleziona tutto
0A 00 00 00 00 00 00 00 00 00 00
01 06 FF 1F 21 F8 3F 00 00 00 00


Questi pacchetti sono contigui, si vede bene che nel primo È arrivato solo il primo byte, mentre parte del resto è finito nel pacchetto successivo. Gli ultimi 2 (o forse 3) bytes sono andati persi.

La funzione che si occupa della comunicazione è questa:
Codice: Seleziona tutto
        public static bool SendAndReceive(NetworkStream stream, byte[] txDatagram, ref byte[] rxDatagram)
        {
            rxDatagram = new byte[rxDatagram.Length];

            lock (streamLock)
            {
                // purge input buffer
                var buffer = new byte[1024];
                while (stream.DataAvailable)
                {
                    stream.Read(buffer, 0, buffer.Length);
                }
               
                // send tx datagram
                try
                {
                    stream.Write(txDatagram, 0, txDatagram.Length);
                }
                catch(Exception ee)
                {
                    Debug.WriteLine("Exception writing datagram: " + ee.Message);
                    return false;
                }
               
                System.Threading.Thread.Sleep(150);

                // get rx datagram
                try
                {
                    stream.Read(rxDatagram, 0, rxDatagram.Length);
                }
                catch (Exception ee)
                {
                    Debug.WriteLine("Exception reading datagram: " + ee.Message);
                    return false;
                }
               
            }

            return true;
        }


Come vedete non può essere un problema di read-timeout perché questo viene gestito diversamente (blocco catch) e non risulta in un pacchetto.
Inoltre prima di trasmettere la richiesta di lettura, svuoto il buffer dello stream da tutto quello che contiene. Non capisco quindi come possa ritrovarmi i resti di un pacchetto incompleto nel pacchetto successivo.

Al momento questa funzione viene chiamata da un solo punto, inoltre c'è un lock, quindi non credo che ci possa essere qualche accesso tra trasmissione della richiesta e ricezione della risposta.

Tra trasmissione e ricezione c'è una pausa di 150 ms per permettere al dispositivo remoto di rispondere.

Qualche idea?

Grazie e saluti, Boiler
Avatar utente
Foto Utenteboiler
26,4k 5 9 13
G.Master EY
G.Master EY
 
Messaggi: 5618
Iscritto il: 9 nov 2011, 12:27

1
voti

[2] Re: Lettura NetworkStream in .NET ritorna dati disordinati

Messaggioda Foto Utentenicsergio » 15 gen 2021, 15:26

Ciao, non sono per niente esperto, ma sembra che la funzione stream.Read() possa non ritornare in un colpo solo tutti i byte inviati, negli esempi che si trovano in rete di solito viene fatto un while.

Prova a vedere qui, l'esempio di risposta itera la lettura fino al raggiungimento dei bytes attesi depositandoli nell'array.

Sullo svuotamento del buffer ho paura che la verifica di stream.DataAvailable con un while non sia corretta, prova a vedere qui.
Avatar utente
Foto Utentenicsergio
4.701 3 9 13
Master
Master
 
Messaggi: 938
Iscritto il: 1 gen 2020, 16:42

0
voti

[3] Re: Lettura NetworkStream in .NET ritorna dati disordinati

Messaggioda Foto Utenteboiler » 15 gen 2021, 15:39

Hai ragione, nel frattempo mi sono accorto di questo comportamento e ho modificato il codice in modo che non avvenga:
Codice: Seleziona tutto
                // get rx datagram
                try
                {
                    int readPointer = 0;
                    while (readPointer < (rxDatagram.Length-1))
                    {
                        if (stream.DataAvailable)
                        {
                            readPointer += stream.Read(rxDatagram, readPointer, 1);
                        }                       
                    }
                }
                catch (Exception ee)
                {
                    Debug.WriteLine("Exception reading datagram: " + ee.Message);
                    return false;
                }


Il problema è sparito e così ho aggiunto un paio di altre funzioni che invocano questo codice.
E qui mi sono accorto di un altro problema. Il lock di C# è re-entrant. Vuol dire che visto che qui viene acquisito dallo stesso thread, non realizza la protezione che mi serve. Devo trovare una soluzione alternativa #-o

Boiler
Avatar utente
Foto Utenteboiler
26,4k 5 9 13
G.Master EY
G.Master EY
 
Messaggi: 5618
Iscritto il: 9 nov 2011, 12:27


Torna a PC e informatica

Chi c’è in linea

Visitano il forum: Nessuno e 9 ospiti