鬼混_txL 2023-04-19 19:03 采纳率: 100%
浏览 22
已结题

C/C++ http服务器返回html页面请求js css问题

改了一个简单的http服务器遇到一个问题
浏览器请求并成功返回html文件,但是HTML页面中需要加载一些js css文件等,抓包显示服务器能接收到相应的请求并返回了相应的js css文件,但是浏览器报错如图

img

.C文件

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include "httpsever.h"

#define SERVER_PORT 8800
#define ON_DEBUG

const char month_tab[48] =
    "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";
const char day_tab[] = "Sun,Mon,Tue,Wed,Thu,Fri,Sat,";

time_t current_time;
static int debug = 1;

void* do_http_request(void *client_sock); //http处理线程函数
int get_line(int sock, char *buf, int size);
int Parse_Request(struct Request *request); 
void Process_Request(struct Request *request);
void GET_Process(struct Request *request);
void POST_Process(struct Request *request);
int Get_FILE(struct Request *request);
int do_http_Response(struct Request *request);
int  Headers(struct Request *request);
void Send_Body(struct Request *request);
void rfc822_time_buf(char *buf, time_t s);

void not_found(int client_sock);//404 
void unimplemented(int client_sock);//500
void bad_request(int client_sock); //400
void inner_error(int client_sock);



int main(void){

    int sock;
    struct sockaddr_in server_addr;


    //创建socket
    sock = socket(AF_INET, SOCK_STREAM, 0);
    int opt =1;
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

    //2.清空标签,写上地址和端口号
    bzero(&server_addr, sizeof(server_addr));

    server_addr.sin_family = AF_INET;//选择协议族IPV4
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//监听本地所有IP地址
    server_addr.sin_port = htons(SERVER_PORT);//绑定端口号80

    //绑定socket
    bind(sock, (struct sockaddr *)&server_addr,  sizeof(server_addr));

    //监听socket
    listen(sock, 128);
    time(¤t_time);

    int done =1;

    while(done){
        struct sockaddr_in client;
        int client_sock, len, i;
        char client_ip[64];
        char buf[256];
        pthread_t id;
        int* pclient_sock = NULL;

        socklen_t  client_addr_len;
        client_addr_len = sizeof(client);
        #ifdef ON_DEBUG
        printf("\n等待客户端的连接\n");
        #endif
        client_sock = accept(sock, (struct sockaddr *)&client, &client_addr_len);
        
        //打印客服端IP地址和端口号
        printf("\nclient ip: %s\t port : %d\n",
                 inet_ntop(AF_INET, &client.sin_addr.s_addr,client_ip,sizeof(client_ip)),
                 ntohs(client.sin_port));
             
        /*处理http 请求,读取客户端发送的数据*/
        // do_http_request(client_sock);
        // do{
        //     len = get_line(client_sock, buf, sizeof(buf));
        //     if(debug) printf("heard: %s\n", buf);
        // }while(len>0);

        //启动线程处理http 请求
        pclient_sock = (int *)malloc(sizeof(int));
        *pclient_sock = client_sock;
        
        pthread_create(&id, NULL, do_http_request, (void *)pclient_sock);
        
        // close(client_sock);

    }
    close(sock);
    return 0;
}



