简单HTTP服务器(select模型)

server.c

<pre name="code" class="cpp">#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <signal.h>

#define SERVER_NAME "IAMCAP-SERVER"
#define PROTOCOL    "HTTP/1.1"
#define REQUESTLEN 4096
#define RESPONSELEN  1024000

#define LISTENNUM 5

#define TIMELEN 55
#define TEMPLEN 100
#define BUFFERLEN 1024

#define HOMEPATH  "/Users/iamcap/http/showhttp/"

static char* add_header(int , char *, char *, off_t , char *, int );
void parsedata(char*,int);

int main(int argc, char **argv){
    if(argc <=2){
        printf("usage: %s ip_address port_number\n", (argv[0]));
        return 1;
    }
    const char *ip = argv[1];
    int port = atoi(argv[2]);
    
    //initialize the struct

    
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);
    
    //reuse the port
    
    int sock = socket(PF_INET, SOCK_STREAM, 0);
    assert( sock >= 0);
    int opt = 1;
    setsockopt(sock, SOL_SOCKET,SO_REUSEADDR, &opt, sizeof(opt));
    
    int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));
    assert(ret != -1);
    
    printf("listening ...\n");
    ret = listen(sock, LISTENNUM);
    assert(ret != -1);
    fd_set fp_socketselect;
    FD_ZERO(&fp_socketselect);
    FD_SET(sock,&fp_socketselect);
    
    int max_fp = sock;   

    struct sockaddr_in client;
    socklen_t client_addrlength = sizeof(client);
    
    int temp;

    int  fdarr[65535];
    
    fdarr[0] = sock;
    printf("------>>%d\n",fdarr[0]);
    int boundcount = 1;
    signal(SIGCHLD,SIG_IGN);
    while(1){
        printf("i am coming to accept\n");
    
        temp = accept(sock,(struct sockaddr*)&client,&client_addrlength);
        printf("connect = %d",temp);
        
        max_fp = max_fp > temp ? max_fp : temp;
	    fdarr[boundcount++]=temp;
        FD_SET(temp, &fp_socketselect);

        int num = select(max_fp+1,&fp_socketselect,NULL,NULL,NULL);
        //return the number which suit to the rules
	    printf("num = %d\n",num);
        printf("boundcount = %d",boundcount);
	    if(num > 0){
                int i = 0;
		        printf("polling..\n");
                while(i++ < boundcount )
                {
		            FD_SET(fdarr[i],&fp_socketselect);
                    if(FD_ISSET(fdarr[i],&fp_socketselect)){
                        
                        if(fdarr[i] == sock){
                            temp = accept(sock,(struct sockaddr*)&client,&client_addrlength);
                            max_fp = max_fp > temp ? max_fp : temp;
			                fdarr[boundcount++]=temp;
                            FD_SET(temp, &fp_socketselect);
                            printf("\nconnected with ip: %s and port: %d\n", inet_ntoa(client.sin_addr),ntohs(client.sin_port));

                        }else if(fdarr[i]>3){
                            char recvdata[REQUESTLEN];
                            memset(recvdata,'\0',REQUESTLEN);
                            int ret = recv(fdarr[i],recvdata,REQUESTLEN-1,0);
                            printf("\n%s\n", recvdata);
                            pid_t pid = fork();
                            if(-1 == pid){
                                printf("fork() is wrong!!!\n");
                            }else if(0 == pid){
                                parsedata(recvdata,fdarr[i]);
                                break;
                            }else{
                                close(fdarr[i]);
                            }
                        }
                    }
                }

        }else if(0==num){
            printf("time out \n");
        }else{
            printf("something wrong\n");
        }

    }
    close(sock);
    return 0;
}


// send header to the  browser

static char* add_header(int status, char *title, char *mime_type, off_t length, char *buffer , int buffersize)
{
    
    char temp[TEMPLEN];
    
    
    memset(buffer, 0, sizeof(buffersize));
    sprintf(temp, "%s %d %s\r\n", PROTOCOL, status, title);

    strcat(buffer, temp);
    sprintf(temp, "Server: %s\r\n", SERVER_NAME);
    strcat(buffer, temp);
    sprintf(temp, "Connection: Keep-Alive\r\n");
    strcat(buffer, temp);
    sprintf(temp, "Content-Type: %s\r\n", mime_type);
    strcat(buffer, temp);
    sprintf(temp, "Content-Length: %d\r\n", (int)length);
    strcat(buffer, temp);
    sprintf(temp, "Content-Language: zh-CN\r\n");
    strcat(buffer, temp);
    strcat(buffer, "\r\n");
    return buffer;
}

static char* get_mime_type(char *filename)
{
    char *postfix;
    postfix = strrchr(filename, '.');
    if (!strcasecmp(postfix, ".html") || !strcasecmp(postfix, ".htm")){
        return "text/html; charset=UTF-8";
    }else if (!strcasecmp(postfix, ".jpg") || !strcasecmp(postfix, ".jpeg")){
        return "image/jpeg";
    }else{
        return "text/plain; charset=UTF-8";
    }
}

