Autor Beitrag
braincom654
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 32



BeitragVerfasst: Fr 30.11.12 16:57 
Hey Community,

ich programmiere gerade mit TCP über Netzwerk, dabei hatte ich eigentlich noch nie dieses Problem:
Manchmal schickt der Client zum Server einfach nur Müll, also etwas was ich möchte jedoch abgetrennt oder etwas fehlt, das natürlich der Server dann nicht mehr versteht >.<
Der Client schickt eigentlich durchgehend wenn er Online ist eine Meldung via TCP zum Server. Ich dachte es könnte daran liegen dass der Client 2 mal zugleich Sendet und dadurch der Müll zustande kommt. Dann habe ich ein bool eingebaut, dass er nur noch immer eine Meldung schickt, doch das brachte auch nichts... Hier der Code:

Client Seite:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
wait = true;
foreach (string item in getDirectory(msg.Substring(1, msg.Length - 1)))
{
    sendMsgToServer(item);
}
sendMsgToServer("4");
Thread.Sleep(1000);
wait = false;

-----
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
private void sendMsgToServer(string msg)
{
    byte[] buffer = Encoding.Default.GetBytes(msg);
    nsServer.Write(buffer, 0, buffer.Length);
    //nsServer.Flush();
}

----
Die Methode, welches bei Online status, sendet dass Client online ist:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
while (online())
{
    if (!wait)
    {
        byte[] buffer = Encoding.Default.GetBytes("1:IPOnline:" + strSource);
        nsServer.Write(buffer, 0, buffer.Length);
        //nsServer.Flush();
        Console.WriteLine("Online on " + DateTime.Now.ToShortTimeString());
    }
    else
    {
        Console.WriteLine("Send dirs " + DateTime.Now.ToShortDateString());
    }
}

Server Seite:
ausblenden C#-Quelltext
1:
2:
3:
4:
byte[] bufferRec = new byte[4096];
int rec = nsCC.Read(bufferRec, 0, bufferRec.Length);
Array.Resize(ref bufferRec, rec);
string msgRec = Encoding.Default.GetString(bufferRec);


Moderiert von user profile iconTh69: Codeformatierung überarbeitet.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 30.11.12 17:59 
Hallo,

bedenke, daß die Nachrichten nicht unbedingt in einem Rutsch geschickt werden, sondern in kleineren Paketen. Du mußt also in einer Schleife die Daten auslesen.
Sofern du unterschiedliche Daten schicken willst, solltest du dir ein Protokoll überlegen, z.B. am Anfang immer die Größe als int übergeben und diese dann als erstes auf der Gegenseite auswerten, bevor du dann die restlichen Daten (in einer Schleife) entgegennimmst.
braincom654 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 32



BeitragVerfasst: Fr 30.11.12 18:07 
Danke für die Antwort.
Normalerweise ging das bei meinen anderen Projekten schon immer "in einem Rutsch". Doch beim debugging stell ich fest dass sie korrekt geschickt werden vom Client, jedoch der Server unterschiedlich aufnimmt.
Ein Beispiel: Client schickt "Hallo ich bin XY" in bytes und server bekommt es wandelt um in string und es kommt raus "Hallo" gleich darauf bekommt er nochn paket mit "bin XY".
Wäre ja auch noch okay wenn die Pakete gesplitet wären, aber es IST EIN Problem wenn Daten fehlen.
Zu dein Vorschlag mit Protokoll, damit habe ich mich leider nie wirklich befasst. Ich schicke einfach immer gewisse Nummern am Anfang der Pakete, welche die gegenseite weiß was zu tun ist mit dem Paket,

edit:
Manchmal beim debugging musste ich sogar feststellen dass der Server Daten bekommt zu einem string zB. nur "H" das nächste mal "a". Das kann einfach nicht sein, wenn der Client "Hallo" schickt. Ich meine wirklich nur 5 stellen sollten schon in einem Rutsch gehen..
jochenc
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Do 03.01.13 17:30 
Hi, mir ist diese Problematik auch bekannt, dass es anders ankommt als weggeschickt da es der Server anders aufnimmt und das macht auch einen komischen Eindruck. Bin da grad am Tüffteln, hab aber noch keine effektive Lösung gefunden.
braincom654 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 32



BeitragVerfasst: Mo 10.06.13 17:28 
Habe das Projekt damals aufgegeben, weil ich so nicht weiter arbeiten konnte. Nun habe ich es wider gefunden und möchte daran arbeiten, jedoch ist dasselbe Problem!
Nun habe ich herausgefunden dass der Server nach einem bestimmten Code nur noch 8 Bytes jeweils empfängt. Client schickt es immer richtig ab zB. mit 24 Bytes usw. jedoch empfängt der Server immer das falsche.
Wäre sehr dankbar wenn jemand bei diesem Problem weiterhelfen könnte oder damit schon Erfahrung gemacht hat.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 10.06.13 17:57 
Hallo braincom654,

