Problem mit recv und endlos schleife
-
ich habs : MSG_DONTWAIT
-
MSG_DONTWAIT ließt dir aber nur das aus, was gerade schon drin steht. Ich weiß nicht, ob du das möchtest.
Noch 2 Anmerkungen:
int i=1; // weger \0 while((r=recv(sock, buffer, buffersize,0))>=0){ i=(i+strlen(buffer)); // +1; nicht nötig, da du nur ein \0 brauchst und nicht für jeden Empfang ein \0 data=(char*)realloc(data,i); // \0 ist auch ne schöne Sache... würde strcat auch freuen, wenn es eines hätte buffer[r]='\0'; strcat(data,buffer); }
-
habe das soweit geändert nur wenn ich MSG_DONTWAIT raus nehme bleibt er in der while schleife hängen.
const char *Schnack::getHttp(int sock){ char *data=NULL; char buffer[buffersize]; int r=0; int i=1; while((r=recv(sock, buffer, buffersize,0))>=0){ i=(i+strlen(buffer)); data=(char*)realloc(data,i); buffer[r]='\0'; strcat(data,buffer); } return data; }
schnack.cpp
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> #include "schnack.h" #define buffersize 255 void Schnack::sendHttp(int sock,const char *data){ int n; char *tmp=(char*)malloc(strlen(data)+255); sprintf(tmp,"HTTP/1.1 200 OK\n Server: schack(Unix)\nContent-Length:" "%d\nConnection: close\nContent-Type: text/html\n\n\n%s",(int)strlen(data)+1,data); n = write(sock,tmp,strlen(tmp)); if (n < 0){ perror("ERROR writing to socket"); } free(tmp); } const char *Schnack::Reqparse(const char* input){ } const char *Schnack::getHttp(int sock){ char *data=NULL; char buffer[buffersize]; int r=0; int i=1; while((r=recv(sock, buffer, buffersize,0))>=0){ i=(i+strlen(buffer)); data=(char*)realloc(data,i); buffer[r]='\0'; strcat(data,buffer); } return data; } void *Schnack::Controller(void *httpsocket){ intptr_t n=*(intptr_t*)httpsocket; printf("%s\n",((Schnack *)n)->getHttp(n)); ((Schnack *)n)->sendHttp(n,"Moin wat geiht"); pthread_exit(0); } int main(int argc, char *argv[]){ if (argc < 2){ fprintf(stderr,"ERROR, no port provided\n"); exit(1); } Schnack(atoi(argv[1])); return 0; } Schnack::Schnack(int port){ int sockfd; socklen_t clilen; struct sockaddr_in serv_addr, cli_addr; pthread_t cthread; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0){ perror("ERROR opening socket"); exit(1); } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(port); if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){ perror("ERROR on binding"); exit(1); } listen(sockfd,5); clilen = sizeof(cli_addr); while(1){ int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0){ perror("ERROR on accept"); exit(1); } pthread_create(&cthread, NULL, Schnack::Controller,(void*)&newsockfd); pthread_join(cthread, NULL); // controller(newsockfd+); close(newsockfd); } close(sockfd); }
schnack.h
class Schnack { private: public: Schnack(int port); void sendHttp(int sock,const char *data); const char *getHttp(int sock); static void *Controller(void *httpsocket); const char *Reqparse(const char* input); };
-
Laut rfc glaube soll der Server erst wirklich die Verbindung schließen, wenn ein "connection: close" im HTTP Request Header auftaucht(natürlich erst nachdem entsprechendem Response).
Apache und verschiedene andere Server(Google) scheinen die Verbindung auch nach einigen Sekunden bis Minuten zu schließen.
Du kannst zum Abbruch, wenn auf einer Verbindung schienbar nichts mehr ankommt, auch select() mit einem Timeout nutzen. Also nach 3 Min etc. ohne Daten am Eingang, aber aufgebauter TCP-Verbindung einfach closen.
Ansonsten würde ich auch wirklich erst schließen, wenn der Client das durch "connection: close" signalisiert. Und auf das "connection: close" musst du ja in deiner Schleife prüfen. Ansonsten musst du nach HTTP/1.1 davon ausgehen, dass der Browser diesen TCP-Socket noch nutzt um weiteren Inhalt zu erfragen.
EDIT: Achja, ein HTTP Request Header ist ja nach erstem "\r\n\r\n" + ContentLength-Angabe(wenn nicht vorhanden 0) beendet. Dann ist der HTTP-Request komplett(die ganze Verbindung kann aber noch nciht geclosed werden, wenn es sich nicht um HTTP/1.0 handelt).
-
joar denn schicke ich den thread in backgroud und zur sicherheit mit timeout
-
Joar, ist ein wenig müsig sich da einzulesen.
Wenn du den Client nicht auch selbst programmierst, dann füge lieber noch eine "Date: " Angabe(beim Response) ein. Ich glaube, da hat mein Firefox bei meiner Serverantwort ein bissel gemeckert.
-
nimmt langsam form an
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> #include "schnack.h" #define buffersize 256 char *Schnack::Data=NULL; void Schnack::sendHttp(int sock,const char *data){ int n; char *tmp=(char*)malloc(strlen(data)+255); sprintf(tmp,"HTTP/1.1 200 OK\n Server: schack(Unix)\nContent-Length:" "%d\nConnection: close\nContent-Type: text/html\n\n\n%s",(int)strlen(data)+1,data); n = write(sock,tmp,strlen(tmp)); if (n < 0){ perror("ERROR writing to socket"); } free(tmp); } void *Schnack::Httpd(void *httpsocket){ intptr_t n=*(intptr_t*)httpsocket; char buffer[buffersize]; int r=0; int i=1; while((r=recv(n, buffer, buffersize-1,0))>=0){ i=(i+strlen(buffer)); Data=(char*)realloc(Data,i); buffer[r]='\0'; strcat(Data,buffer); } return 0; } void *Schnack::Parser(void *httpsocket){ intptr_t n=*(intptr_t*)httpsocket; while(Data!=0){ ((Schnack *)n)->sendHttp(n,Data); } pthread_exit(0); } Schnack::Schnack(int port){ int sockfd; socklen_t clilen; struct sockaddr_in serv_addr, cli_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0){ perror("ERROR opening socket"); exit(1); } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(port); if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){ perror("ERROR on binding"); exit(1); } listen(sockfd,5); clilen = sizeof(cli_addr); while(1){ Data=0; pthread_t cthread ,dthread; int newsockfd; newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0){ perror("ERROR on accept"); exit(1); } pthread_create(&dthread, NULL, Schnack::Httpd,(void*)&newsockfd); pthread_create(&cthread, NULL, Schnack::Parser,(void*)&newsockfd); pthread_join(cthread, NULL); close(newsockfd); } close(sockfd); } int main(int argc, char *argv[]){ if (argc < 2){ fprintf(stderr,"ERROR, no port provided\n"); exit(1); } Schnack(atoi(argv[1])); return 0; }
-
Tuxist schrieb:
nimmt langsam form an
So hässlichen Code hab ich schon lange nicht mehr gesehen.
-
eine sehr präzise aussage muss ich schon sagen.
-
Ich persönlich bin noch recht gut mit c unterwegs. Mit deinem Code komm ich zurecht, obwohl ich C++ nur halbherzig programmiere.
Ich glaube, dass ist in etwa seine Kritik. Du benutzt ne Mischung von C und C++... C deßhalb, weil ich dachte das in C++ nicht mehr gemalloced wird.
Oder hab ich jetzt noch was derb fatales übersehen?
-
man kann auch new und delete nehmen aber um realloc kommt nicht rum zu in verbindung mit char*, zum dem habe ich mir angewöhnt die Vorteile beider sprachen zu nutzen. Klassen und Templates von C++ und den Rest von C. Spart rechenzeit und ist trotzdem sehr übersichtlich und über new und delete lässt sich drüber streiten.
-
Ich programmiere fast ausschließlich in C++ und finde den Code auch grausam. Wenn man C++ nutzt, dann sollte man auch die entsprechenden Mittel einsetzen, die es einem bietet.
Das fängt schon bei diesem hässlichen Makro an. Makros sollte man übrigens immer in Großbuchstaben schreiben, damit man nicht wohlmöglich irgendwann mal ein int buffersize; in int 256; ersetzt bekommt...
Und durch weitere Abstraktionen, etc. hätte man sicher auch noch das ein odere andere close in einem Destruktor packen können. Netter Nebeneffekt: Die Verbindung wird definitiv geschlossen.
Tuxist schrieb:
man kann auch new und delete nehmen aber um realloc kommt nicht rum zu in verbindung mit char*, zum dem habe ich mir angewöhnt die Vorteile beider sprachen zu nutzen. Klassen und Templates von C++ und den Rest von C. Spart rechenzeit und ist trotzdem sehr übersichtlich und über new und delete lässt sich drüber streiten.
Man kann auch std::string nehmen und spart sich beides.
Im übrigen glaube ich nicht, dass dein Programm so performancekritisch ist, dass du überhaupt einen Unterschied merken würdest. Tatsächlich würdest du sogar noch schneller mit deinem Programm voran kommen und hättest dann Zeit dort zu optimieren wo es tatsächlich eng wird.
-
Tuxist schrieb:
Spart rechenzeit
Wohl kaum. Selbst wenn, du würdest es nicht mal merken.
Tuxist schrieb:
und ist trotzdem sehr übersichtlich
Dein Code ist das hässlichste Stück Scheiße, das ich seit Wochen gesehen habe. Sogar die schlechtesten Anfänger schreiben schöneren Code, wenn sie nicht gerade ein J.W. Buch haben.
Tuxist schrieb:
und über new und delete lässt sich drüber streiten.
So viel Mist in einem Satz, Gratz!
-
sdfsdfsdf:
mit dem Marco haste recht habe ich übersehen und close kann man auch Deconstructor
paltzieren . Aber std::string mit C funktionen ist ein Interessantes Konstrukt. Ahja der kernel und die glibc sind in c geschrieben314159265358979:
New ist vergleichbar mit Malloc.
delete ist vergleichbar mit free.Schau mal GCC nach dar wird die das auffallen es nur kürzer weil der Rückgabe type entsprechend zurückgegeben wird
-
Tuxist schrieb:
Deconstructor
Es heißt Destruktor.
Tuxist schrieb:
Ahja der kernel und die glibc sind in c geschrieben
Zusammenhang zum Thread = 0.
Tuxist schrieb:
New ist vergleichbar mit Malloc.
delete ist vergleichbar mit free.Nein. new ruft Konstruktoren auf, delete Destruktoren.
Tuxist schrieb:
Schau mal GCC nach
Ich brauche nichts nachsehen, ich weiß es besser als du.
Tuxist schrieb:
dar wird die das auffallen es nur kürzer weil der Rückgabe type entsprechend zurückgegeben wird
Siehe oben. Du hast new und delete nicht verstanden.
P.S.: Und schreib bitte Deutsch, es fällt mir unglaublich schwer, deine Posts zu entziffern.
-
Der Kernel operiert auch auf Hardware Ebene und muss zudem mit stark begrenzten Ressourcen auskommen. Das heißt nicht, dass es nicht auch in C++ möglich wäre, aber es macht einfach nicht viel Sinn.
Und das die C Bibliothek in C geschrieben ist. Tja, muss wohl was damit zu tun haben, dass es eine C und keine C++ Bibliothek ist (die C++ Bibliothek ist in C++ geschrieben).
Sind also alles keine Argumente dagegen. Ganz im Gegenteil. Viele Fehler im Kernel, etc. hätte man mit C++ verhindern können - man hatte aber einfach keine Wahl. Du hast aber die Wahl!
-
Nein. new ruft Konstruktoren auf, delete Destruktoren.
ja wenn man ein klasse verwendet:
Bezogen auf eine Klasse stimmt das, aber es ist auch new int oder new char[255] möglich und in diesem Fall wir es nur gewrapped.
Natürlich ist auch eine
Class class = new Class(); möglich hier wird die klasse mit einem Zeiger Initialisiert. Den man natürlich auch wieder löschen kann.
new reserviert Speicher und Delete gibt ihn wieder frei. Eigentlich ganz einfach.
-
Mit std::string kannst du auf diesen ganzen quatsch verzichten. Die C Funktionen brauchst du dann gar nicht mehr. Mit Ausnahme der Socket-Funktionen, aber dafür hat std::string die Funktion c_str und alles ist gut.
In C++ könnte man dann noch Smart Pointer verwenden, und braucht sich um das delete nicht mal mehr kümmern. Das Programm ist dadurch um einiges robuster und sicherer! Und das ist nicht zuletzt gerade bei einem Webserver wichtig, der ja möglichst immer erreichbar sein soll.
Aber mach mal wie du denkst. Irgendwann wirst du an einem Punkt sein, wo du merkst, das etwas schief läuft. Viel Spaß beim Suchen wünsch ich dir schon mal. Vielleicht denkst du dann ja nochmal an uns.
-
c_str gibt einen const char * zurück. Ist bißchen blöd wenn man reinschreiben muss :-p.
-
Tuxist schrieb:
c_str gibt einen const char * zurück. Ist bißchen blöd wenn man reinschreiben muss :-p.
std::vector<char> und dann ggf. in std::string. Glaub mir, du kannst dir das Leben so viel einfacher machen.