【问题标题】:Request to this serever keep loading forever对此服务器的请求永远保持加载
【发布时间】:2021-11-24 02:45:53
【问题描述】:

我正在用 C 语言编写一个非常简单的 Web 服务器,名为 tinyWeb。我无法理解它有什么问题。我花了几个小时试图找出问题所在。但我没有找到它。这个程序也以特殊权限运行。我认为我用来向客户端主机发送信息的以下函数有问题。

int send_string(int sockfd, unsigned char *buffer){
    int sent_bytes, bytes_to_send;
    bytes_to_send = strlen(buffer);
    while(bytes_to_send > 0){
        sent_bytes = send(sockfd, buffer, bytes_to_send, 0);
        if(sent_bytes == -1);
            return 0;
        bytes_to_send -= sent_bytes;
        buffer += sent_bytes;
    } 
    printf("ALL BYTES SENT\n"); //I can't see this message.                         
    return 1; 

这是完整的源代码。

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "XXX.h" 

#define PORT 80 
#define WEBROOT "./webroot" //serevers root

void handle_connection(int, struct sockaddr_in *); //handle web request
int get_file_size(int); //returns the file soze of open file descriptor

int main(void){
    int sockfd, new_sockfd, yes=1;
    struct sockaddr_in host_addr, client_addr;
    socklen_t sin_size;
    
    printf("Accepting web requests on port %d\n", PORT);
    
    if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
        printf("ERROR: while creating socket\n");
        exit(0);
    }

    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) ==-1){
        printf("ERROR: while setting socket option SO_REUSEADDR\n");
        exit(0);
    }
    
    host_addr.sin_family = AF_INET;
    host_addr.sin_port = htons(PORT);
    host_addr.sin_addr.s_addr = INADDR_ANY;
    memset(&(host_addr.sin_zero), '\0', 8);

    if(bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)) == -1){
        printf("ERROR: while binding socket to address.\n");
        exit(0);
    }

    if(listen(sockfd, 20) == -1){   
        printf("ERROR: while listening for connections\n");
        exit(0);
    }

    while(1){
        printf("in while(1)\n");
        sin_size = sizeof(struct sockaddr_in);
        printf("done up to sin_size\n");
        new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
        printf("done up to accept\n");
        if(new_sockfd == -1){
            printf("ERROR: while accepting connection\n");
            exit(0);
        }
        
        handle_connection(new_sockfd, &client_addr);
    }
    return 0;
}

void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr){
    unsigned char *ptr, request[500], resourse[500];
    int fd, len;

    len = recv_line(sockfd, request); //scroll below to see this function.
    printf("done up to recv_line()\n");

    printf("Got request from %s:%d \"%s\"\\\n", inet_ntoa(client_addr_ptr -> sin_addr), ntohs(client_addr_ptr->sin_port), request);
    
    ptr = strstr(request, " HTTP/"); //search for HTTP
    if(ptr == NULL){
        printf("NOT HTTP!\n");
    }
                 
    else{
        *ptr = 0;
        ptr = NULL;
        printf("request is HTTP\n");
        if(strcmp(request, "GET ")){
            ptr = request+4;
            printf("is a get request\n");
        }
        if(strcmp(request, "HEAD ")){
            ptr = request+5;
            printf("is a head request\n");
        }
        if(ptr == NULL){
            printf("NULL: ");
            printf("\tUNKNOWN REQUEST!\n");
        }
    
        else{
            printf("%s\n", ptr);
            if((ptr[strlen(ptr)-1]) == '/' )
                strcat(ptr, "/index.html"); //add index.html to the end strcat().
            strcpy(resourse, WEBROOT);   
            strcat(resourse, ptr);  
                                                  
            fd = open(resourse, O_RDONLY, 0);
            printf("opening file \'%s\' \n", resourse);
            if (fd == -1){          
                printf(" 404 Not Found\n");
                send_string(sockfd, "HTTP/1.0 404 Not Found\r\n");
                send_string(sockfd, "Serever: Tiny webserver\r\n");
                send_string(sockfd, "<html><head><title>404 Not Found</title></head>\r\n");
                send_string(sockfd, "<body><h1>URL not found</h1></body></html>\r\n");
            }                       
                                        
            else{                   
                printf("200 OK\n");
                unsigned char temp_buffer[] = "HTTP/1.0 200 OK\r\n";
                send(sockfd, &temp_buffer, strlen(temp_buffer), 0);
                unsigned char temp2_buffer[] = "Server: Tiny webserver\r\n";
                send(sockfd, &temp2_buffer, strlen(temp_buffer), 0);
                printf("done sending basic info\n");
                if((ptr == request+4) || (ptr == request+5)){ //if it's a GET request.
                    printf("ptr is request+4\n");
                    if((len=get_file_size(fd)) == -1){
                        printf("Error: while getting file size\n");
                        exit(0);
                    }      
                    if((ptr = (unsigned char *)malloc(len)) == NULL){
                        printf("Error: while allocatin memory of heap\n");
                        exit(0);
                    }
                    printf("passed get_file_size() and malloc() succesfully\n");
                    read(fd, ptr, len);
                    send(sockfd, ptr, len, 0);
                    printf("file sent\n"); //I can see this massege on the terminal but the browser is not displaying any thing.
                    free(ptr);
                }                
                close(fd);         
            }
        }
    }
}
                        
                    
int get_file_size(int fd){
    struct stat fileInfo;
    
    if(fstat(fd, &fileInfo) == -1)
        return -1;
    return (int) fileInfo.st_size;
}
                    

