C编写的HTTP服务器在重新生成

时间:2016-06-11 15:31:37

标签: c http server httpserver

我已经阅读了所有相关的答案,但找不到发生这种情况的原因。我已经尝试将close()替换为关闭然后关闭以及更多但仍然相同。 我所需要的只是能够浏览到我的服务器,并在询问文件时它将返回其内容,当询问目录时,它将返回其中的最新列表。除了RST数据包之外,这一切都是可行的。 有人可以帮忙吗?

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <signal.h>

#define HTTP_BAD_REQUEST "HTTP/1.1 404 Not Found\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>File Not Found</TITLE>\n</HEAD>\n<BODY>\n<br/>\n</BODY>\n</HTML>\n"
#define HTTP_GOOD_REQUEST "HTTP/1.1 200 OK\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>Results</TITLE>\n</HEAD>\n<BODY>\n"
#define HTTP_ERROR "HTTP/1.1 500 Internal Server Error\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>Internal Server Error!</TITLE>\n</HEAD>\n<BODY>\n<br/>\n</BODY>\n</HTML>\n"
#define HTTP_NOT_IMPLEMENTED "HTTP/1.1 501 Not Implemented\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>Method Not Implemented</TITLE>\n</HEAD>\n<BODY>\n<br/>\n</BODY>\n</HTML>\n"
#define HTTP_END "<br/></BODY></HTML>\n\0"
#define MAX_REQUEST_SIZE 1024


int send_response(int fd, char* filepath)
{
    struct stat statbuf;

    int iofd;
    int check = 1;
    char buf[1024];

    if ( stat(filepath,&statbuf) < 0 )
    {
    printf("Path not found\n");
    send(fd, HTTP_BAD_REQUEST, strlen(HTTP_BAD_REQUEST), 0);

        return -1;
    }
    else
    {
        if(S_ISDIR(statbuf.st_mode))
        {
            //directory
            DIR *dp;
            struct dirent *ep;

            dp = opendir (filepath);
            if (dp == NULL)
            {
        printf("Error opening directory\n");
        send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
                return -1;
            }

        send(fd, HTTP_GOOD_REQUEST, strlen(HTTP_GOOD_REQUEST), 0);

        ep = readdir (dp);
            while (ep != NULL)
            {
        send(fd, ep->d_name, strlen(ep->d_name), 0);
        send(fd, "<br/>", strlen("<br/>"), 0);
        ep = readdir (dp);
            }

            send(fd, HTTP_END, strlen(HTTP_END), 0);

            (void) closedir (dp);
            return 0;
        }
        else if (S_ISREG(statbuf.st_mode))
        {
            //regular file

            iofd = open(filepath, O_RDONLY);
            if( iofd < 0 )
            {
                printf("Error opening file\n");
        send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
                return -1;
            }

        send(fd, HTTP_GOOD_REQUEST, strlen(HTTP_GOOD_REQUEST), 0);

            while ( check > 0)
            {
                check = read(iofd,buf,sizeof(buf));
                if (check < 0)
                {
                    printf("Error reading file\n");
            send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
                    close(iofd);

                    return -1;
                }
                else if (check == 0)
            break;
                else
            send(fd, buf, strlen(buf), 0);
            }

            send(fd, HTTP_END, strlen(HTTP_END), 0);

        close(iofd);
            return 0;
        }
    }
}

int process(int fd, char* header)
{
    char npath[MAX_REQUEST_SIZE];

    char *eol = strchr(header, '\r');

    // split header to get path and method
    char *method = strtok(header, " ");
    char *path = strtok(NULL, " ");
    char *http = strtok(NULL, " ");
    if( eol != NULL )
        *eol = '\0';


    if( strcmp(method, "GET") || (strcmp(method, "POST")))
    {
        if( path[0] == '/' && path[1] == '\0' )
        {
            path ="/";
        }
        else if( path[0] == '/' )
        {
            snprintf(npath, MAX_REQUEST_SIZE, "%s", path);
            path = npath;
        }

        return send_response(fd, path);
    }
    else
    {
        send(fd, HTTP_NOT_IMPLEMENTED, strlen(HTTP_NOT_IMPLEMENTED), 0);
        return -1;
    }
}