ich kann eigentlich nur wiederholen, was ich schon in meinem ersten Beitrag geschrieben habe:
Th69 hat folgendes geschrieben:
Du mußt also in einer Schleife die Daten auslesen.

Wo ist das Problem dabei?
braincom654 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 32



BeitragVerfasst: Di 11.06.13 08:19 
Ich habe schon eine Schleife, wollte nur nicht zuviel Code reinpacken:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
while (true)
            {
                int rec = nsCC.Read(bufferRec, 0, bufferRec.Length);
                Array.Resize(ref bufferRec, rec);
                string msgRec = Encoding.Default.GetString(bufferRec);

                if (!string.IsNullOrWhiteSpace(msgRec))
                {
                     switch (msgRec.Substring(01))
                    {
                        case "1":
                           ....
                            break;
                       
                        case "2":
                           ....
                            break;
                        case"3":
                            ...
                            break;
                        case "4":
          break;
         .
        .
        .
                    }
                }
            }


Habe ich dich vielleicht falsche verstanden?
Wie schon gesagt das Problem ist am Anfang läuft es immer normal, es empfängt via TCP alles in einem Rutsch, das der Client schickt. Doch danach nicht mehr, danach empfängt er immer nur noch 8 Bytes egal, was der Client abschickt.

edit:
Am Anfang schickt IP-Online, das funktioniert immer BIS die foreach ausgeführt wird, nachdem dieser Code aufgerufen wurde empfängt er nur noch wie gesagt jeweils 8 Bytes. Ich finde das Problem nicht...
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Di 11.06.13 09:37 
Ja, du musst dir eben ein einfaches Protokoll ausdenken. In deiner Schleife hast in meinen Augen schon zwei komische Sachen drin: 1. Du prüft nicht ob die Nachricht vollständig ist.

In den Beispielen werden oft die ankommenden Daten in eine Testbox geschrieben, das reicht auch aus um es schön anzugucken. Man sieht nur leider nicht, ob das alles auf einmal kommt, oder in 5 Durchgängen, die sehr schnell hintereinander sind.

Angenommen dein Paket hat eine maximale Länge von 256 Bytes, dann brauchst du einen passen Puffer. Der wird ständig aus dem Netzwerk gefüllt, und nach jedem Empfang ürüfst du, ob sich jetzt ein vollständiges Paket im Puffer befindet. Ist das der Fall, entnimmst du es und verschiebst den Pufferinhalt entsprechend. (Oder direkt einen Ringpuffer benutzen)

So in etwa:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
// Felder
buffer = byte[256];
ibuffer = 0;

// Methode
while (true)
{
  int received = nsCC.Read(bufferRec, ibuffer, bufferRec.Length);
  ibuffer += received;
  
  if (IsValidPacket())
  {
    ProcessPacket();
    Array.Copy(Buffer, ibuffer, Buffer, 0, bufferRec.Length - ibuffer);
    ibuffer = 0;
  }
}

Darin sind auch noch zwei Haken:
1. Könntest du die ReadAsync() Methode benutzen.
2. Darf da jetzt nie ein Byte hineinrutschen weil dann die Paketgrenze nicht mehr stimmt. Ich weiß nicht wie sicher TCP in dieser Hinsicht ist, wenn das Probleme macht einfach Byteweise lesen und jedes mal prüfen ob das Paket gültig ist.

Variable Paketlängen sind übrigens kein Problem: Du schickst einfach einen Hader mit einer festen Länge und schreibst darin, wie viele Byte da noch hinterher kommen.
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Di 11.06.13 20:16 
Es geht noch einfacher.

Der Sender schickt seine Nachricht und anschließend ein definiertes Zeichen als Abschluß. In deinem Fall, wo eigentlich nur Text hin- und hergeht, würde sich ein ASCII-03 (ETX) anbieten.

Ergo wartet der Empfänger nun einfach darauf, das Text kommt und sobald er das Zeichen ETX empfängt weiß er, das die Nachricht beendet ist - völlig unerheblich, ob noch was im Empfangspuffer ist oder nicht. Die ausgelesene Nachricht kann nun verarbeitet werden und wenn das passiert ist, kümmert sich deine Empfangsroutine um den Rest - bis wieder ein ETX kommt.

Diese Vereinbarung, das Nachrichten mit definierten Zeichen beginnen / enden oder ein ganz spezifisches Format / stets gleiche Länge haben, nennt man Protokoll.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.