void parsedata(char *recvdata, int connectfd){

    if(chdir(HOMEPATH)<0){
       // printf("chdir error\n");
        exit(0);
    }
    char method[BUFFERLEN];
    char path[BUFFERLEN];
    char protocol[BUFFERLEN];
    memset(method,'\0',BUFFERLEN);
    memset(path,'\0',BUFFERLEN);
    memset(protocol,'\0',BUFFERLEN);
    
    sscanf(recvdata, "%[^ ] %[^ ] %[^ ]", method, path, protocol);
    //open file or dir
    struct stat property;
    stat(path,&property);
    if(S_ISDIR(property.st_mode)){        
        
        if(0 == strcmp(path,"/")){ 
            if(0 == strcasecmp(method,"GET"))
            {
               
                FILE *fp;
                if(fp = fopen("index.html","r")){
                    char head[BUFFERLEN];
                    memset(head,'\0',BUFFERLEN);
                    stat(path+1,&property);
                    stat("index.html",&property);
                    
                    add_header(200, "OK", "text/html", property.st_size, head, BUFFERLEN);
                    char temp[RESPONSELEN];
                    memset(temp,'\0',RESPONSELEN);
                    strcpy(temp,head);
                    fread(temp+strlen(head),1,property.st_size,fp);
                    send(connectfd, temp, strlen(head)+property.st_size,0);
                    
                    close(connectfd);
                }
            }else if(0 == strcasecmp(method,"POST")){
                
                char *postemp=strtok(recvdata, "\r\n\r\n");
                char *pos = postemp;
                while (postemp) {
                    postemp=strtok(NULL, "\r\n\r\n");
                    if(postemp){
                        pos = postemp;
                    }
                    
                }
                
                char mes[500]={"<html><script>alert(\""};
                strcat(mes,pos);
                strcat(mes,"\");</script></html>");
                
                char head[BUFFERLEN];
                memset(head,'\0',BUFFERLEN);
                add_header(200, "OK", "text/html", strlen(mes), head, BUFFERLEN);
                char temp[RESPONSELEN];
                memset(temp,'\0',RESPONSELEN);
                strcpy(temp,head);
                strcat(temp,mes);
                send(connectfd, temp, strlen(head)+strlen(mes),0);
                
                close(connectfd);
            }
        }else{        //other dir
            exit(0);
        }
    }else{                               //if it is a file
        if(0 == strcasecmp(method,"GET")){
            FILE *fp;
            if(fp = fopen(path+1,"rb")){
                char head[BUFFERLEN];
                memset(head,'\0',BUFFERLEN);
                stat(path+1,&property);
                add_header(200, "OK", get_mime_type((path + 1)), property.st_size, head, BUFFERLEN);
                char temp[RESPONSELEN];
                memset(temp,'\0',RESPONSELEN);
                strcpy(temp,head);
                fread(temp+strlen(head),1,property.st_size,fp);
                send(connectfd, temp, strlen(head)+property.st_size,0);
                close(connectfd);
            }
        }else if(0 == strcasecmp(method,"POST")){
            
        }else if(0 == strcasecmp(method,"HEAD")){
            
        }else if(0 == strcasecmp(method,"PUT")){
            
        }else{
            exit(0);
        }
    }
}

index.html

<html>
<script type="text/javascript">
<span style="white-space:pre">	</span>function mdo(){
<span style="white-space:pre">		</span>var flag = confirm("Do you want to download ?");
<span style="white-space:pre">		</span>if(flag == true){
<span style="white-space:pre">			</span>var x = document.getElementById('mydo').href = "1.zip";
<span style="white-space:pre">			</span>alert("you confirmed");
<span style="white-space:pre">		</span>}else{
<span style="white-space:pre">			</span>alert("you canceled");
<span style="white-space:pre">		</span>}


<span style="white-space:pre">	</span>}


</script>
<span style="white-space:pre">	</span><body>
<span style="white-space:pre">		</span><H1>this is a page</H1>
<span style="white-space:pre">		</span><img src="mypic.jpg" />
<span style="white-space:pre">		</span><form  method="post">
<span style="white-space:pre">		</span><input id="firstid" type="text" name="first" />
<span style="white-space:pre">		</span><input id="secondid" type="text" name="second"/>
<span style="white-space:pre">		</span><input id="sumid" type="text" name="sum" readonly="true">
<span style="white-space:pre">		</span><input type="submit" value="compute" οnclick="location.reload(true)">
<span style="white-space:pre">		</span></form>
<span style="white-space:pre">		</span><a id="mydo" href="" οnclick="mdo()" >click to download zip</a>
<span style="white-space:pre">	</span></body>
</html>

加入了一个POST请求,并将请求数据用alert显示出来。带了文件下载功能,附带了CGI的处理,就将输入的数传给服务器,服务器执行一段shell脚本,然后将数据打包回馈给浏览器,在代码中,我使用了中间文件存储处理生成的结果,后来我发现可以利用更好的方法利用 popen函数来处理,自己改动吧!

CGI执行的代码:

#!/bin/sh
echo "<HTML><HEAD>"
echo "<TITLE>bigger or not</TITLE>"
echo "</HEAD><BODY>"
if [ $1 -gt 0 ] 
then echo "<script>alert(\"$1 > 0\");</script>"
else
echo "<script>alert(\"$1 <= 0\");</script>"
fi
echo "</BODY></HTML>"


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值