Forum: Mikrocontroller und Digitale Elektronik Probleme beim Empfang vom TCP Server


von ArduStemmi (Gast)


Lesenswert?

Guten Morgen,

derzeit arbeite ich an einer einfachen Datenübertragung zwischen PC und 
Mikrocontroller über WLAN. Ein ESP8266 Dev.Kit 1.0 dient in meiner 
Hardware als Communication Controller. Die Übertragung erfolgt auf der 
TCP/IP Ebene, der Communication Controller läuft als TCP Server, das 
Programm auf dem PC läuft als TCP Client.
Die Verbindung habe ich hinbekommen - alles fein. Allerdings ist mir 
nicht ganz klar, was ich da vom TCP Server empfange.
Ich habe, um die Kommunikation zu testen, dem TCP Server höflich 
mitgeteilt, er soll alle empfangenen Datenströme unverändert 
zurückschicken. und zwar über die serielle Kommunikation, als auch über 
WLAN. Das seht Ihr hier:
1
 WiFiClient client = server.available();
2
  String command ="";
3
  if (client) 
4
  {
5
    Serial.println("Client connected.");
6
    
7
    while (client.connected()) 
8
    {
9
      if (client.available()) 
10
      {
11
        command = client.readStringUntil('\r');
12
        Serial.println(command);
13
        client.println(command);
14
      }
15
    }
16
    Serial.println("Client disconnected.");
17
    client.stop();
18
  } /* if (client)*/
19
}
Im Terminalprogramm sieht man, das er das verstanden hat, auch über WLAN 
kommt die Nachricht zurück. Ich empfange die in meinem Programm auf dem 
PC über die Sub Routine Listen, die in einem eigenen Thread läuft und 
über While True immer und immer wieder die Ohren spitz um ja nichts zu 
verpassen! Auch das funktioniert, hier die Routine:
1
    Sub Listen()
2
3
        Dim completeMessage() As Byte
4
        Dim FirstRun As Boolean = True
5
        Dim MessageAvailable As Boolean = False
6
        Dim Message(myTcpClient.ReceiveBufferSize) As Byte
7
        Dim Params(1) As Object
8
9
        While True
10
            While myNetworkStream.DataAvailable
11
                'Do
12
                MessageAvailable = True
13
14
                myNetworkStream.Read(Message, 0, CInt(myTcpClient.ReceiveBufferSize))
15
                If FirstRun Then
16
                    completeMessage = Message
17
                    FirstRun = False
18
                Else
19
                    completeMessage.Concat(Message)
20
                End If
21
                'Loop While myNetworkStream.DataAvailable
22
            End While
23
24
            FirstRun = True
25
26
            If MessageAvailable Then
27
28
                MessageAvailable = False
29
30
                Params(0) = txtReceivedBytes
31
                Params(1) = completeMessage
32
                Me.Invoke(New WriteTextDelegate(AddressOf WriteText), Params)
33
34
            End If
35
36
37
        End While
38
    End Sub

Ganz kurz zum Programm: Die While true ... End While Schleife läuft 
ewig. In die While myNetworkStream.DataAvailable Schleife wird 
eingesprungen, sobald Daten im Networkstream verfügbar sind. Da ich 
sicherstellen muss, dass auch Daten abgerufen werden, die beim ersten 
mal nicht in der Puffer passten, erzeuge ich eine CompleteMessage, an 
die ich solange Daten anhänge, bis keine Daten mehr verfügbar sind.

Was mich wundert: Die While myNetworkStream.DataAvailable Schleife wird 
immer zweimal aufgerufen! Egal wie groß ich den Puffer wähle! Und noch 
komischer, der zweite Datenstrom begint immer mit Chr(13) und Chr(10), 
dem typischen Endezeichen einer Datenübertragung! Noch kurioser wird es 
nun: Die Message ist 256 Byte lang, weil mein Puffer derzeit auf 256 
Byte Länge eingestellt ist.
1
                myTcpClient.ReceiveBufferSize = 256