下面是XXX.h文件的内容。

#define EOL "\r\n"                           
#define EOL_SIZE 

//This is the previously mentioned send_string function.                       
int send_string(int sockfd, unsigned char *buffer){
    int sent_bytes, bytes_to_send;
    bytes_to_send = strlen(buffer);
    while(bytes_to_send > 0){
        sent_bytes = send(sockfd, buffer, bytes_to_send, 0);
        if(sent_bytes == -1);
            return 0;
        bytes_to_send -= sent_bytes;
        buffer += sent_bytes;
    } 
    printf("ALL BYTES SENT\n"); //I can't see this message.                         
    return 1;                   
}                                 
                                       
int recv_line(int sockfd, unsigned char *dest_buffer){             
    printf("int recv_line()\n");
    unsigned char *ptr;        
    int eol_match = 0;         
                                  
    ptr = dest_buffer;
    printf("assigning to ptr done\n");        
    while(recv(sockfd, ptr, 1, 0) == 1){
        printf(".");     
        if(*ptr == EOL[eol_match]){
            eol_match++;    
            if(eol_match == EOL_SIZE){
                *(ptr+1-EOL_SIZE) = '\0';
                return strlen(dest_buffer);
            }else{  
                eol_match == 0;
            }       
        }                
        ptr++;            
    }                            
    return 0;                 
}
        

当我启动服务器程序并在浏览器上键入我的 IP 地址时,它会一直加载,直到我用 ^c 终止服务器程序,我不知道出了什么问题。我将非常感谢您的帮助。 如果您可以对问题发表评论。

