Socket-Server: Request parsen/verarbeiten
-
Hallo!
Ich bin gerade dabei einen Socketserver, den ich zuvor in PHP (nicht lachen ;-)) hgeschreiben hatte, in C zu implementieren. Dieser Kommuniziert mit Clients über TCP über ein eigenes Protokoll, welches von der Syntax her HTTP ähnelt.
Ein typischer Request sieht so aus:
PROTOCOL/1.0 METHODE\n Field: Value\n Field: Value\n \n
Jeder Request hat 1,2 oder 3 Felder. Ich bin jedenfalls schonmal so weit, dass ich die erste Zeile per Tokenizer parsen kann, und entsprechend der Methode unterschiedlich antworten kann.
Mal ein konkretes Beispiel
PROTOCOL/1.0 AUTH\n Username: Andreas\n Password: secret\n \n
Der Server soll jetzt in einer DB nachgucken, ob die Zugangsdaten stimmen, und entsprechend antworten. Das heißt, ich muss irgendwie dahin kommen, dass ich diese Daten einer Methode übergeben kann:
db_check_auth(username, password);
Ich kann wie gesagt bereits verzweigen, zu dem Code, der zur Methode "AUTH" gehört:
while(1) { // main accept() loop sin_size = sizeof(struct sockaddr_in); if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { perror("accept"); continue; } printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr)); if (!fork()) { // this is the child process int numbytes; char buf[MAXDATASIZE]; char res_buf[MAXDATASIZE]; char *protocol; char *version; char *command; close(sockfd); // child doesn't need the listener if ((numbytes=recv(new_fd, buf, MAXDATASIZE-1, 0)) == -1) { perror("recv"); exit(1); } buf[numbytes] = '\0'; protocol = strtok(buf, "/"); version = strtok(NULL, " "); command = strtok(NULL, "\r\n"); if(strcmp (command, "AUTH") == 0) { printf("auth\n"); // hier ist das Problem ;-) strncpy(res_buf, "201 Yes\n", MAXDATASIZE); } else if(strcmp (command, "ADDUSER") == 0) { //[...] } res_buf[MAXDATASIZE] = '\0'; printf("response: %s\n",res_buf); if (send(new_fd, res_buf, strlen(res_buf), 0) == -1) perror("send"); close(new_fd);
Jetzt habe ich mehrere Probleme. Was wenn ich einen String vergleichen will, aber case-in-sensitive? Gibt es vielleicht eine Funktion die den String kpl. in kleine Buchstaben umwandelt - oder gibt es eine effizientere Möglichkeit?
Das größere Problem ist aber, wie ich jetzt am besten die Werte auslese. Ja, ich könnte hier wieder mit Tokenizer arbeiten, das heißt sowas:
strtok(buf, ": "); char *user = strtok(buf, "\n"); strtok(buf, ": "); char *pass = strtok(buf, "\n");
(nur so ganz grob ;-))
Ich bin aber der Meinung, dass man noch prüfen sollte, ob die Feldnamen auch entsprechend stimmen, aber wie mache ich das am besten? Ich hatte schon überlegt mit Konstanten zu arbeiten, das heißt eine Konstante(Zahlenwert) für jede Methode, und ebenso für jedes einzelne Feld. Und dann am Ende mit sowas zu arbeiten:
#define FIELD_USRNAME 1
#define FIELD_PASSWORD 2#define METHODE_AUTH 1
#define METHODE_ADDUSER 2field_name = get_field(fieldname, METHODE_AUTH); // gibt z.B. 1 für FIELD_USRNAME zurück
//fields[field_name] = tokenizer_value....
...und diese dann der oben genannten check-Funktion zu übergeben.
Aber da kann ich mir einfach nicht vorstellen dass das nicht vielleicht einen Tick eleganter geht
Hat da jemand von Euch ne Idee? Will das auch möglicht effizient machen
Viele Grüße
Andreas