Веб-сервер сокета C не отображает HTML в браузере, только отправляет ответ HTTP - PullRequest
0 голосов
/ 10 ноября 2018

Я относительно новичок в C, и пытаюсь поиграться с кодом, который мне дал профессор, а затем с тех пор модифицирую его, чтобы помочь мне вместе с серверным проектом. Я не могу понять, как на самом деле быть в состоянии видеть HTML в Lynx, я просто получаю ответ HTTP. (я могу свернуться и посмотреть, что я пытаюсь отправить, но браузер не будет загружать тело HTML) Я проверял все, что мог придумать, но на данный момент я должен признать, что недостаточно знаю о HTTP ответы и мог бы сделать шаг в правильном направлении, где я сошел с пути.

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BUFFER_SIZE 9999
#define HTTP_METHOD     "HTTP/1.1 "
#define HTTP__OK    "200 OK\r\n"
#define HTTP__NOT_FOUND "404 Not Found\r\n"
#define SERVER_NAME     "Server: ECE435\r\n"

/* Default port to listen on */
#define DEFAULT_PORT    8080 //modify port to listen on 8080

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

    int socket_fd,new_socket_fd;
    struct sockaddr_in server_addr, client_addr;
    int port=DEFAULT_PORT;
    int n;
    socklen_t client_len;
    char buffer[BUFFER_SIZE];

    printf("Starting server on port %d\n",port);

    /* Open a socket to listen on */
    /* AF_INET means an IPv4 connection */
    /* SOCK_STREAM means reliable two-way connection (TCP) */
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd<0) {
        fprintf(stderr,"Error opening socket! %s\n",
            strerror(errno));
        exit(1);
    }

    /* Set up the server address to listen on */
    /* The memset stes the address to 0.0.0.0 which means */
    /* listen on any interface. */
    memset(&server_addr,0,sizeof(struct sockaddr_in));
    server_addr.sin_family=AF_INET;

    /* Convert the port we want to network byte order */
    server_addr.sin_port=htons(port);

    /* Bind to the port */
    if (bind(socket_fd, (struct sockaddr *) &server_addr,
        sizeof(server_addr)) <0) {
        fprintf(stderr,"Error binding! %s\n", strerror(errno));
        fprintf(stderr,"Probably in time wait, have to wait 60s if you ^C to close\n");
        exit(1);
    }

    /* Tell the server we want to listen on the port */
    /* Second argument is backlog, how many pending connections can */
    /* build up */
    listen(socket_fd,5);


