Sockets bitweise auslesen
-
Hallo zusammen!
Ich habe folgendes Problem: Ich habe einen ISDN-Server der an die angeschlossenen clients ständig Daten übermittelt und auch Befehle derselben annehmen kann.
Einige Befehle senden verschieden grosse Datenpakete aus, z.B. Telefonlisten die mehrere Kbytes gross sein können.
Mit ich den Server mit telnet "anhaue" funktioniert alles tadellos.
Aber ich hab keine grosse Ahnung wie ich jetzt die read oder recv Befehle einsetzen soll damit die Datenströme auch richtig eingelesen werden.
while ((numbytes=recv(sockfd, buf, 1, 0)) > 0) { cout << buf; }
Die obige Schleife z.B. funktioniert nicht da numbytes immer grösser als 0 ist. Wie kann ich feststellen ob noch was im Socket etwas vorhanden ist?
Vielen Dank im Voraus
-
Ach ja, mit telnet funktioniert alles.
-
recv ist normalerweise blokierend, und gibt erst dann was zurück wenn's was gelesen hat. du liest hier aber nur 1 byte und terminierst auch nicht mit null. das ganze is bisschen wacklig.
wenn du mehr kontrolle willst brauchste select (man select)
-
Original erstellt von Korbinian:
recv ist normalerweise blokierend, und gibt erst dann was zurück wenn's was gelesen hat. du liest hier aber nur 1 byte und terminierst auch nicht mit null. das ganze is bisschen wacklig.
wenn du mehr kontrolle willst brauchste select (man select)Vielen Dank.
Aber hat leider nichts gebracht, oder ich mache es falsch.
while (select(fdmax+1,&pollSocket,NULL,NULL,0)>0) { numbytes=recv(sockfd, buf, MAXDATASIZE, 0); input << buf[0]; }
funktioniert auch nicht da select > 0, habe auch schon poll ausprobiert.
-
dein ursprünglicher code funktioniert mit telnet sagst du. was machst du denn in der client anwendung die sendet?
und vergiss nicht den buffer mit null zu terminieren, sonst kannst probleme kriegen ( int ret = recv(socket, buf, 255, 0); buf[ret] = '\0'; )
empfehle ausserdem nicht, immer nur ein byte abzuholen, wie du das uhrsprünglich vorhattest. würde mir vielmehr n allgemeines protokoll für deine netzwerksitzgun überlegen.
-
ich versteh zwar nicht genau was du meinst, aber vielleicht hilft dir folgendes weiter:
sowohl select als auch recv blockt, wenn keine daten im kernel receive buffer sind. dies kannst du abschalten mit:
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
in diesem falle liefert recv, sofern keine daten verfuegbar sind, -1 zurueck und errno wird auf EWOULDBLOCK gesetzt.
alternativ kannst du auch recv(a, b, c, MSG_DONTWAIT) aufrufen. willst du nur sehen, ob daten vorhanden sind, ohne sie einzulesen, kannst du recv(a, b, c, MSG_DONTWAIT | MSG_PEEK) benutzen.
-
Original erstellt von Korbinian:
dein ursprünglicher code funktioniert mit telnet sagst du. was machst du denn in der client anwendung die sendet?
und vergiss nicht den buffer mit null zu terminieren, sonst kannst probleme kriegen ( int ret = recv(socket, buf, 255, 0); buf[ret] = '\0'; )
empfehle ausserdem nicht, immer nur ein byte abzuholen, wie du das uhrsprünglich vorhattest. würde mir vielmehr n allgemeines protokoll für deine netzwerksitzgun überlegen.Der client sollte sein Socket auf Anrufe und andere Events, wie z.B. Kosten-Infos bei ausgehenden Anrufe, überwachen.
Der Server sendet auf jedem aktiven Socket dauernd Informationen wenn jemand z.B. irgendwohin anruft. Aber man kann dennoch Befehlen an den Server senden, wie z.B. list 12.7.2002 00:00:00, dieser Befehl liest eine Logdatei rückwarts bis zum angegebenen Datum und Uhrzeit und sendet diese dann zum Client.
Das ganze wurde über poll (für /dev/isdnctrl) und select (für die Sockets) realisiert.
Also der Client sollte sein Socket überwachen und darüberhinaus kann er Befehle senden. z.B. damit man die Anrufe in Abwesenheit anschauen kann kann der client den Befehl "list <datum beim letzen ausloggen> <Zeit beim letzten ausloggen>" zum Server senden und der liest die Logdatei und liefert die angeforderten Daten zurück.
Der client wird mal ein KDE programm. Nur bis jetzt hab ich es nicht geschafft die Daten einzulesen.
-
Original erstellt von <egal>:
ich versteh zwar nicht genau was du meinst, aber vielleicht hilft dir folgendes weiter:
sowohl select als auch recv blockt, wenn keine daten im kernel receive buffer sind. dies kannst du abschalten mit:
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
in diesem falle liefert recv, sofern keine daten verfuegbar sind, -1 zurueck und errno wird auf EWOULDBLOCK gesetzt.
alternativ kannst du auch recv(a, b, c, MSG_DONTWAIT) aufrufen. willst du nur sehen, ob daten vorhanden sind, ohne sie einzulesen, kannst du recv(a, b, c, MSG_DONTWAIT | MSG_PEEK) benutzen.Hallo, vielen Dank.
Leider funzt es nich so. Wenn ich z.B
int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); write(sockfd,"list 0 0",9); // sendet den Befehl "list alle" an den Server, dies wird noch ausgefürht. while (numbytes=recv(sockfd, buf, 1, 0)>0) { input << buf[0]; } cout << input.str();
wird der Server einfach beendet. Sollte ja nicht passieren wenn man in einem Client Blödsinn macht, das der Server beendet wird.
-
also ich steig bei der sache leider noch nich so richtig durch. am für mich verwirrendsden ist, dass du beim client (is doch der client code oder?) immer nur ein byte liest. damit kommst du glaub ich nie auf n vernünftiges auswerten (ausser lesen :)) der empfangenen informationen. ich würd das n bisschen anders angehen: (mal ne session aufgezeichnet)
Client: list 0 0
Server: OK
S: LIST BEGIN
C: OK
S: listeneintrag 1
C: OK
S: listeneintrag 2
C: OK
S: listeneintrag 3
C: OK
S: LIST END
C: OK 3 items receivedwas in einer zeile bei C oder S steht, wird jeweils auf einmal gesendet / empfangen:
// Beim Server: int ret = send (socket, "listeneintrag 1", 15, 0); // Beim Client: char buf[255]; int ret = recv (socket, buf, 255, 0); // das blockierd, bis was empfangen worden ist buf[ret] = '\0'; // null terminieren, sonst hast du mist drin cout << buf << endl; // wenn du es ausgeben willst. da wird dann "listeneintrag 1" stehen // etc...
auf diese weise kannst du auch schön mit dem empfangenen umgehen:
string text = buf; if (text == "BEGIN LIST") recv_list(): // ... int recv_list() { // mal n bisschen pseudo... vector <string> liste; for (;;) { string recv_text; // empfangen und in recv_text speichern, siehe oben if (recv_text == "LIST END") break; liste.push_back(recv_text); } ... }
damit hast du dann die ganze liste in nem vector und kannst schön weitermachen. ich hoffe das dir das n bisschen geholfen hat! (und nicht an der sache vorbeigeredet hat :D)