tinyhttpd项目中客户端socket关闭的问题


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int start_up(unsigned short *port){
    int server_sock;
    struct sockaddr_in name;
    server_sock=socket(PF_INET, SOCK_STREAM, 0);
    memset(&name,0,sizeof(name));
    name.sin_family=AF_INET;
    name.sin_port=htons(*port);
    name.sin_addr.s_addr=htonl(INADDR_ANY);
    socklen_t len=sizeof(name);
    bind(server_sock,(struct sockaddr *)&name,sizeof(name));
    if(*port==0){
         getsockname(server_sock, (struct sockaddr *)&name, &len);
         *port=ntohs(name.sin_port);
    }
    listen(server_sock,5);
    return server_sock;
}
int get_line(int sock,char *str,int size){
    int len=0;
    char tmp;
    while (len'\n')
    {
        int n=recv(sock,&tmp,1,0);
        if (n>0)
        {
            if (tmp=='\r')
            {
                n=recv(sock,&tmp,1,MSG_PEEK);
                if (n>0&&tmp=='\n')
                {
                    recv(sock,&tmp,1,0);
                }
                else
                    tmp='\n';
            }
            str[len]=tmp;
            len++;
        }
        else{
            tmp='\n';
            str[len]=tmp;
            len++;
        }
    }
    str[len]='\0';
    return len;
}
void*accept_request(void *arg){
    
    int cgi=0;
    int client_socket=*(int*)arg;
    char buf[1024];
    int len=get_line(client_socket,buf,sizeof(buf));
    char method[20];
    int i=0;
    for (i = 0;buf[i]!=' '&&imethod[i]=buf[i];
    }
    method[i]='\0';
    if (strcasecmp(method,"GET")!=0&&strcasecmp(method,"POST")!=0)
    {
        //wrong;
    }
    while (buf[i]==' ')
        i++;
    char url[1024];
    char query;
    int j=0;
    while (i' ')
    {
        url[j]=buf[i];
        j++;i++;
    }
    url[j]='\0';
    if (!strcasecmp(method,"GET"))
    {
        
        for (i = 0; i < strlen(url)&&url[i]!='?'; i++)
        {
        }
        if (url[i]=='?'){
            url[i]='\0';
            query=1+url;
            cgi=1;
        }
    }
    if (!strcasecmp(method,"POST"))
        cgi=1;
    
    char path[1024];
    sprintf(path,"htdocs%s",url);
    if (path[strlen(path)-1]=='/')
        strcat(path,"index.html");
    struct stat st;
    stat(path, &st);
    if ((st.st_mode & S_IXUSR) ||
        (st.st_mode & S_IXGRP) ||
        (st.st_mode & S_IXOTH))
    {
        cgi=1;
    }
    if (cgi==1)
    {
        execute_cgi(client_socket);
    }
    else
        serve_file(client_socket,path);
    close(client_socket);
    return NULL;
    
    
}
void header(int client,char *filename){
    char buf[1024];
    (void)filename;  /* could use filename to determine file type *///有啥用???
 
    /*正常的 HTTP header */
    strcpy(buf, "HTTP/1.0 200 OK\r\n");
    send(client, buf, sizeof(buf), 0);
    /*服务器信息*/
    strcpy(buf, "Server: jdbhttpd/0.1.0\r\n");
    send(client, buf, sizeof(buf), 0);
    sprintf(buf, "Content-Type: text/html\r\n");
    send(client, buf, sizeof(buf), 0);
    strcpy(buf, "\r\n");
    send(client, buf, sizeof(buf), 0);
}
void cat(int client,FILE *resource){
    char buf[1024];

    fgets(buf, sizeof(buf), resource);
    while (!feof(resource)) {
        send(client, buf, strlen(buf), 0);
        fgets(buf, sizeof(buf), resource);
    }

}
void serve_file(int cli_sock,char *filepath){
    FILE *re;
    char buf[1024];
    int numchar;
    numchar=get_line(cli_sock,buf,sizeof(buf));
    while (numchar>0&&strcmp(buf,"\n"))
    {
        numchar=get_line(cli_sock,buf,sizeof(buf));
    }
    re=fopen(filepath,"r");
    header(cli_sock,filepath);
    cat(cli_sock,re);
    fclose(re);
}
void execute_cgi(int cli_sock,char *method,char *query,char *path){
    int status;
    char buf[1024];
    int numchar;
    int len_content;
    if (strcasecmp(method,"GET")){
        numchar=get_line(cli_sock,buf,sizeof(buf));
        while (numchar>0&&strcmp(buf,'\n'))
            numchar=get_line(cli_sock,buf,sizeof(buf));
    }
    else{
        numchar=get_line(cli_sock,buf,sizeof(buf));
         while (numchar>0&&strcmp(buf,'\n')){
            buf[15]='\0';
            if (!strcmp(buf,"Content-Length:")){
                len_content=atoi(&buf[16]);
            }
            numchar=get_line(cli_sock,buf,sizeof(buf));
         }
    }
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    send(cli_sock, buf, strlen(buf), 0);
    int input[2];
    int output[2];
    pipe(input);
    pipe(output);
    int pid=fork();
    if (fork==0)
    {
        dup2(output[1],1);
        dup2(input[0],0);
        close(output[0]);
        close(input[1]);
        char meth_env[255];
        char que_env[255];
        char len_env[255];
        sprintf(meth_env, "REQUEST_METHOD=%s", method);
        putenv(meth_env);
        if (strcasecmp(method,"GET"))
        {
            sprintf(que_env,"QUERY_STRING=%s",query);
            putenv(que_env);
        }
        else{
            sprintf(len_env,"CONTENT_LENGTH=%d",len_content);
            putenv(len_env);
        }
        execl(path, path, NULL);
        exit(0);
    }
    else{
        close(output[1]);
        close(input[0]);
        char c;
        for (int i = 0; i < len_content; i++)
        {
            recv(cli_sock,&c,1,0);
            write(input[1],&c,1);
        }
        while (read(output[0],&c,1)>0)
        {
            send(cli_sock,&c,1,0);
        }
        close(output[0]);
        close(input[1]);
        waitpid(pid, &status, 0);
    }
    
}
int main(){
    int client_sock=-1;
    int server_sock=-1;
    unsigned short port=4000;
    struct sockaddr_in client_name;
    socklen_t client_name_len = sizeof(client_name);
    pthread_t newthread;
    server_sock=start_up(&port);
    printf("httpd running on port %d\n", port);

    while(1){
    
        client_sock= accept(server_sock, (struct sockaddr *)&client_name,&client_name_len);
        if(pthread_create(&newthread,NULL,accept_request,(void*)(intptr_t)&client_sock)!=0)    {
            perror("pthread_create");
        }
    }
    close(server_sock);
    return 0;
}

模仿写了一个tinyhttpd的c代码 调试过程中在accept_request函数 close(client_socket)关闭了客户端的套接字浏览器就显示The connection was reset ,如果用shutdown(client_socket,0) 代替close函数 ,访问服务器端口,浏览器就会一直处于加载界面 怎么解决呢

shutdown(client_socket,2);
close(client_socket);

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/676070
  • 我还给你找了一篇非常好的博客,你可以看看是否有帮助,链接:tinyhttpd编译错误修改(开源小项目)
  • 除此之外, 这篇博客: TinyHttpd详解中的 TinyHttpd介绍 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

        一个轻量级的C语言HTTP服务端程序,500多行代码实现,具有清晰的结构,是一个良好的服务端入门程序。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^