基於http的在線版日期計算器+雲筆記

1、HTTP概念

超文本傳輸協議(HTTP,HyperText Transfer Protocol)是互聯網上應用最爲廣泛的一種網絡協議。所有的WWW文件都必須遵守這個標準。

1、http的請求報文格式

這裏寫圖片描述

2、http的響應報文格式

這裏寫圖片描述

3、http服務器基於傳輸層的TCP協議編寫

TCP協議保證了http可靠性

4、代碼思路:

這裏寫圖片描述

5、部分代碼:

1、監聽套接字的創建

int startup(const char *ip, int port)
{
    int sock = socket(AF_INET,SOCK_STREAM, 0);
    if(sock < 0){
        perror("sock");
        exit(2);
    }
    struct sockaddr_in local;
    local.sin_family = AF_INET;//
    local.sin_port = htons(port);
    local.sin_addr.s_addr = inet_addr(ip);
    if( bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0 ){
        perror("bind");
        exit(3);
    }
    if( listen(sock, 5) < 0 ){
        perror("listen");
        exit(4);
    }
    return sock;
}

2、請求行分析處理

void *handler_request(void *arg)
{
    int sock = (int)arg;//數據交互的socket
    char buf[SIZE]; 
    int err_code = 200;//正常狀態碼
    char method[SIZE/10];//存儲請求方式
    char url[SIZE];//
    int i, j;
    int cgi = 0;//標記
    char *query_string = NULL;//GET方式的參數
    char path[SIZE];//訪問文件的路徑
    // read line
    int len = get_line(sock, buf, sizeof(buf));
    if(len <= 0)
    {
        //printf("get_line err\n");
        err_code = 404;
        goto end;
    }
    //detach get/post
    i = 0, j = 0;
    while(i < sizeof(method) &&\
            j < sizeof(buf) &&\
            buf[j] != ' ')
    {
        method[i] = buf[j];
        i++,j++;
    }
    //printf("%s",&buf[j]);
    method[i] = '\0';
    if( strcasecmp(method, "GET") && strcasecmp(method, "POST") )
    {
        printf("is no get and post\n");
        err_code = 404;
        goto end;
    }
    while(buf[j] == ' ')
    {
        j++;
    }
    if( !strcasecmp(method, "POST") )
    {
        cgi = 1;
    }
    //detach url
    i = 0;
    while(i < sizeof(url) &&\
            j < sizeof(buf) &&\
            buf[j] != ' ')
    {
        url[i] = buf[j];
        i++;
        j++; 
    }
    url[i] = '\0';
    query_string = url;
    while( *query_string )
    {
        if(*query_string == '?')
        {
            cgi = 1;
            *query_string = '\0';
            query_string++;//query_string爲GET的參數
            break;
        }
        query_string++; 
    }
    sprintf(path, "wwwroot%s", url);//訪問相對路徑文件名
    if( path[strlen(path)-1] == '/')
    {
        strcat(path, "index.html");
    }
    struct stat st;
    if(stat(path, &st) < 0){
        perror("stat");//文件不存在
        err_code = 404;
        goto end;
    }else{
        if(S_ISDIR(st.st_mode)){//dir
            strcat(path, "/index.html");
        }else if( (st.st_mode & S_IXUSR) ||\
                  (st.st_mode & S_IXGRP) ||\
                  (st.st_mode & S_IXOTH) ){
            cgi = 1;//具有可執行權限文件
        }
        else{}
        if(cgi == 1){
            //exe_cgi
            exe_cgi(sock, path, method, query_string);
        }
        else{
            handler_header(sock);
            err_code = echo_www(sock, path, st.st_size);
        }
    }
end:
    echo_clinet(sock, err_code);//錯誤狀態處理
    close(sock);
    return (void *)0;
}

3、CGI部分

int main()
{
    int content_length = 0;
    char *query_string = 0;
    char buf[1024] = {0};
    char *path = getenv("METHOD");//獲得請求方式的環境變量
    if(strcasecmp(path, "GET") == 0 )//判斷請求方式是GET
    {
        query_string = getenv("QUERY_STRING");//直接獲得參數
    }else{
        content_length = atoi(getenv("CONTENT_LENGTH"));//獲得參數的字符個數
        int i = 0;
        for(i=0; i<content_length; ++i)
        {
            read(0, &buf[i], 1);//從標準輸入中讀(已經從管道中重定向)
        }
        query_string = buf;//參數得到
    }
    //printf("<h1>%s<br></h1>",__DATE__);
    fun(query_string);//參數交給fun函數處理
    return 0;
}

4、HTML、日期計算的編寫
這裏就不寫出日期計算了,HTML可以從是從網上(w3school)找的模板

6、結果演示:

這裏寫圖片描述
這裏寫圖片描述

7、總結

1、利用的是多線程的方式處理每個鏈接,這樣當訪問數量達到一定的上限時,性能就會下降
解決方案:利用多路轉接epoll的方式改進
2、http是短鏈接的方式、使多次訪問的效率下降
解決方案:利用session機制,添加定時器,當一個鏈接在一段時間內是不被斷開、當長時間沒有再次訪問時、服務器自動斷開連接

參考文獻:linux高性能服務器編程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章