recv nur bis \n



  • Hallo zusammen,

    ich habe folgendes Problem und zwar nutze ich folgenden Ausschnitt um Daten von einem Socket zu empfangen:

    char ausgabe[1000];
    	int x = 0;
    
    	while(1)
    	{
    		x = recv((SOCKET)sock, ausgabe, 1000, 0);
    
    		if(x > 0)
    		{
    			ausgabe[x] = 0;
    			CheckForEvent(ausgabe);
    		}
    		Sleep(10);
    	}
    

    Nun habe ich das Problem, dass mir der Server nicht schön Line für Line sendet sondern eine Masse an Nachrichten welche in keinsterweise getrennt sind sondern nur durch \n. So kann es zustande kommen, dass die Nachrichten nur halb ankommen und solche Sachen. Nun ist die Frage wie bekomme ich es am besten hin, dass die Variable ausgabe jeweils nur bis "\n" gefüllt wird? Muss ich da Zeichen für Zeichen einlesen und solange die Zeichen anhängen bis ich auf ein "\n" stoße oder gibt es da eine andere Möglichkeit?

    MfG
    snpr



  • Was spricht dagegen, in den empfangenen Daten nach dem Newline zu suchen und sich dann die entsprechenden Teile herauszuschneiden?



  • Im moment ist es wohl der Ansatz wie ich das am besten anstelle. Also das aufteilen in verschiedene substrings. Anderes Problem ist, dass es ja vorkommen kann das ein Satz in der Hälfte unterbrochen ist. Dieser sollte aber wieder als ein Satz erkannt werden. Irgendwie habe ich grade ein Brett vor dem Kopf wie man das am besten anstellen soll.



  • Wenn du feststellst, daß die erwartete Eingabe nicht komplett ist, schreibst du dir den Teil vom "hier geht die Zeile los"-Marker bis zum Ende des empfangenen Puffers in eine Hilfsvariable. Danach holst du dir per recv() den nächsten Block und holst dir daraus den Rest der Zeile.



  • okay klar ist natürlich 'ne nette Lösung und definitv ne super idee 🙂 dankeschön. Jetzt bleibt nurnoch die Frage womit ich letztlich den String am besten zerstückel. Problem ist in meiner Überlegung im moment, dass ich ja nicht beim \n aufhören darf. Also stehe gerade wirklich auf dem Schlauch. Hast du da noch eine Idee?



  • Ich würde std::find() verwenden, um die NewLines zu finden, und dann die Bereiche dazwischen gleich in einen String reinpacken. Den Puffer und (ganz wichtig) die Position, bis wohin du ihn schon ausgewertet hast, würde ich als statische Variable* aufbewahren und bei der nächsten Anforderung weiter auswerten.

    * alternativ packst du das ganze in eine Klasse mit dem Puffer als Member.



  • Wahrscheinlich war das jetzt viel zu überhastet und zu wenig durchdacht aber ich bekommen eine komplet leere Ausgabe. 😞 Vermutlich sollte ich mich dafür schämen was ich da gebaut habe aber naja. Dass eine Satz auf 2 Nachrichten aufgeteil ist, ist hier mal schön rausgelassen.

    void ausgeben(char *ausgabe)
    {
    
    	std::string	buffer(ausgabe);
    	std::string line[20];
    	unsigned int n_line = 0;
    	size_t pos,lastpos;
    	lastpos = 0;
    	while(buffer.find("\n",lastpos+1) != std::string::npos)
    	{
    		pos = buffer.find("\n",lastpos+1);
    		line[n_line] = buffer.substr(lastpos+1,(pos-lastpos));
    		std::cout << line[n_line] << std::endl;
    		n_line++;
    	}
    }
    


  • Kommt denn in der Eingabe überhaupt ein NewLine vor? Wenn nicht, wird die Schleife komplett übersprungen.

    Ansonsten hast du vergessen, in der Schleife die lastpos anzupassen - mit einigen leichten Anpassungen läuft es so: http://ideone.com/4dB4T



  • Okay. Ich glaube es läuft schonmal halbwegs 😉

    Leider zickt das ganze noch ein wenig rum. Warum ist momentan zwar noch in den sternen aber naja. Und zwar kommen scheinbar nicht alle nachrichten durch. Könnte natürlich daran liegen, dass ich bisher nicht berücksichtigt hab, dass die Nachricht in der nächsten Ladung weitergehen könnte. Ich müsste dann mir quasi merken, dass es nicht abgeschlossen wurde und dann quasi den Rest des einen Strings + dem des neuens bis zum NewLine oder?



  • Ja, das Endstück solltest du dir auch noch merken und dann mit dem Anfang der nächsten Eingabe zusammenfassen.

    (PS: Nur ein kleiner Hinweis: Ich würde statt des festen Arrays lieber einen vector<string> verwenden - ich weiß zwar nicht wie lang die einzelnen Zeilen sind, aber bei 1000 Byte recv-Puffer könnte es passieren, daß du die 20 Einträge überschreitest)



  • snpr schrieb:

    void ausgeben(char *ausgabe)
    {
    
    	std::string	buffer(ausgabe);
    	std::string line[20];
    	unsigned int n_line = 0;
    	size_t pos,lastpos;
    	lastpos = 0;
    	while(buffer.find("\n",lastpos+1) != std::string::npos)
    	{
    		pos = buffer.find("\n",lastpos+1);
    		line[n_line] = buffer.substr(lastpos+1,(pos-lastpos));
    		std::cout << line[n_line] << std::endl;
    		n_line++;
    	}
    }
    

    Mhm, dies Codestück sieht so aus, als wolltest Du einfach die empfangenen Daten Zeile für Zeile in einen Stream schreiben ... dafür würde aber doch:

    void ausgeben(char *ausgabe)
    {
       std::cout << ausgabe;
    }
    

    völlig ausreichen 😕
    Edit: Der Puffer 'ausgabe' muss natürlich nullterminiert werden, nachdem er mit recv gefüllt wurde.


Log in to reply