2

我尝试在 C 中创建一个简单的 HTTP 服务器,但我需要获取浏览器请求以查看平台、cookie、...为此,我正在尝试使用 fgets 函数读取 sock 文件,但它返回给我一个无限环形。

看我的代码。

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdbool.h>

#define SERVER          "TestServer4"               //Servername
#define PROTOCOL        "HTTP/1.1"                  //Protocol used
#define RFC1123FMT      "%a, %d %b %Y %H:%M:%S GMT" //Date format of returns
#define PORT            7777                        //Socket port
#define NUM_THREADS     5                           //Threads clusters numbers

int sock; //Stores the socket

void send_headers(FILE *f, int status, char *title, char *extra, char *mime, int length, time_t date) {
    time_t now;
    char timebuf[128];

    fprintf(f, "%s %d %s\r\n", PROTOCOL, status, title);
    fprintf(f, "Server: %s\r\n", SERVER);
    now = time(NULL);
    strftime(timebuf, sizeof (timebuf), RFC1123FMT, gmtime(&now));
    fprintf(f, "Date: %s\r\n", timebuf);
    if (extra) fprintf(f, "%s\r\n", extra);
    if (mime) fprintf(f, "Content-Type: %s\r\n", mime);
    if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length);
    if (date != -1) {
        strftime(timebuf, sizeof (timebuf), RFC1123FMT, gmtime(&date));
        fprintf(f, "Last-Modified: %s\r\n", timebuf);
    }
    fprintf(f, "Connection: close\r\n");
    fprintf(f, "\r\n");
}

void send_error(FILE *f, int status, char *title, char *extra, char *text) {
    send_headers(f, status, title, extra, "text/html", -1, -1);
    fprintf(f, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
    fprintf(f, "<BODY><H4>%d %s</H4>\r\n", status, title);
    fprintf(f, "%s\r\n", text);
    fprintf(f, "</BODY></HTML>\r\n");
}

void get_request(FILE *f) {
    char buf[4096];

    while (fgets(buf, sizeof(buf), f) != NULL) {        
        fgets(buf, sizeof(buf), f);

        printf("%s", buf);
    }

}

int process(FILE *f, long tid) {
    char buf[4096];
    char *method;
    char *path;
    char *protocol;

    struct stat statbuf;  

    if (!fgets(buf, sizeof(buf), f))  return -1;

    get_request(f);

    method = strtok(buf, " ");
    path = strtok(NULL, " ");
    protocol = strtok(NULL, "\r");
    if (!method || !path || !protocol) return -1;

    fseek(f, 0, SEEK_CUR); // Force change of stream direction

    if (strcasecmp(method, "GET") != 0) {
        send_error(f, 501, "Not supported", NULL, "Method is not supported.");
    } else {             
        send_headers(f, 200, "OK", NULL, "text/html", -1, statbuf.st_mtime);

        bool page = !strcmp(path, "/photos.json");

        if (page) {
           fprintf(f, "<b> yeah, photos stream :) </b>"); 
        }  else {           
           fprintf(f, "<HTML><HEAD><TITLE>Yeah</TITLE></HEAD>\r\n<BODY>");
           fprintf(f, "<H4>server (%s) </H4>\r\n<PRE>\n", path); 
        }         
    }

    printf("Im running in thread #%ld!\n", tid); 
    fclose(f);
    return 0;
}

void accept_conn(void *threadid) {
    long tid;
    tid = (long) threadid;

    while (1) {
        int s;
        FILE *f;        

        s = accept(sock, NULL, NULL);
        if (s < 0) { 
            break;
        } else {                    
            f = fdopen(s, "a+");   
            process(f, tid);                   
        };
    }
}

int main(int argc, char *argv[]) {

    struct sockaddr_in sin;

    sock = socket(AF_INET, SOCK_STREAM, 0);

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(PORT);
    bind(sock, (struct sockaddr *) &sin, sizeof (sin));

    listen(sock, 5);
    printf("HTTP server listening on port %d\n", PORT);

    pthread_t threads[NUM_THREADS];
    int rc;
    long t;
    for (t = 0; t < NUM_THREADS; t++) {
        printf("In main: creating thread %ld\n", t);
        rc = pthread_create(&threads[t], NULL, accept_conn, (void *) t);
        if (rc) {
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }

    /* Last thing that main() should do */
    pthread_exit(NULL);

    close(sock);
    return 0;
}

问题出在 get_request 函数中。

4

1 回答 1

1

发生的事情是fgets在它完成读取 http 请求的结尾后阻塞,即"\r\n". 您正在从套接字读取,而不是从文件读取。

你需要做的是这样的事情。此外,必须传入缓冲区及其长度,以便您稍后可以对缓冲区执行某些操作。

void
get_request(FILE *f, char *buf, int len)
{
    int n;
    char *p = buf;

    while (1) {
        fgets(p, len, f);

        if (strcmp(p, "\r\n") == 0) {
            break;
        }

        n = strlen(p);
        p += n;
        len -= n;
    }

    printf("req = %s\n", buf);
}
于 2012-12-14T20:11:23.957 回答