/***************************************************
 *请求处理线程 :do_http_request(void* pclient_sock);
 *pclient_sock : 客户端socket
****************************************************/
void* do_http_request(void* pclient_sock){
    int len = 0;
    char buf[256];
    
    struct timeval timeout;
    struct Request request,*ptrrequest;
    // memset(&request,0,sizeof(request));
    timeout.tv_sec = READ_TIMEOUT ;
    timeout.tv_usec = 0 ;

    /*初始化请求结构体默认参数*/
    ptrrequest = &request;
    request.client_sock = *(int *)pclient_sock;
    request.readTumeout = &timeout;
    request.status = 0 ;                /* see #defines.h */
    request.keepalive = 0;              /* keepalive status 1 keepalive , 0 closelive */
    request.fp = NULL ;                  /*descriptor of requested file*/
    request.data =NULL ;
    request.send_buf = NULL;
    
    /*设置等待超时*/
    if (setsockopt(request.client_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) {
        printf("setsockopt failed:");
    }

    do{
        request.Request_Length = 0 ;            /*Content-Length*/
        request.send_buf_len = 0 ;
        memset(request.path,0,256);                /* pathname of requested file */
        
        int ret = Parse_Request(ptrrequest);    /*解析客户端http请求*/
        if(ret == 0)
        {
            Process_Request(ptrrequest);        /*处理客户端http请求*/
        }
        if(request.data) {free(request.data); request.data = NULL;}
        if(request.send_buf) {free(request.send_buf); request.send_buf = NULL;}
    }while(request.keepalive == 1);
    

    close(request.client_sock);
    if(pclient_sock) free(pclient_sock);//释放动态分配的内存    
    return NULL;
}

/***************************************************
 *解析客户端请求 :do_http_request(int client_sock);
 *struct Request *request : 客户端请求结构体
****************************************************/
int Parse_Request(struct Request *request)
{
    int len = 0;
    char buf[256],tempbuf[256];

    len = get_line(request->client_sock, buf, sizeof(buf));
    #ifdef ON_DEBUG
            printf("请求第一行: %s\n", buf);
    #endif
    if(len > 0){//读到了请求行
        /*获取请求方式GET or POST*/
        int i=0, j=0;
        while(!isspace(buf[j]) && (i<sizeof(tempbuf)-1)){
            tempbuf[i] = buf[j];
            i++;
            j++;
        }
        tempbuf[i] = '\0';
        // #ifdef ON_DEBUG
        //     printf("request method: %s\n", tempbuf);
        // #endif
        if(strcmp("GET",tempbuf)==0)
        {
            request->method = GET;
        }else if(strcmp("POST",tempbuf)==0)
        {
            request->method = POST;
            // #ifdef ON_DEBUG
            //     printf("method: %s\n", tempbuf);
            // #endif
        }

        while(isspace(buf[j]))
        {
            j++;
        };//跳过白空格
        i = 0;

        /*读取path*/
        while(!isspace(buf[j]) && (i<sizeof(request->path)-1)){
            request->path[i] = buf[j];
            i++;
            j++;
        }
        request->path[i] = '\0';
        #ifdef ON_DEBUG
            printf("url: %s\n", request->path);
        #endif

        /*处理path中的?并将读取URL中的数据放到request->data堆空间*/
        char *pos = strchr(request->path, '?');
        if(pos){
            *pos = '\0';
            pos++;
            request->data = (char *)malloc(sizeof(pos)+1);
            memset(request->data,0,sizeof(pos)+1);
            strcpy(request->data,pos);
            memset(pos,0,sizeof(pos));
        #ifdef ON_DEBUG
            printf("url data: %s\n", request->data);
        #endif
        }

        /*判断请求文件类型*/
        if(strncmp("/js",request->path,3) ==0 )
        {
            request->Content_Type = JS ;
        }else if(strncmp("/css",request->path,4) ==0 )
        {
            request->Content_Type = CSS ;
        }else if(strncmp("/img",request->path,4) ==0 )
        {
            request->Content_Type = PNG ;
        }else if(strncmp("/JPG",request->path,4) ==0 )
        {
            request->Content_Type = JPG ;
        }else if(strncmp("/SET",request->path,4) ==0 )
        {
            request->Content_Type = SET ;  //设置请求
        }else if(strncmp("/QUERY",request->path,6) ==0 )
        {
            request->Content_Type = QUERY ; //查询请求
        }else{
            request->Content_Type = HTML ;
        }

        /*请求头部除第一行剩余数据处理,获取request->data*/
        do{
            memset(buf,0,sizeof(buf));
            len = get_line(request->client_sock, buf, sizeof(buf));
        #ifdef ON_DEBUG
            printf("%s\n", buf);
        #endif

            if(strncmp("Content-Length",buf,14) == 0) //读取Content-Length参数初始化数据堆空间
            {
                request->Request_Length = atoi(&buf[16]);
            #ifdef ON_DEBUG
                printf("request->Length: %d\n", request->Request_Length);
            #endif
                if(request->Request_Length>0)
                request->data = (char *)malloc(request->Request_Length+1);
                memset(request->data,0,request->Request_Length+1);
            }
            else if(strncmp("Connection",buf,10) == 0)  //读取Connection参数
            {
                if(strncmp("keep-alive",&buf[12],10) == 0)
                {
                    request->keepalive = 1;
                }else{
                    request->keepalive = 0;
                }
            }
            
        }while(len>0);

        /*读取请求数据实体*/
        if(request->Request_Length>0)
        {
            len = read(request->client_sock, request->data, request->Request_Length);
            #ifdef ON_DEBUG
                 printf("data: %s\n", request->data);
            #endif
        }

    }else{
        request->keepalive = 0;
        return -1;
    }
    return 0;
}



/***************************************************
 *请求处理 :Process_Request(struct Request *request);
 *struct Request *request : 客户端请求结构体
****************************************************/
void Process_Request(struct Request *request)
{
    switch(request->method)
    {
        case GET :
            //GET....
            GET_Process(request);
        break;
        case POST :
            //POST....
            POST_Process(request);
        break;
    }
}

//返回值: -1 表示读取出错, 等于0表示读到一个空行, 大于0 表示成功读取一行
int get_line(int sock, char *buf, int size){
    int count = 0 ;
    char ch = '\0';
    int len = 0;
    
    
    while( (count<size - 1) && ch!='\n'){
        len = read(sock, &ch, 1);
        
        if(len == 1){
            if(ch == '\r'){
                continue;
            }else if(ch == '\n'){
                //buf[count] = '\0';
                break;
            }
            
            //这里处理一般的字符
            buf[count] = ch;
            count++;
            
        }else if( len == -1 ){//读取出错
            perror("read failed");
            count = -1;
            break;
        }else {// read 返回0,客户端关闭sock 连接.
            fprintf(stderr, "client close.\n");
            count = -1;
            break;
        }
    }
    
    if(count >= 0) buf[count] = '\0';
    
    return count;
}


void GET_Process(struct Request *request)
{
    char temppath[256] = {0};
    strcat(temppath,"./www");
    if(strcmp("/",request->path) == 0) //GET请求空路劲时默认请求login.html
    {
        strcat(request->path,"login.html");
    }
    
    if(request->Content_Type!=SET && request->Content_Type!=QUERY) 
    {//请求文件
        strcat(temppath,request->path);
        memcpy(request->path,temppath,strlen(temppath));
        int ret = Get_FILE(request);
        if(ret == -1)
        return ;
    }

    do_http_Response(request);
}


int do_http_Response(struct Request *request)
{
    if(request->Content_Type == SET || request->Content_Type == QUERY)
    {
        //进行设置或者查询任务并且返回,回复信息长度和回复信息
    }

    int ret = Headers(request);

    if(!ret)
    {
        Send_Body(request); 
    }
    if(request->fp!=NULL)
    {
        fclose(request->fp);
        request->fp = NULL;
    }
}

/****************************
 *返回关于响应文件信息的http 头部
 *输入: 
 *     client_sock - 客服端socket 句柄
 *     resource    - 文件的句柄 
 *返回值: 成功返回0 ,失败返回-1
******************************/
int  Headers(struct Request *request){
    struct stat st;
    int fileid = 0;
    char tmp[64];
    char buf[1024]="HTTP/1.0 200 OK\r\nDate: "
        "                             "
        "\r\nServer: web Server\r\n";

    rfc822_time_buf(buf + 23, 0);

    // strcpy(buf, "HTTP/1.0 200 OK\r\n");
    // strcat(buf, "Server: web Server\r\n");
    switch(request->Content_Type)
    {
        case JPG :
            strcat(buf, "Content-Type: image/jpeg\r\n");
            break;
        case CSS :
            strcat(buf, "Content-Type: text/css\r\n");
            break;
        case JS :
            strcat(buf, "Content-Type: text/javascript\r\n");
            break;
        case PNG :
            strcat(buf, "Content-Type: image/png\r\n");
            break;
        default :
            strcat(buf, "Content-Type: text/html\r\n");
            break;
    }
    
    if(request->keepalive == 1)
    {
        strcat(buf, "Connection: Keep-Alive\r\n");
    }else{
        strcat(buf, "Connection: Close\r\n");
    }
    snprintf(tmp, 64, "Keep-Alive: timeout=%ld\r\n", request->readTumeout->tv_sec);
    strcat(buf, tmp);
    memset(tmp,0,64);
    if(request->Content_Type == SET || request->Content_Type == QUERY)
    {
        snprintf(tmp, 64, "Content-Length: %d\r\n\r\n", request->send_buf_len);
    }else{
        fileid = fileno(request->fp);
        if(fstat(fileid, &st)== -1){
            inner_error(request->client_sock);
            return -1;
        }
        snprintf(tmp, 64, "Content-Length: %ld\r\n\r\n", st.st_size);
    }
    strcat(buf, tmp);
    
    #ifdef ON_DEBUG
        printf("Send Header:\n%s", buf);
    #endif
    
    if(send(request->client_sock, buf, strlen(buf), 0)<0){
        fprintf(stderr, "send failed. data: %s, reason: %s\n", buf, strerror(errno));
        return -1;
    }
    
    return 0;
}

/****************************
 *说明:实现文件的内容按行读取并送给客户端
 ****************************/
void Send_Body(struct Request *request){    
    char buf[1024];
    int count = 1;
    if(request->Content_Type == SET || request->Content_Type == QUERY)
    {
        int len = write(request->client_sock, request->send_buf, request->send_buf_len);    
        while(len<0 && count<3){//发送body 的过程中出现问题,重传
                len = write(request->client_sock, request->send_buf, request->send_buf_len);
                count ++;
            }
    }
    else{
        fgets(buf, sizeof(buf), request->fp);
        while(!feof(request->fp)){
            int len = write(request->client_sock, buf, strlen(buf));
            count = 1;
            while(len<0 && count<3){//发送body 的过程中出现问题,重试
                fprintf(stderr, "send body error. reason: %s\n", strerror(errno));
                len = write(request->client_sock, buf, strlen(buf));
                count ++;
            }
            if(count == 3 && len<0 )
            {
                break;
            }

            #ifdef ON_DEBUG
                fprintf(stdout, "%s", buf);
            #endif
            fgets(buf, sizeof(buf), request->fp);
        }
    }
    
}



void POST_Process(struct Request *request)
{
    //若果请求路径为/(默认是HTML类型)
}


int Get_FILE(struct Request *request)
{
    struct stat  st;
    if(stat(request->path, &st)==-1){//文件不存在或是出错
        not_found(request->client_sock);
        return -1;
    }else {//文件存在
        // if(S_ISDIR(st.st_mode)){ //判断request->path是否是,目录是为真
        // }
        request->fp = fopen(request->path, "r");
        if(request->fp == NULL){
        not_found(request->client_sock);
        return -1;
        }    
    }
}



/* rfc822 (1123) time is exactly 29 characters long
 * "Sun, 06 Nov 1994 08:49:37 GMT"
 */

void rfc822_time_buf(char *buf, time_t s)
{
    struct tm *t;
    char *p;
    unsigned int a;

    if (!s) {
        t = gmtime(¤t_time);
    } else
        t = gmtime(&s);

    p = buf + 28;
    /* p points to the last char in the buf */

    p -= 3;
    /* p points to where the ' ' will go */
    memcpy(p--, " GMT", 4);

    a = t->tm_sec;
    *p-- = '0' + a % 10;
    *p-- = '0' + a / 10;
    *p-- = ':';
    a = t->tm_min;
    *p-- = '0' + a % 10;
    *p-- = '0' + a / 10;
    *p-- = ':';
    a = t->tm_hour;
    *p-- = '0' + a % 10;
    *p-- = '0' + a / 10;
    *p-- = ' ';
    a = 1900 + t->tm_year;
    while (a) {
        *p-- = '0' + a % 10;
        a /= 10;
    }
    /* p points to an unused spot to where the space will go */
    p -= 3;
    /* p points to where the first char of the month will go */
    memcpy(p--, month_tab + 4 * (t->tm_mon), 4);
    *p-- = ' ';
    a = t->tm_mday;
    *p-- = '0' + a % 10;
    *p-- = '0' + a / 10;
    *p-- = ' ';
    p -= 3;
    memcpy(p, day_tab + t->tm_wday * 4, 4);
}




#if 1


void not_found(int client_sock){
    const char * reply = "HTTP/1.0 404 NOT FOUND\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML lang=\"zh-CN\">\r\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\
<HEAD>\r\n\
<TITLE>NOT FOUND</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
    

文件不存在!\r\n\

The server could not fulfill your request because the resource specified is unavailable or nonexistent.\r\n\ </BODY>\r\n\ </HTML>"; int len = write(client_sock, reply, strlen(reply)); if(debug) fprintf(stdout, reply); if(len <=0){ fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno)); } } void unimplemented(int client_sock){ const char * reply = "HTTP/1.0 501 Method Not Implemented\r\n\ Content-Type: text/html\r\n\ \r\n\ <HTML>\r\n\ <HEAD>\r\n\ <TITLE>Method Not Implemented</TITLE>\r\n\ </HEAD>\r\n\ <BODY>\r\n\

HTTP request method not supported.\r\n\ </BODY>\r\n\ </HTML>"; int len = write(client_sock, reply, strlen(reply)); if(debug) fprintf(stdout, reply); if(len <=0){ fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno)); } } void bad_request(int client_sock){ const char * reply = "HTTP/1.0 400 BAD REQUEST\r\n\ Content-Type: text/html\r\n\ \r\n\ <HTML>\r\n\ <HEAD>\r\n\ <TITLE>BAD REQUEST</TITLE>\r\n\ </HEAD>\r\n\ <BODY>\r\n\

Your browser sent a bad request!\r\n\ </BODY>\r\n\ </HTML>"; int len = write(client_sock, reply, strlen(reply)); if(len<=0){ fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno)); } } void inner_error(int client_sock){ const char * reply = "HTTP/1.0 500 Internal Sever Error\r\n\ Content-Type: text/html\r\n\ \r\n\ <HTML lang=\"zh-CN\">\r\n\ <meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\ <HEAD>\r\n\ <TITLE>Inner Error</TITLE>\r\n\ </HEAD>\r\n\ <BODY>\r\n\

服务器内部出错.\r\n\ </BODY>\r\n\ </HTML>"; int len = write(client_sock, reply, strlen(reply)); if(debug) fprintf(stdout, reply); if(len <=0){ fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno)); } } #endif

#ifndef HTTPSEVER
#define HTTPSEVER

/*请求类型*/
#define GET     1
#define POST    2

/*请求文件类型*/
#define JPG     1
#define CSS     2
#define JS      3
#define HTML    4
#define PNG     5
#define SET     6 //设置请求/SET
#define QUERY   7 //查询请求/QUERY

#define READ_TIMEOUT 3 /*read超时时间*/

#include <stdio.h>
#include <sys/time.h> 
struct Request {                /* pending requests */
    int client_sock;            /* client's socket fd */
    int method;                 /* M_GET, M_POST, etc. */
    int status;                 /* see #defines.h */
    int keepalive;              /* keepalive status 1 keepalive , 0 closelive */
    int Request_Length;                 /*Content-Length*/
    int send_buf_len;
    int Content_Type;           /*Type of requested file*/
    char path[256];             /* pathname of requested file */
    FILE * fp;                  /*descriptor of requested file*/
    char *data;
    char *send_buf;
    struct timeval *readTumeout;


};

#endif

  • 写回答

2条回答 默认 最新

  • 鬼混_txL 2023-04-20 10:00
    关注

    js css 加载问题的解决了,sendbody函数发送文件while逻辑有问题最后一行读出来没发送,现在png和jpg文件响应还是有问题

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 4月28日
  • 已采纳回答 4月20日
  • 创建了问题 4月19日

悬赏问题

  • ¥15 准备学习小程序搭建,谁能手把手的教我啊?
  • ¥15 关于#嵌入式硬件#的问题:树莓派第一天重装配置python和opencv后第二天打开就成这样,瞎捣鼓搞出来文件夹还是没把原来的界面调回来
  • ¥20 Arduino 循迹小车程序电路出错故障求解
  • ¥20 Arduino 循迹小车程序电路出错故障求解
  • ¥100 AT89C52单片机C语言调试之后再回答
  • ¥15 AT89C52单片机C语言串口助手发送数据包返回值
  • ¥15 C++数组中找第二小的数字程序纠错
  • ¥50 MATLAB APP 制作出现问题
  • ¥15 wannier复现图像时berry曲率极值点与高对称点严重偏移
  • ¥15 利用决策森林为什么会出现这样·的问题(关键词-情感分析)