搭建简单的http服务器

来源:互联网 发布:淘宝借呗 编辑:程序博客网 时间:2024/06/06 06:35

开发语言C++,平台为Linux。
主要流程为:服务器获得请求–>响应并处理请求–>返回结果。

这里写图片描述

这里着重讲怎么处理请求。
主程序在获得一个请求后会开辟一个线程来处理请求
流程图如下。
这里写图片描述

hand_cgi函数流程图
这里写图片描述

cgi程序流程图。
这里写图片描述
代码:

#include"http.h"int ret = 0;void printf_log(string s){        //cout << s << endl;}int init_fd(int socketi, char* str){    sockaddr_in addr;    bzero(&addr, sizeof(addr));    addr.sin_family = AF_INET;    addr.sin_addr.s_addr = htonl(inet_addr(str));    addr.sin_port = htons(PORT);    int err = bind(socketi, (struct sockaddr*)&addr, sizeof(addr));    if (err < 0){        printf_log("bind error");        ret = -1;    }    int on = 0;    setsockopt( socketi, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );    err = listen(socketi, 5);    if (err < 0){        printf_log("listen error");        ret = -1;    }    return socketi;}static int get_line(int fd, char *buf){    char ch = 0;    char next = 0;    int i = 0;    int err = 0;    while (ch != '\n'){        int size = read(fd, &ch, 1);        if (size <= 0){            ch = '\n';        }        if (ch != '\n' && ch != '\r'){            buf[i++] = ch;        }        else{            if (ch == '\r'){                err = recv(fd, &next, 1, MSG_PEEK);                if (err < 0){                    printf_log("recv error");                    return -1;                }                if (next == '\n'){                    err = read(fd, &ch, 1);                    if (err < 0){                         printf_log("recv error");                        return -1;                    }                }//if                ch = '\n';            }        }//else    }//whilebuf[i] = 0;    return 1;}static void clean_header(int fd){    char ch[100] = {0};    get_line(fd, ch);    while (strlen(ch) != 0){        get_line(fd, ch);    }}static int hand_cgi(int fd, char* path, char * argument){    char line[SIZE/2] = {0};    char length[10] = {0};    int i_length = 0;    char method[10] = {0};    if (strlen(argument) == 0){        sprintf(method, "METHOD=POST");        while (get_line(fd, line) > 0){            if (strncmp(line, "Content-Length", 16) == 0){                i_length = atoi(line + 16);                break;            }        }//while        clean_header(fd);        sprintf(length, "Content-Length=%d", i_length);        putenv(length);    }//if    else{        sprintf(method, "METHOD=GET");           char str[100] = {0};        sprintf(str, "QESTRING=%s", argument);        if (putenv(str) < 0){            printf_log("she zhi huai jing cuo wu");            ret = -1;        }        clean_header(fd);    }//else    putenv(method);    //reponse    char request[] = "HTTP/1.0 200 OK\r\n";    write(fd, request, strlen(request));    int _std[2] = {0};    int _std2[2] = {0};    if (pipe(_std) < 0){        printf_log("pipe error");        ret = -1;    }    if (pipe(_std2) < 0){        printf_log("pipe2 error");        ret = -1;    }    pid_t pid = fork();    if (pid < 0){        printf_log("fork error");        ret = -1;        return 0;    }    if (pid == 0){        close(_std[0]);        close(_std2[1]);          dup2(_std[1], 1);          dup2(_std2[0], 0);        execl(path,path, NULL);        cout << "error" << endl;    }    else{        close(_std[1]);        close(_std2[0]);        int ch = 0;        char string[SIZE/2] = {0};        for (int i = 0; i < i_length; i++){            read(fd, &ch, 1);            string[i] = ch;        }        char buf[SIZE/2] = {0};        write(_std2[1], string, strlen(string));        read(_std[2], buf, SIZE/2);        //返回输出        write(fd, buf, strlen(buf));        }        close(_std[0]);        close(_std2[1]);    }}static void get(int fd){        char buf[2*SIZE];    char ch;    int i = 0;    while (read(fd, &ch, 1) > 0){        buf[i++] = ch;    } //   printf("%s\n", buf);}void *handler_in(void *arg){    pthread_detach(pthread_self());    char method[SIZE/2] = {0};    char buf[SIZE] = {0};    char line[SIZE/2] = {0};    char url[SIZE/2] = {0};    char goal[SIZE/2] = {0};    char argument[SIZE] = {0};    int err = 0;    int cgi = 0;    int i = 0;    char request[] = "HTTP/1.1 200 OK\r\n";    //cout << 123 << endl;    err =  get_line((int)arg, line);    if (err < 0){        ret = 1;        goto end;    }    for (i = 0; line[i] != ' '; i++){            method[i] = line[i];    }    i++;    for (int j = 0; line[i] != ' '&&line[i] != '?'; i++){        url[j++] = line[i];    }    //printf("%s\n" ,method);    if (line[i] == '?'){        i++;        for (int j = 0; line[i] != ' '&&line[i] != '?'; i++){             argument[j++] = line[i];        }    }    if (strcasecmp(method, "POSE") != 0 && strcasecmp(method, "GET") != 0){        printf_log("method");        ret = 2;        goto end;    }    if (strcasecmp(method, "POSE") == 0)        cgi = 1;    if (strcasecmp(method, "GET") == 0 && argument[0] != 0)        cgi = 1;    if (strlen(url) == 1 && strcasecmp(url , "/") == 0)        sprintf(goal, "wwwroot/root.html");    else sprintf(goal, "wwwroot%s", url);    //判断文件    struct stat file;    err = stat(goal, &file);    if (err < 0){        ret = 3;        printf_log("file not found");        goto end;    }    if (file.st_mode & S_IFDIR){        //    }    if (file.st_mode & S_IXUSR || file.st_mode & S_IXGRP || file.st_mode & S_IXOTH){        if (0 == cgi){         ret = 4;         printf_log("文件类型与cgi不匹配");         goto end;        }    }    if (1 == cgi){      err =   hand_cgi((int)arg, goal, argument);    }//cgi if    else{    clean_header((int)arg);    write((int)arg, request, strlen(request));    write((int)arg, "\r\n", 2);   int fd = open(goal, O_RDONLY);   err = sendfile((int)arg, fd, 0, file.st_size);        if (err < 0){            ret = 5;            printf_log("sendfile error");            printf("%d, %s\n", errno, strerror(errno));        }    }//cgi elseend: close((int)arg);}

