C语言学习web服务器小实例

service.c

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctype.h>
#include <strings.h>
#include <string.h>
#include <sys/stat.h>
#include <pthread.h>
#include <sys/wait.h>
#include <stdlib.h>

#define SERVER_STRING "Server: xx\r\n"

void *accept_request();
void serve_file();
void headers();
void cat();
void execute_cgi();

void *accept_request(int client)
{
    int recvbytes;
    char buf[1024];
    char path[512];
    if((recvbytes=recv(client,buf,1024,0))==-1)  
    {  
        perror("recv error");exit(1);  
    }
    buf[recvbytes]='\0';
    printf("%s\n", buf);
    /*
    这里输出,不对请求做出处理,直接测试打开静态和cgi
    */
    // strcat(path, "index.html");
    // serve_file(client, path);
    strcat(path, "cgi.py");
    execute_cgi(client,path);
    close(client);
}

void serve_file(int client,const char *filename)
{
    FILE *resource = NULL;
    char buf[1024];
    resource=fopen(filename,"r");
    if (resource == NULL)
    {
        perror("not found");exit(1);
    }
    else
    {
        headers(client);
        cat(client,resource);
    }
    fclose(resource);
}

void execute_cgi(int client, const char *path)
{
    // char buf[1024];
    int cgi_output[2];
    // int cgi_input[2];
    int status;
    char c;
    pid_t pid;
    // headers(client);//输出表头不是强行要求
    if (pipe(cgi_output)<0)
    {
        perror("pipe error");
        exit(0);
    }

    if ((pid=fork())<0)
    {
        perror("fork error");
        exit(0);
    }
    if (pid==0)
    {
        char meth_env[255];
        char query_env[255];
        
        dup2(cgi_output[1],1);
        close(cgi_output[0]);

        /*设置 request_method 的环境变量*/
        sprintf(meth_env, "REQUEST_METHOD=%s","method");
        putenv(meth_env);
        sprintf(query_env, "QUERY_STRING=%s","query_string");
        putenv(query_env);

        execl(path,NULL);
        printf("path=%s",path);
        //如果看到页面输出path=...,说明path传入的值不对。
        //因为execl输出占用了那管道,所以后面应该不输出。
    
        exit(0);
    }
    else
    {
        close(cgi_output[1]);
        while(read(cgi_output[0],&c,1)>0)
            send(client,&c,1,0);
        // printf("success\n");
        close(cgi_output[0]);
        waitpid(pid,&status,0);
    }
}

void headers(int client)
{
    char buf[1024];
    strcpy(buf,"HTTP/1.0 200 OK\r\n");
    send(client,buf,strlen(buf),0);

    strcpy(buf, SERVER_STRING);
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "Content-Type: text/html\r\n");
    send(client, buf, strlen(buf), 0);
    strcpy(buf, "\r\n");
    send(client, buf, strlen(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);
    }
}

int main(int argc, char const *argv[])
{
    int sockfd,client_fd;
    u_short port=8888;
    struct sockaddr_in my_addr,it_addr;
    if ((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1)
    {
        perror("socket error");exit(1);
    }
    memset(&my_addr,0,sizeof(my_addr));
    my_addr.sin_family=AF_INET;
    my_addr.sin_port=htons(port);
    my_addr.sin_addr.s_addr=htonl(INADDR_ANY);

    if (bind(sockfd,(struct sockaddr *)&my_addr, sizeof(my_addr))==-1)
    {
        perror("bind error");exit(1);
    }

    if (listen(sockfd,5)==-1)  
    {  
        perror("listen error");exit(1);  
    }
    int sin_size= sizeof (my_addr);  
    pthread_t newthread;
    while(1)
    {
        if ((client_fd=accept(sockfd,(struct sockaddr *)&it_addr,&sin_size))==-1)  
        {  
            perror("accept error");exit(1);
        }
        if (pthread_create(&newthread , NULL, (void *)accept_request, (int *)client_fd) != 0)
            perror("pthread_create");
    }
    close(sockfd);
    return 0;
}
gcc service.c -o bird -lpthread

编译出执行文件。

cgi.py测试cgi输出

#!/usr/bin/env python
import os
for param in os.environ.keys():
	print "<b>%20s</b>: %s<\br>" % (param, os.environ[param])
print os.environ['QUERY_STRING']
print "xxcgi.py"
打开浏览器输入服务器地址和端口测试即可。

附:需要了解C语言socket,进程,线程,以及http通信基本原理。

需要学习了解CGI,想进一步学习的可了解apache和ngxin服务器。

参考:CGI与FastCGI区别-》http://www.cnblogs.com/wanghetao/p/3934350.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值