Wenn die Schleife 2 mal aufgerufen wird, müsste CompleteMessage danach 
512 Byte lang sein, aber nein, es ist wie mit der Lichtgeschwindigkeit, 
die Größe bleibt bei 256! Und, noch schlimmer, die Daten sind nicht mehr 
erkennbar!

Weiss jemand Rat?

von Jim M. (turboj)


Lesenswert?

Könnte auch Programmierfehler auf dem PC sein. Ich nutze zum Testen bei 
sowas immer Wireshark, lies Dich da mal ein. Mit dem Tool sieht man 
genau was auf dem Netzwerk passiert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

ArduStemmi schrieb:
> command = client.readStringUntil('\r');

Stell Dir vor, es wirt der String "Hello World\r\n" gesendet. Ja, am 
Ende einer ASCII-Übertragung steht am Ende in der Regel sowohl ein CR 
(\r oder 0x0C=13) als auch ein LF (\n oder 0x0A=10).

readStringUntil() liest also bis zum \r (Chr(10)). Was bleibt in der 
Input-Queue zurück? Richtig, der Rest, also zumindest das \n (Chr(10)). 
Das bekommst Du dann am Anfang des nächsten readStringUntil()-Aufrufs 
untergejubelt.

Es ist also schlecht, readStringUntil() mit Argument '\r', aufzurufen, 
weil dann immer das \n im Input stehenbleibt. Okay, Du könntest nun 
readStringUntil('\n') aufrufen, dann steht aber in command das \r drin 
und Du müsstest das noch "abstreifen".

Andere Möglichkeit: Du rufst readStringUntil() weiterhin mit '\r' auf 
und Du liest das nachfolgende '\n' mit einem zeichenweisen read, so dass 
es im Input verschwindet.

Weitere Möglichkeit: Du liest den Input-Strom zeichenweise statt 
zeilenweise und füllst selbst den Buffer. Ein \r wird ignoriert, das 
nachfolgende \n terminiert den Buffer.

ArduStemmi schrieb:
> der zweite Datenstrom begint immer mit Chr(13) und Chr(10),
> dem typischen Endezeichen einer Datenübertragung!

Sicher, dass da nicht nur ein \n (Chr(10)) am Anfang des "zweiten 
Datenstroms" steht?

von ArduStemmi (Gast)


Lesenswert?

Leider bin ich sicher! Es beginnt mit Chr(13) und Chr(10)! Inzwischen 
habe ich auf read until gänzlich verzichtet. Meine Nachricht ist 10 Byte 
lang, da ist das ganze kein Problem!

Des Weiteren habe ich beide Writeln durch Write ersetzt! (Wahnsinn: 
Diese Funktion kenne ich noch von Turbo Pascal 4.0 [oder noch eher?] vom 
Ende der 80er Jahre in der damals noch gerade DDR!) Damit sendet der 
keine Chr(13) und Chr(10) mehr. In PC verwalte ich das selbst!

Leider ist der empfangene Datenstrom noch immer nicht, was ich erwarte. 
Ich habe den Eindruck, dass der Datenempfangspuffer im PC nicht gelöscht 
wird. Ich erkläre das beispielhaft: Wenn ich einmal 10 Byte sende, 
kommen die 10 Byte sauber zurück. Sende ich jetzt 20 Byte kommen 20 Byte 
sauber zurück. Sende ich jetzt wieder 10 Byte, bekomme ich 20 Byte 
zurück, wobei die aktuelle Nachricht an der richtigen Stelle stehen. Nur 
die letzten 20 Byte gehen nicht weg! Die bleiben wo sie sind.

von ArduStemmi (Gast)


Lesenswert?

Toll, da wollte ich mal lustig sein, da heißt der Befehl println und 
nicht writeln. Println gab's aber im Pascal auch schon!

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.