int get_line(int sock, char *buf, int size)
{
    int i = 0;
    char c = '\0';
    int n;

    while ((i < size - 1) && (c != '\n'))
    {
        n = recv(sock, &c, 1, 0);

        if (n > 0)
        {
            if (c == '\r')
            {
                n = recv(sock, &c, 1, MSG_PEEK);
                if ((n > 0) && (c == '\n'))
                    recv(sock, &c, 1, 0);
                else
                    c = '\n';
            }
            buf[i] = c;
            i++;
        }
        else
            c = '\n';
    }
    buf[i] = '\0';

    return(i);
}

int service(int fd)
{
    char buffer[MAX_REQUEST_SIZE];

    if (get_line(fd, buffer, MAX_REQUEST_SIZE) <= 0)
    {
        printf("Error reading from socket");
        send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
        return -1;
    }
    return process(fd, buffer);
}
void cleanup( int signal )
{

    int pid;
        while(1)
        {
            pid = waitpid(-1, NULL, WNOHANG);

            if( pid < 0 )
                break;
            else if( pid == 0 )
                break;
        }
    exit(0);
}
int main(int argc, char *argv[])
{
    int port = 80;
    int max_requests;
    struct sigaction finish;

    finish.sa_handler = &cleanup;
    sigaction( SIGINT, &finish, NULL );

    if ((argc == 1) || (argc > 3))
    {
        printf("Usage Error: wrong amount of arguments to main");
        return -1;
    }
    else if (argc == 3)
    {
        max_requests = strtol(argv[1], NULL, 0);
        port = strtol(argv[2], NULL, 0);
    }
    else
        max_requests = strtol(argv[1], NULL, 0);


    struct sockaddr_in servaddr;
    int serversock = socket(AF_INET, SOCK_STREAM, 0);
    int on = 1;


    if( serversock < 0 )
    {
        printf("Error creating socket: %s\n", strerror(errno));
        return 1;
    }


    if( setsockopt(serversock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0 )
        printf("Error tweaking socket options: %s\n", strerror(errno));

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(port);
    if( bind(serversock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )
    {
        printf("Error binding to server address: %s\n", strerror(errno));
        return 1;
    }

    if( listen(serversock, max_requests) < 0 )
    {
        printf("Error using listen(): %s\n", strerror(errno));
        return 1;
    }

    while(1)
    {
        int clientsock, pid, childstatus;

        //server shall now wait for a new connection
        clientsock = accept(serversock, NULL, NULL);
        if( clientsock < 0 )
        {
            printf("Error using accept(): %s\n", strerror(errno));
            return 1;
        }

        pid = fork();
        if( pid < 0 )
        {
            printf("Error using fork(): %s\n", strerror(errno));
            send(clientsock, HTTP_ERROR, strlen(HTTP_ERROR), 0);
            close(clientsock);
            continue;
        }
        else if( pid == 0 )
        {
            shutdown(serversock, 2);
            if (service(clientsock) != 0 )
        printf("error in service\n");
        if (shutdown(clientsock, SHUT_WR) != 0)
        {
        printf("Error shutting the socket down: %s\n", strerror(errno));
        return -1;
        }
        close(clientsock);  
            return 0;
        }

        pid = waitpid(-1, NULL, WNOHANG);
        if( pid < 0 )
        {
                printf("Error using waitpid(): %s\n", strerror(errno));
                break;
        }
    close(clientsock);

    }
    return 999;
}

1 个答案:

答案 0 :(得分:1)

以下代码:

  1. 干净地编译
  2. 正确地将错误消息输出到stderr
  3. 正确输出&#39;用法&#39;不正确的命令行参数数时的消息
  4. &#39;应该&#39;在第一次
  5. 之后正确连接 警告:没有经过彻底的测试。

    #include <sys/socket.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <sys/sendfile.h>
    #include <sys/stat.h>
    #include <arpa/inet.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <dirent.h>
    #include <errno.h>
    #include <signal.h>
    
    #define HTTP_BAD_REQUEST "HTTP/1.1 404 Not Found\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>File Not Found</TITLE>\n</HEAD>\n<BODY>\n<br/>\n</BODY>\n</HTML>\n"
    #define HTTP_GOOD_REQUEST "HTTP/1.1 200 OK\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>Results</TITLE>\n</HEAD>\n<BODY>\n"
    #define HTTP_ERROR "HTTP/1.1 500 Internal Server Error\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>Internal Server Error!</TITLE>\n</HEAD>\n<BODY>\n<br/>\n</BODY>\n</HTML>\n"
    #define HTTP_NOT_IMPLEMENTED "HTTP/1.1 501 Not Implemented\nContent-Type: text/html\nConnection: Closed\n\n<HTML>\n<HEAD>\n<TITLE>Method Not Implemented</TITLE>\n</HEAD>\n<BODY>\n<br/>\n</BODY>\n</HTML>\n"
    #define HTTP_END "<br/></BODY></HTML>\n\0"
    
    #define MAX_REQUEST_SIZE 1024
    
    
    int send_response(int fd, char* filepath)
    {
        struct stat statbuf;
    
        int     iofd;    // file descriptor
        ssize_t readStatus = 1;
        char    buf[ MAX_REQUEST_SIZE ];
    
        if ( stat(filepath,&statbuf) < 0 )
        {
            perror( "stat for file failed" );
            //printf("Path not found\n");
            send(fd, HTTP_BAD_REQUEST, strlen(HTTP_BAD_REQUEST), 0);
            return -1;
        }
    
        else
        { // path found
            if(S_ISDIR(statbuf.st_mode))
            {
                //directory
                DIR *dp;
                struct dirent *ep;
    
                dp = opendir (filepath);
                if (dp == NULL)
                {
                    fprintf( stderr, "Error opening directory\n");
                    send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
                    return -1;
                }
    
                // implied else, opendir successful
    
                send(fd, HTTP_GOOD_REQUEST, strlen(HTTP_GOOD_REQUEST), 0);
    
                ep = readdir (dp);
    
                while (ep != NULL)
                {
                    send(fd, ep->d_name, strlen(ep->d_name), 0);
                    send(fd, "<br />", strlen("<br />"), 0);
                    ep = readdir (dp);
                }
    
                send(fd, HTTP_END, strlen(HTTP_END), 0);
    
                closedir (dp);
                return 0;
            }
    
            else if (S_ISREG(statbuf.st_mode))
            { //regular file
                iofd = open(filepath, O_RDONLY);
                if( iofd < 0 )
                {
                    //fprintf(stderr, "Error opening file\n");
                    perror( "open failed" );
                    send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
                    return -1;
                }
    
                // implied else, open successful
    
                send(fd, HTTP_GOOD_REQUEST, strlen(HTTP_GOOD_REQUEST), 0);
    
                while ( readStatus > 0)
                {
                    readStatus = read(iofd,buf,sizeof(buf));
                    if (readStatus < 0)
                    {
                        perror( "read of file failed");
                        //printf("Error reading file\n");
                        send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
                        close(iofd);
                        return -1;
                    }
    
                    else if (readStatus == 0) // EOF or signal
                        break;
    
                    else // transmit line from file
                        send(fd, buf, strlen(buf), 0);
                } // end while
    
                send(fd, HTTP_END, strlen(HTTP_END), 0);
    
                close(iofd);
                return 0;
            }
        }
        return -2;
    }
    
    
    int process(int fd, char* header)
    {
        // split header to get path and method
        char *method = strtok(header, " ");
        char *path = strtok(NULL, " ");
        //char *http = strtok(NULL, " ");
    
        // if trailing newline, replace with NUL byte
        char *eol = NULL;
        if( NULL == (eol = strchr(header, '\r') ) )
            *eol = '\0';
    
    
        if( strcmp(method, "GET") || (strcmp(method, "POST")))
        {
            return send_response(fd, path);
        }
    
        else
        {
            send(fd, HTTP_NOT_IMPLEMENTED, strlen(HTTP_NOT_IMPLEMENTED), 0);
            return -1;
        }
    } // end function: process
    
    
    int get_line(int sock, char *buf, int size)
    {
        int     i = 0;
        char    c = '\0';
        ssize_t recvStatus;
    
        while ( (i < (size - 1)) && (c != '\n') )
        {
            recvStatus = recv(sock, &c, 1, 0);
    
            if ( recvStatus > 0)
            { // then some bytes read
                if (c == '\r')
                {
                    recvStatus = recv(sock, &c, 1, MSG_PEEK);
    
                    if ((recvStatus > 0) && (c == '\n'))
                        recv(sock, &c, 1, 0);
    
                    else
                        c = '\n';
                } // endif
    
                buf[i] = c;
                i++;
            }
    
            else
            {
                c = '\n';
            } // endif
        } // end while
    
        // terminate the char array
        buf[i] = '\0';
    
        return(i);
    } // end function: get_line
    
    
    int service(int fd)
    {
        char buffer[MAX_REQUEST_SIZE];
    
        if (get_line(fd, buffer, MAX_REQUEST_SIZE) <= 0)
        {
            fprintf( stderr, "Error reading from socket");
            send(fd, HTTP_ERROR, strlen(HTTP_ERROR), 0);
            return -1;
        }
    
        return process(fd, buffer);
    } // end function: service
    
    
    void cleanup( int signal )
    {
        (void)signal;
        pid_t pid;
    
        while(1)
        {
            pid = waitpid(-1, NULL, WNOHANG);
    
            if( pid <= 0 )
                break;
        }
        exit(0);
    } // end function: cleanup
    
    
    int main(int argc, char *argv[])
    {
        uint16_t port = 80;
        int      max_requests;
        struct sigaction finish;
    
        finish.sa_handler = &cleanup;
        sigaction( SIGINT, &finish, NULL );
    
        if ( (argc != 3) && (argc != 2) )
        {
            fprintf( stderr, "USAGE: %s <maxConnections> [<portToUse>]\n", argv[0]);
            //printf("Usage Error: wrong amount of arguments to main");
            return -1;
        }
    
    
        max_requests = (int)strtol(argv[1], NULL, 0);
    
        if( 3 == argc )
        {
            port = (uint16_t)strtol(argv[2], NULL, 0);
        }
    
        int serversock = socket(AF_INET, SOCK_STREAM, 0);
        if( serversock < 0 )
        {
            printf("Error creating socket: %s\n", strerror(errno));
            return 1;
        }
    
        int on = 1;
        if( setsockopt(serversock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0 )
        {
            perror( "setsockopt for SO_REUSEADDR failed" );
            //printf("Error tweaking socket options: %s\n", strerror(errno));
        }
    
        if( setsockopt(serversock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0 )
        {
            perror( "setsockopt for SO_KEEPALIVE failed" );
            //printf("Error tweaking socket options: %s\n", strerror(errno));
        }
    
        struct sockaddr_in servaddr;
    
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family      = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port        = htons(port);
    
        if( bind(serversock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )
        {
            perror( "bind failed" );
            //printf("Error binding to server address: %s\n", strerror(errno));
            return 1;
        }
    
        if( listen(serversock, max_requests) < 0 )
        {
            perror( "listen failed" );
            //printf("Error using listen(): %s\n", strerror(errno));
            return 1;
        }
    
        while(1)
        {
            int clientsock;
            pid_t pid;
            //int childstatus;
    
            //server shall now wait for a new connection
            clientsock = accept(serversock, NULL, NULL);
            if( clientsock < 0 )
            {
                perror( "accept failed" );
                //printf("Error using accept(): %s\n", strerror(errno));
                close( serversock );
                return 1;
            }
    
            pid = fork();
            switch( pid )
            {
                case -1: // fork failed
                    fprintf(stderr, "Error using fork(): %s\n", strerror(errno));
                    send(clientsock, HTTP_ERROR, strlen(HTTP_ERROR), 0);
                    close(clientsock);
                    break;
    
                case 0: // in child process
                    //shutdown(serversock, 2);
    
                    if (service(clientsock) != 0 )
                    {
                        fprintf( stderr, "error in service\n");
                    }
    
                    close(clientsock);
                    return 0;
                    break;
    
                default: // in parent process
                    pid = waitpid( -1, NULL, WNOHANG);
                    close(clientsock);
                    break;
            } // end switch
        } // end while
        return 0;
    } // end function: main