cgi程序示例(2数相加):

#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>#define SIZE 1024using namespace std;int hand(char *q){    char *num = NULL;  char *num_2 = NULL;  int num1 = 0;  int num2 = 0;  while (*q != '=')    q++;    q++;  num = q;  while (*q != '&')    q++;  *q = 0;  num1 = atoi(num);  while (*q != '=')      q++;    q++;  num_2 = q;  num2 = atoi(num_2);    printf("<html>\n");    printf("<head><h2>%d + %d = %d</h2></head>\r\n", num1, num2, num1+num2);    printf("</html>\n");}int main(){    printf("Content-Type:text/html;charset=ISO-8859-1\n\n");               char *p = NULL;      int i_length = 0;    char query_string[SIZE/2] = {0};    char *length = NULL;   p = getenv("METHOD");   if (strcmp(p, "GET") == 0){           char *s = getenv("QESTRING");           memcpy(query_string, s, strlen(s));    }//if   else{       length = getenv("Content-Length");       i_length = atoi(length);       char ch = 0;       for (int i = 0; i < i_length; i++){           ch = getc(0);           query_string[i] = ch;       }   }   hand(query_string);    printf("\n");    return 0;}

运行:
发送请求
这里写图片描述
返回结果:
这里写图片描述

此外,我们可再写一个可以连接mysql数据库的cgi程序,这样我们就可以远程管理数据库了。
cgi程序:

#include<iostream>#include<cstdio>#include<cstdlib>#include<mysql.h>#include<cstring>using namespace std;const int SIZE = 100;//把值赋给相应的参数void static handing(char* &str, char* &query){    while (*query != '=')            query++;    str = ++query;    while (*query != '&'&& *query != 0)        query++;    *query = 0;    query++;}//取值static void hand_query(int &mod, char* &name, int &age, char *&where, char *query){    char *str = NULL;    handing(str, query);    mod = atoi(str);    handing(where, query);    handing(name, query);    if (3 == mod)        return;    handing(str, query);    age = atoi(str);}void find(MYSQL *conn, char *name, char *where){    MYSQL_RES *result;    MYSQL_ROW row;    char buf[100] = {0};    sprintf(buf, "SELECT * FROM %s", where);    mysql_query(conn, buf);    result = mysql_store_result(conn);    if (NULL == result)        cout << "NULL" << endl;    int num_fields = mysql_num_fields(result);    while ((row = mysql_fetch_row(result))){        if (strcmp(row[0], name) == 0)        for (int i = 0; i < num_fields; i++){            printf("%s ", row[i] ? row[i] : "NULL");        }    }    mysql_free_result(result);}int hand(char *query){    int mod = 0;    char *name = NULL;    char buf[100] ={0};    int age = 0;    char *where = NULL;    hand_query(mod, name, age, where, query);    MYSQL *conn = new MYSQL;    conn = mysql_init(NULL);    if (conn == NULL){        printf("ERROR %u: %s\n", mysql_errno(conn), mysql_error(conn));        exit(1);    }    if (mysql_real_connect(conn, "localhost", "root",                            NULL, "tq", 0, NULL, 0)==NULL){        printf("ERROR %u:%s\n", mysql_errno(conn), mysql_error(conn));        exit(1);    }    //这里只列举最简单的find操作    switch(mod){        case 1:creat(conn, name, age, where);        break;        case 2:insert(conn, name, age,where);        break;        case 3:find(conn, name,where);        break;        case 4:modifier(conn, name, age, where);        break;        case 5:my_delete(conn, name, where);        default:        break;    }    mysql_close(conn);}int main(){    printf("Content-Type:text/html;charset=ISO-8859-1\n\n");               char *p = NULL;      int i_length = 0;    char query_string[SIZE/2] = {0};    char *length = NULL;   p = getenv("METHOD");   if (strcmp(p, "GET") == 0){           char *s = getenv("QESTRING");           memcpy(query_string, s, strlen(s));    }//if   else{       length = getenv("Content-Length");       i_length = atoi(length);       char ch = 0;       for (int i = 0; i < i_length; i++){           ch = getc(0);           query_string[i] = ch;       }   }    hand(query_string);    printf("\n");    return 0;}

这里写图片描述
mod表示操作,where是哪个·表,name是人名。
tbq这个表如下:
这里写图片描述
处理请求的结果:
这里写图片描述
前端知识知之甚少,勿怪啊。。
在这里一个简单的http服务器就搭建完成了,但是我们还可以做很多事。比如,当请求过多时效率太低怎么办?再者,我们可以写一个爬虫程序来提高。除此之外,我们可以在深入调研nginx服务器。
源码地址:https://github.com/fengasdf/-http-(由于整合了协程,python爬虫,以及其他程序,可能有点乱)
http服务器运用协程:
http://blog.csdn.net/fengasdfgh/article/details/76688440

原创粉丝点击