wait_for_connection:


    /* Call accept to create a new file descriptor for an incoming */
    /* connection.  It takes the oldest one off the queue */
    /* We're blocking so it waits here until a connection happens */
    client_len=sizeof(client_addr);
    new_socket_fd = accept(socket_fd,
            (struct sockaddr *)&client_addr,&client_len);
    if (new_socket_fd<0) {
        fprintf(stderr,"Error accepting! %s\n",strerror(errno));
        exit(1);
    }

    while(1){
        /* Someone connected!  Let's try to read BUFFER_SIZE-1 bytes */
        memset( buffer, 0, BUFFER_SIZE );
        n = read( new_socket_fd, buffer, ( BUFFER_SIZE-1 ) );
        if (n==0){
            fprintf( stderr, "Connection to client lost\n\n" );
            break;
        }
        else if( n < 0 ){
            fprintf(stderr,"Error reading from socket %s\n",
                strerror(errno));
        }

        /* Print the message we received */
        printf("Message received: %s\n" ,buffer);


        const char *PATTERN1 = "GET /"; //first cut to make on buffer
        const char *PATTERN2 = " HTTP"; //second cut to make on buffer
        char *target = NULL; //variable to hold the slice we're taking
        char *start, *end;  //defining variables to hold start and end positions
        if ( start = strstr( buffer, PATTERN1 ) ){  //code to grab a slice of buffer
            start += strlen( PATTERN1 );        

        if ( end = strstr( start, PATTERN2 ) ){
            target = ( char * )malloc( end - start + 1 );
            memcpy( target, start, end - start );
            target[end - start] = '\0';
        }
    }
        if ( target ) printf( "Client requested: %s\n", target ); //code is working to this point. I can tell what file to get.

    time_t rawtime;
    struct tm info;
    time( &rawtime );
    struct tm * timeinfo;
    char timestamp[100];
    time_t now = time(0);
    struct tm tm = *gmtime(&now);
    strftime(timestamp, sizeof( timestamp ) , "%a, %d %b %Y %H:%M:%S %Z", &tm);
    //printf("Time is: [%s]\n", timestamp);

    struct stat file_info;      //define statistics structure for file info
    stat( target, &file_info ); //initiate file_info as the stat structure for target


    char send_client[9999];


    sprintf( send_client, "HTTP/1.0 %s%s\r\nServer: ECE435\r\nLast-Modified: Fri, 08 Sep 2017 04:31:47 GMT\r\nContent-Length: 85\r\nContent-Type: text/html\r\n\r\n", HTTP__OK, timestamp );

    char file_path[256]; //limited to 256 char for now
    sprintf( file_path, "./%s", target); //this is how you can combine char arrays: puts "./" + 'target' into 'file_path'   

    //int fd;

    //printf( "%ld\r\n" , file_info.st_size ); //this should print the File Size


    char source[BUFFER_SIZE + 1];
    FILE *fp = fopen( file_path, "r");
    if (fp != NULL) {
        size_t newLen = fread(source, sizeof(char), BUFFER_SIZE, fp);
        if (newLen == 0) {
            fputs("Error reading file", stderr);
        } else {
            source[newLen] = '\0'; /* Just to be safe. */
        }

        fclose(fp);
    }
        strcat( send_client, source);


    /* Send a response */
    printf( "\r\n%s\r\n" , send_client ); //print response before sending
    n = write( new_socket_fd, send_client , strlen(send_client) ) ;     
    if( n < 0 ){
        fprintf( stderr, "Error writing. %s\n", strerror(errno));
    }

}

close(new_socket_fd);

printf("Done connection, go back and wait for another\n\n");

goto wait_for_connection;

/* Try to avoid TIME_WAIT */
//  sleep(1);

/* Close the sockets */
close(socket_fd);

return 0;
}

1 Ответ

0 голосов
/ 10 ноября 2018
    memset( buffer, 0, BUFFER_SIZE );
    n = read( new_socket_fd, buffer, ( BUFFER_SIZE-1 ) );
    if (n==0){
        fprintf( stderr, "Connection to client lost\n\n" );
        break;
    }
    else if( n < 0 ){
        fprintf(stderr,"Error reading from socket %s\n",
            strerror(errno));
    }

    /* Print the message we received */
    printf("Message received: %s\n" ,buffer);

Когда вы звоните read по TCP-соединению, вы не получаете сообщение. Если вы хотите получать HTTP-сообщения, вы должны написать код для этого. Это просто сломано.

sprintf( send_client, "HTTP/1.0 %s%s\r\nServer: ECE435\r\n"
   "Last-Modified: Fri, 08 Sep 2017 04:31:47 GMT\r\n"
   "Content-Length: 85\r\nContent-Type: text/html\r\n\r\n", HTTP__OK, timestamp );

Если файл не содержит ровно 85 байтов, отправка заголовка "Content-Length" не является хорошей идеей.

У вас есть цикл while(1), который, кажется, пытается получить несколько сообщений по одному соединению. Но нет кода, который бы определял, когда вы действительно получили HTTP-запрос, так что это определенно не сработает.

Протокол HTTP сложен, и написание кода для его правильной реализации требует прохождения стандарта и реализации всего, что требуется стандартом. Этот код не делает этого, и если он действительно работает, это будет в основном удачей.

Вы можете просто изменить заголовок «Content-Length», чтобы иметь правильную длину. Но вы все еще нарушаете множество правил. Например, вы могли бы легко отправить более одного ответа на один запрос, поскольку вы не гарантируете, что read вернул весь HTTP-запрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...