Forum: Mikrocontroller und Digitale Elektronik ESP32 esp-idf tcp client empängt Daten Packet nicht immer vollständig


von Florian K. (florian_k89)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich versuche einen Snapcast Client mit meinem ESP32-A1S Audio Dev Kit zu
bauen. Und stoße dabei auf ein Problem bei dem ich nicht mehr weiter 
komme.
Der Snapcast Server zerteilt den Audio Daten Strom vom Audioplayer in 
20ms Stücke und sendet diese per tcp an den Client.
Das sind 3840 Bytes bei 48KHz Sample Frequenz und 16Bit Auflösung.
4Bytes für Rechts Links * 48000/50 = 3840Bytes (1 Sekunde / 20ms = 50).
Mein Problem ist das so ca. jedes 10te Datenpacket nicht vollständig von 
meinem
Client empfangen wird. Bzw. recv() nicht 3840 als gelesene Bytes zurück 
gibt.
Ich dachte immer das TCP/IP eine Empfangsbestätigung hat und damit 
gewährleistet
das Datenpackete vollständig ankommen ?


meine Socket Read Funktion
1
static int _snapcast_stream_socket_receive(const char *tag, const int sock, char * data, size_t max_len){
2
    int len = recv(sock, data, max_len, 0);
3
   // ESP_LOGI(tag, "[sock=%d]: MAX_LEN: %d", sock, max_len);
4
    if (len < 0) {
5
        if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
6
            return 0;   // Not an error
7
        }
8
        if (errno == ENOTCONN) {
9
            ESP_LOGW(tag, "[sock=%d]: Connection closed", sock);
10
            return -2;  // Socket has been disconnected
11
        }
12
        log_socket_error(tag, sock, errno, "Error occurred during receiving");
13
        return -1;
14
    }
15
16
    return len;
17
}

ich habe die komplette c Datei mit Header im Anhang.
Ich Nutze zur zeit pcm Audio, da ich dort immer eine konstante Anzahl 
von Bytes gesendet bekomme und somit einfacher zu debugen ist. Später 
will ich auf flac oder opus als Decoder umsteigen.

von J. S. (jojos)


Lesenswert?

Bei non blocking receive brauchst du eine Schleife die recv solange 
aufruft bis alle Bytes angekommen sind.

von Xanthippos (xanthippos)


Lesenswert?

Kommen die Daten später im nächsten Paket an?

Ethernet arbeitet mit Paketen bis zu 1497 Bytes (oder so ähnlich). TCP 
garantiert nur, dass die Bytes in der richtigen Reihenfolge ankommen, 
nicht aber dass dein Programm ein gesendetes Paket in einem recv() 
erhält.

von Sebastian W. (wangnick)


Lesenswert?

J. S. schrieb:
> Bei non blocking receive brauchst du eine Schleife die recv solange
> aufruft bis alle Bytes angekommen sind.

Ich meine, solch eine Schleife braucht man immer, nicht nur bei 
non-blocking receive: "The receive calls normally return any data 
available, up to the requested amount, rather than waiting for receipt 
of the full amount requested."

LG, Sebastian

von Florian K. (florian_k89)


Lesenswert?

Vielen Dank,

Der Tipp über eine while Schleife recv solange aufzurufen bis alle Daten 
angekommen sind, hat mein Problem gelöst.

von Wastl (hartundweichware)


Lesenswert?

Florian K. schrieb:
> Ich dachte immer das TCP/IP eine Empfangsbestätigung hat und damit
> gewährleistet
> das Datenpackete vollständig ankommen ?

Bei einem Audio Stream braucht man TCP eigentlich nicht. Es geht
ja nicht um absolut fehlerfreie bzw. vollständige Datenübertragung.

Versuche mal dein Glück mit UDP, dort bekommst du die Datenmenge
als Paket übertragen die du dir wünschst, bis zur maximal
möglichen (MTU).

von Xanthippos (xanthippos)


Lesenswert?

> Ich Nutze zur zeit pcm Audio, ... und somit einfacher zu debugen ist.

Stimmt nicht :-)

Hättest du von Anfang an ein komprimiertes Format genommen, müsstet du 
in einer Schleife Bytes holen, bis du ein dekodierbares Paket zusammen 
hast.

Und das Problem wäre erst gar nicht entstanden.

von Stefan F. (Gast)


Lesenswert?

Florian K. schrieb:
> Ich dachte immer das TCP/IP eine Empfangsbestätigung hat und damit
> gewährleistet das Datenpackete vollständig ankommen ?

TCP ist ein Streaming Protokoll, nicht Paket-Orieniert. Es ist nur 
sicher gestellt, dass keine Bytes verloren gehen. Aber sie können den 
Empfänger in  beliebiger Stückelung erreichen.

Wenn du Pakete mit fester Größe brauchst, musst du UDP nehmen. Das 
garantiert allerdings keine Lückenlose Übertragung, es wiederholt im 
Fehlerfall nicht automatisch.

von Harald K. (kirnbichler)


Lesenswert?

Wastl schrieb:
> Versuche mal dein Glück mit UDP

Das verwendete Protokoll hier heißt Snapcast, und das verwendet TCP. 
Hier UDP vorzuschlagen ist also wenig hilfreich.

https://github.com/badaix/snapcast

Wenn man sich sein eigenes Protokoll entwickelt, weil man beide Enden 
der Übertragung in der Hand hat, dann kann UDP einem einiges an 
Nervkram abnehmen.

Beitrag #7384061 wurde vom Autor gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.