【问题讨论】:

    标签: c sockets web server


    【解决方案1】:

    发布的代码在通过 C 编译器运行时会产生以下结果:

    gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" -o "untitled.o" 
    
    untitled.c: In function ‘send_string’:
    
    untitled.c:19:28: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness [-Wpointer-sign]
       19 |     bytes_to_send = strlen(buffer);
          |                            ^~~~~~
          |                            |
          |                            unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:385:35: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      385 | extern size_t strlen (const char *__s)
          |   
                    ~~~~~~~~~~~~^~~
    untitled.c:19:21: warning: conversion from ‘size_t’ {aka ‘long unsigned int’} to ‘int’ may change value [-Wconversion]
       19 |     bytes_to_send = strlen(buffer);
          |                     ^~~~~~
    
    untitled.c:21:43: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
       21 |         sent_bytes = send(sockfd, buffer, bytes_to_send, 0);
          |                                           ^~~~~~~~~~~~~
    
    untitled.c:21:22: warning: conversion from ‘ssize_t’ {aka ‘long int’} to ‘int’ may change value [-Wconversion]
       21 |         sent_bytes = send(sockfd, buffer, bytes_to_send, 0);
          |                      ^~~~
    
    untitled.c:22:29: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]
       22 |         if(sent_bytes == -1);
          |                             ^
    
    untitled.c:22:9: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
       22 |         if(sent_bytes == -1);
          |         ^~
    
    untitled.c:23:13: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
       23 |             return 0;
          |             ^~~~~~
    
    untitled.c: In function ‘recv_line’:
    
    untitled.c:42:37: error: expected expression before ‘)’ token
       42 |             if(eol_match == EOL_SIZE){
          |                                     ^
    
    untitled.c:44:31: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness [-Wpointer-sign]
       44 |                 return strlen(dest_buffer);
          |                               ^~~~~~~~~~~
          |                               |
          |                               unsigned char *
    
    In file included from untitled.c:4:
    /usr/include/string.h:385:35: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      385 | extern size_t strlen (const char *__s)
          |                       ~~~~~~~~~~~~^~~
    
    untitled.c:44:24: warning: conversion from ‘size_t’ {aka ‘long unsigned int’} to ‘int’ may change value [-Wconversion]
       44 |                 return strlen(dest_buffer);
          |                        ^~~~~~~~~~~~~~~~~~~
    
    untitled.c:46:27: warning: statement with no effect [-Wunused-value]
       46 |                 eol_match == 0;
          |                 ~~~~~~~~~~^~~~
    
    untitled.c: In function ‘handle_connection’:
    
    untitled.c:119:18: warning: pointer targets in passing argument 1 of ‘strstr’ differ in signedness [-Wpointer-sign]
      119 |     ptr = strstr(request, " HTTP/"); //search for HTTP
          |                  ^~~~~~~
          |                  |
          |                  unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:330:14: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      330 | extern char *strstr (const char *__haystack, const char *__needle)
          |              ^~~~~~
    
    untitled.c:119:9: warning: pointer targets in assignment from ‘char *’ to ‘unsigned char *’ differ in signedness [-Wpointer-sign]
      119 |     ptr = strstr(request, " HTTP/"); //search for HTTP
          |         ^
    
    untitled.c:128:19: warning: pointer targets in passing argument 1 of ‘strcmp’ differ in signedness [-Wpointer-sign]
      128 |         if(strcmp(request, "GET ")){
          |                   ^~~~~~~
          |                   |
          |                   unsigned char *
    
    In file included from untitled.c:4:
    /usr/include/string.h:137:32: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      137 | extern int strcmp (const char *__s1, const char *__s2)
          |                    ~~~~~~~~~~~~^~~~
    
    untitled.c:132:19: warning: pointer targets in passing argument 1 of ‘strcmp’ differ in signedness [-Wpointer-sign]
      132 |         if(strcmp(request, "HEAD ")){
          |                   ^~~~~~~
          |                   |
          |                   unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:137:32: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      137 | extern int strcmp (const char *__s1, const char *__s2)
          |                    ~~~~~~~~~~~~^~~~
    
    untitled.c:143:28: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness [-Wpointer-sign]
      143 |             if((ptr[strlen(ptr)-1]) == '/' )
          |                            ^~~
          |                            |
          |                            unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:385:35: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      385 | extern size_t strlen (const char *__s)
          |                       ~~~~~~~~~~~~^~~
    
    untitled.c:144:24: warning: pointer targets in passing argument 1 of ‘strcat’ differ in signedness [-Wpointer-sign]
      144 |                 strcat(ptr, "/index.html"); //add index.html to the end strcat().
          |                        ^~~
          |                        |
          |                        unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:130:14: note: expected ‘char * restrict’ but argument is of type ‘unsigned char *’
      130 | extern char *strcat (char *__restrict __dest, const char *__restrict __src)
          |              ^~~~~~
    
    untitled.c:145:20: warning: pointer targets in passing argument 1 of ‘strcpy’ differ in signedness [-Wpointer-sign]
      145 |             strcpy(resourse, WEBROOT);
          |                    ^~~~~~~~
          |                    |
          |                    unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:122:14: note: expected ‘char * restrict’ but argument is of type ‘unsigned char *’
      122 | extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
          |              ^~~~~~
    
    untitled.c:146:20: warning: pointer targets in passing argument 1 of ‘strcat’ differ in signedness [-Wpointer-sign]
      146 |             strcat(resourse, ptr);
          |                    ^~~~~~~~
          |                    |
          |                    unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:130:14: note: expected ‘char * restrict’ but argument is of type ‘unsigned char *’
      130 | extern char *strcat (char *__restrict __dest, const char *__restrict __src)
          |              ^~~~~~
    
    untitled.c:146:30: warning: pointer targets in passing argument 2 of ‘strcat’ differ in signedness [-Wpointer-sign]
      146 |             strcat(resourse, ptr);
          |                              ^~~
          |                              |
          |                              unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:130:14: note: expected ‘const char * restrict’ but argument is of type ‘unsigned char *’
      130 | extern char *strcat (char *__restrict __dest, const char *__restrict __src)
          |              ^~~~~~
    
    untitled.c:148:23: warning: pointer targets in passing argument 1 of ‘open’ differ in signedness [-Wpointer-sign]
      148 |             fd = open(resourse, O_RDONLY, 0);
          |                       ^~~~~~~~
          |                       |
          |                       unsigned char *
    
    In file included from untitled.c:2:
    
    /usr/include/fcntl.h:168:30: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      168 | extern int open (const char *__file, int __oflag, ...) __nonnull ((1));
          |                  ~~~~~~~~~~~~^~~~~~
    
    untitled.c:152:37: warning: pointer targets in passing argument 2 of ‘send_string’ differ in signedness [-Wpointer-sign]
      152 |                 send_string(sockfd, "HTTP/1.0 404 Not Found\r\n");
          |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
          |                                     |
          |                                     char *
    
    untitled.c:17:44: note: expected ‘unsigned char *’ but argument is of type ‘char *’
       17 | int send_string(int sockfd, unsigned char *buffer){
          |                             ~~~~~~~~~~~~~~~^~~~~~
    
    untitled.c:153:37: warning: pointer targets in passing argument 2 of ‘send_string’ differ in signedness [-Wpointer-sign]
      153 |                 send_string(sockfd, "Serever: Tiny webserver\r\n");
          |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          |                                     |
          |                                     char *
    
    untitled.c:17:44: note: expected ‘unsigned char *’ but argument is of type ‘char *’
       17 | int send_string(int sockfd, unsigned char *buffer){
          |                             ~~~~~~~~~~~~~~~^~~~~~
    
    untitled.c:154:37: warning: pointer targets in passing argument 2 of ‘send_string’ differ in signedness [-Wpointer-sign]
      154 |                 send_string(sockfd, "<html><head><title>404 Not Found</title></head>\r\n");
          |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          |                                     |
          |                                     char *
    
    untitled.c:17:44: note: expected ‘unsigned char *’ but argument is of type ‘char *’
       17 | int send_string(int sockfd, unsigned char *buffer){
          |                             ~~~~~~~~~~~~~~~^~~~~~
    
    untitled.c:155:37: warning: pointer targets in passing argument 2 of ‘send_string’ differ in signedness [-Wpointer-sign]
      155 |                 send_string(sockfd, "<body><h1>URL not found</h1></body></html>\r\n");
          |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          |                                     |
          |                                     char *
    
    untitled.c:17:44: note: expected ‘unsigned char *’ but argument is of type ‘char *’
       17 | int send_string(int sockfd, unsigned char *buffer){
          |                             ~~~~~~~~~~~~~~~^~~~~~
    
    untitled.c:161:51: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness [-Wpointer-sign]
      161 |                 send(sockfd, &temp_buffer, strlen(temp_buffer), 0);
          |                                                   ^~~~~~~~~~~
          |                                                   |
          |                                                   unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:385:35: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      385 | extern size_t strlen (const char *__s)
          |                       ~~~~~~~~~~~~^~~
    
    untitled.c:163:52: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness [-Wpointer-sign]
      163 |                 send(sockfd, &temp2_buffer, strlen(temp_buffer), 0);
          |                                                    ^~~~~~~~~~~
          |                                                    |
          |                                                    unsigned char *
    
    In file included from untitled.c:4:
    
    /usr/include/string.h:385:35: note: expected ‘const char *’ but argument is of type ‘unsigned char *’
      385 | extern size_t strlen (const char *__s)
          |                       ~~~~~~~~~~~~^~~
    untitled.c:171:55: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
      171 |                     if((ptr = (unsigned char *)malloc(len)) == NULL){
          |                                                       ^~~
    
    untitled.c:176:35: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
      176 |                     read(fd, ptr, len);
          |                                   ^~~
    
    untitled.c:177:39: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
      177 |                     send(sockfd, ptr, len, 0);
          |                                       ^~~
    
    Compilation failed.
    

    【讨论】:

    • 注意:我将声明:#include "xxx.h"替换为xxx.h的实际内容,此替换的唯一效果是行号略有变化
    • 注意:头文件:xxx.h 不应该有函数体,只有函数原型
    • 关于:printf("Error: while allocatin memory of heap\n"); exit(0); 1) 调用perror() 所以失败的实际原因输出到stderr 2) 一般情况下,exit(0); 用于表示成功。建议:exit( EXIT_FAILURE );
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    • 2012-09-21
    • 2020-03-26
    • 2011-06-30
    • 1970-01-01
    • 2022-11-21
    相关资源
    最近更新 更多