Chinaunix首页 | 论坛 | 博客
  • 博客访问: 914141
  • 博文数量: 177
  • 博客积分: 8613
  • 博客等级: 中将
  • 技术积分: 2835
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-12 04:16
文章分类
文章存档

2012年(12)

2011年(24)

2010年(24)

2009年(75)

2008年(42)

我的朋友

分类: LINUX

2010-02-07 19:42:25

   一年前的现在,目标是写个web服务器,现在看来这已经不是太难的事情了,我需要的是大量的时间而已。
   今天在家憋了一下午,用c写了一个小小的webserver,可以实现的功能是接受客户端的请求,将请求中的url取出文件名,传回去,同时设置几个必要的header头,在新请求到达时,使用fork一个子进程的方式应对请求,全部代码如下,写的过程中,sprintf当成了strcat来用,汗,用gdb调试出来才恍然大悟^_^,另外函数比较少,支持的配置文件比较傻瓜化,将来会继续不断地优化,争取用这个webserver的优化来多多学习linux下的socket编程,想想上周开发的连接memcached的客户端程序中,进步挺多的了。
    整个下午都在折腾这个程序,感觉时间过的很快,当然也很充实,边干边学。

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

#define BUF_SIZE 4096

void sig_handle(int signo);
char * parse_client_request( int sockfd, char *buffer, char *request_filename);
int send_header(int sockfd, char *header_send, char *request_filename);
int send_body(int sockfd, char *request_filename);
void parse_server_conf(char *server_conf_file);
void    my_log(char *fmt, ...);

int backlog;
int server_port;
char server_ip[256];
char logfile[256];
char root_directory[256];


void sig_handle(int signo)
{

    printf("received signal:%d\n",signo);
}

int main ( int argc, char *argv[] )
{
    int sockfd,sockfd_client;
    int status;
    struct    sockaddr_in    addr;
    char server_conf_file[256] = "httpd.conf";

    parse_server_conf(server_conf_file);
    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){
        my_log("create socket fd error!\n");
        exit(1);
    }

    bzero(&addr,sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_port=htons(server_port);
    addr.sin_addr.s_addr=inet_addr(server_ip);

    if( bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0 ){
        my_log("bind socket fd error: %s\n",strerror(errno));
        exit(1);
    }

    if( listen(sockfd, backlog) < 0 ){
        my_log("listen socket fd error: %s\n",strerror(errno));
        exit(1);
    }

    // chroot to htdocs
    if( chroot(root_directory) < 0 ){
        my_log("chroot error: %s\n",strerror(errno));
        exit(1);
    }

    while(1){

        if((sockfd_client = accept(sockfd, NULL, NULL)) < 0){
            my_log("accept socket fd error: %s\n",strerror(errno));
            continue;
        }
        //signal(SIGCHLD, sig_handle);
        pid_t pid;
        if((pid = fork()) < 0){
            my_log("fork error: %s\n",strerror(errno));
        }else if(pid == 0){
            // read from client
            char buffer[BUF_SIZE];
            char request_filename[BUF_SIZE];
            parse_client_request(sockfd_client, buffer, request_filename);
            if(request_filename == NULL){
                my_log("can not get the filename from uri\n");
            }

            char header_send[BUF_SIZE];
            send_header(sockfd_client, header_send, request_filename);
            send_body(sockfd_client, request_filename);

            close(sockfd_client);
            exit(0);
        }else{
            waitpid(pid, &status, 0);
            close(sockfd_client);
        }
    }
    return EXIT_SUCCESS;
}                               /* ----------  end of function main  ---------- */

char * parse_client_request( int sockfd, char *buffer, char *request_filename)
{
    char *split = " ";
    char *token;
    recv(sockfd, buffer, BUF_SIZE, 0);

    if((token = strtok(buffer, split)) != NULL)
        token = strtok(NULL, split);
    strcpy(request_filename, token);
    return token;
}

int send_header(int sockfd, char *header_send, char *request_filename){
    FILE *fp;
    int status_num;
    char buffer[BUF_SIZE];
    char status[BUF_SIZE];
    char *status_str;
    char *version = "HTTP/1.1";
    char *server = "Server: httpd-feng";

    fp = fopen(request_filename,"r");
    if(fp == NULL){
        status_num = 404;
        status_str = "NOT FOUND";
    }else{
        status_num = 200;
        status_str = "OK";
    }

    sprintf(status,"%s %d %s\r\n",version, status_num, status_str);
    strcpy(buffer, status);
    strcat(buffer, server);
    strcat(buffer,"\r\n");
    strcat(buffer,"Content-Type: text/html");
    strcat(buffer,"\r\n");
    strcat(buffer,"\r\n");

    if( send(sockfd, buffer, strlen(buffer), 0) < 0 ){
        my_log("sent header error!\n");
        return -1;
    }

    my_log("send_header:%s\n",buffer);

    return 0;

}

int send_body(int sockfd, char *request_filename){
    FILE *fp;
    char buffer[BUF_SIZE];
    int read_n;

    fp = fopen(request_filename,"r");
    if(fp == NULL){
        strcpy(buffer,"NOT FOUND");
        if( send(sockfd, buffer, strlen(buffer), 0) < 0 ){
            my_log("sent body error!\n");
            return -1;
        }
    }
    else
    {
        read_n = fread(buffer, 1, BUF_SIZE-1, fp);
        if(read_n > 0){
            buffer[read_n] = '\0';
            if( send(sockfd, buffer, strlen(buffer), 0) < 0 ){
                my_log("sent header error!\n");
                return -1;
            }
        }
    }
    return 0;
}

void parse_server_conf(char *server_conf_file)
{
    FILE *fp;
    char buffer[BUF_SIZE];
    char *split = " \t\n";
    char *token;
    fp = fopen(server_conf_file,"r");
    if(fp == NULL){
        perror(server_conf_file);
        exit(1);
    }

    while(fgets(buffer, BUF_SIZE, fp) != NULL){
        if(buffer[0] == '#')
            continue;
        if(strstr(buffer,"backlog") != NULL){
            if((token = strtok(buffer, split)) != NULL)
                token = strtok(NULL, split);
            backlog = atoi(token);
        }
        else if(strstr(buffer,"server_port") != NULL){
            if((token = strtok(buffer, split)) != NULL)
                token = strtok(NULL, split);
            server_port = atoi(token);

        }
        else if(strstr(buffer,"server_ip") != NULL){
            if((token = strtok(buffer, split)) != NULL)
                token = strtok(NULL, split);
            strcpy(server_ip, token);

        }
        else if(strstr(buffer,"logfile") != NULL){
            if((token = strtok(buffer, split)) != NULL)
                token = strtok(NULL, split);
            strcpy(logfile, token);

        }
        else if(strstr(buffer,"root_directory") != NULL){
            if((token = strtok(buffer, split)) != NULL)
                token = strtok(NULL, split);
            strcpy(root_directory, token);

        }


    }


}

void    my_log(char *fmt, ...)
{
    va_list args;
    FILE *file = fopen(logfile, "a+");

    if (file) {

        char timestamp[32];
        time_t t;

        time(&t);
        strftime(timestamp, sizeof(timestamp), "[%d/%b/%Y:%H:%M:%S %z]",
                localtime(&t));
        fprintf(file, "%s: ", timestamp);

        va_start(args, fmt);
        vfprintf(file, fmt, args);
        va_end(args);

        fclose(file);
    }

}

阅读(855) | 评论(0) | 转发(0) |
0

上一篇:2009总结/2010展望

下一篇:开始潜心看thttpd

给主人留下些什么吧!~~