zoukankan      html  css  js  c++  java
  • webserver实现

    最近的工作需求client和server使用https协议进行通讯,我负责client编写程序,在操作系统的-depth理解认为一旦前webserver实现,整理代码:

    #include"apue.h"
    
    extern char **environ;
    void clienterror(int fd,char *cause,char *errnum,char *shortmsg,char *longmsg)
    {
        char buf[MAXLINE],body[MAXLINE];
        sprintf(body,"<html><title>Tiny Error</title>");
        sprintf(body,"%s<body bgcolor=""ffffff"">
    ",body);
        sprintf(body,"%s%s:%s
    ",body,errnum,shortmsg);
        sprintf(body,"%s<p>%s:%s
    ",body,longmsg,cause);
        sprintf(body,"%s<hr><em>The tiny Web server</em?
    ",body);
    
        sprintf(buf,"HTTP/1.0 %s %s
    ",errnum,shortmsg);
        rio_writen(fd,buf,strlen(buf));
        sprintf(buf,"Content-type:text/html
    ");
        rio_writen(fd,buf,strlen(buf));
        sprintf(buf,"Content-length:%d
    
    ",(int)strlen(body));
        rio_writen(fd,buf,strlen(buf));
        rio_writen(fd,body,strlen(body));
    }
    
    
    void read_requesthdrs(rio_t *rp)
    {
    
        char buf[MAXLINE];
        rio_readlineb(rp,buf,MAXLINE);
        while(strcmp(buf,"
    "))
        {
            rio_readlineb(rp,buf,MAXLINE);
    	printf("%s",buf);
        }
        return;
    }
    
    int parse_uri(char *uri,char *filename,char *cgiargs)
    {
        char *ptr;
        printf("parse_uri(uri):%s
    ",uri);
        if(!strstr(uri,"cgi-bin"))
        {
            strcpy(cgiargs,"");
    	strcpy(filename,".");
    	strcat(filename,uri);
    	if(uri[strlen(uri)-1]=='/')
    	    strcat(filename,"home.html");
            return 1;
        }
    
        else
        {
            ptr=index(uri,'?');
    	if(ptr)
    	{
    	    strcpy(cgiargs,ptr+1);
    	    *ptr='';
    	}
    	else
    	    strcpy(cgiargs,"");
             strcpy(filename,".");
    	 strcat(filename,uri);
    	 return 0;
    
        }
    }
    
    
    void get_filetype(char *filename,char *filetype)
    {
    
        if(strstr(filename,".html"))
            strcpy(filetype,"text/html");
        else if(strstr(filename,".gif"))
            strcpy(filetype,"image/gif");
        else if(strstr(filename,".jpg"))
            strcpy(filetype,"image/jpeg"); 
        else
            strcpy(filetype,"text/plain");
    }
    
    void serve_dynamic(int fd,char *filename,char *caiargs)
    {
        char buf[MAXLINE],*emptylist[]={NULL};
    
        sprintf(buf,"HTTP/1.0 200 OK
    ");
        rio_writen(fd,buf,strlen(buf));
        sprintf(buf,"Server:Tiny Web Server
    ");
        rio_writen(fd,buf,strlen(buf));
    
        if(fork()==0)
        {
            setenv("QUERY_STRING",caiargs,1);
    	dup2(fd,STDOUT_FILENO);
    	execve(filename,emptylist,environ);
        }
        wait(NULL);
    }
    
    
    void serve_static(int fd,char *filename,int filesize)
    {
    
        int srcfd;
        char *srcp,filetype[MAXLINE],buf[MAXLINE];
    
        get_filetype(filename,filetype);
        sprintf(buf,"HTTP/1.0 200 OK
    ");
        sprintf(buf,"%sServer:Tiny Web Server
    ",buf);
        sprintf(buf,"%sContent-length:%d
    ",buf,filesize);
        sprintf(buf,"%sContent-type:%s
    
    ",buf,filetype);
        rio_writen(fd,buf,strlen(buf));
    
        srcfd=open(filename,O_RDONLY,0);
        srcp=mmap(0,filesize,PROT_READ,MAP_PRIVATE,srcfd,0);
        close(srcfd);
        rio_writen(fd,srcp,filesize);
        munmap(srcp,filesize);
    }
    
    
    void doit(int fd)
    {
        int is_static;
        struct stat sbuf;
        char buf[MAXLINE],method[MAXLINE],uri[MAXLINE],version[MAXLINE];
        char filename[MAXLINE],cgiargs[MAXLINE];
        rio_t rio;
    
        rio_readinitb(&rio,fd);
        rio_readlineb(&rio,buf,MAXLINE);
        sscanf(buf,"%s %s %s",method,uri,version);
        if(strcasecmp(method,"GET"))
        {
            clienterror(fd,method,"501","Not implemented","Tiny does not implemented this method");
    	return;
        }
    
        read_requesthdrs(&rio);
    
        is_static=parse_uri(uri,filename,cgiargs);
        if(stat(filename,&sbuf)<0)
        {
            clienterror(fd,filename,"404","Not found","Tiny couldn't find this file");
    	return;
        }
    
        if(is_static)
        {
            if(!(S_ISREG(sbuf.st_mode))||!(S_IRUSR&sbuf.st_mode))
    	{
    	    clienterror(fd,filename,"403","Forbidden","Tiny could't read the file");
    	    return;
    	}
    	serve_static(fd,filename,sbuf.st_size);
        }
        else
        {
            if(!(S_ISREG(sbuf.st_mode))|!(S_IXUSR&sbuf.st_mode))
    	{
    	    clienterror(fd,filename,"403","Forbidden","Tiny could't run the CGI program");
    	    return;
    	}
    	serve_dynamic(fd,filename,cgiargs);
        }
    
    
    }
    
    int main(int argc,char **argv)
    {
        int listenfd,connfd,port,clientlen;
        struct sockaddr_in clientaddr;
    
        if(argc!=2)
        {
            fprintf(stderr,"usage:%s <port> 
    ",argv[0]);
    	exit(0);
        }
    
        port=atoi(argv[1]);
    
        listenfd=open_listenfd(port);
        while(1)
        {
            clientlen=sizeof(clientaddr);
    	connfd=accept(listenfd,(SA*)&clientaddr,&clientlen);
    	doit(connfd);
    	close(connfd);
        }
    }
    

    我们能够直接使用浏览器測试上面的程序。比方当前server程序的文件夹以下有一个index.html,仅仅要我们在浏览器中输入:

    localhost:<port>/index.html就能够请求到index.html

    server端收到的浏览器请求行例如以下:


    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    7月17日
    7月16日学习记录
    7月15日学习记录
    git 学习
    投稿相关
    ubuntu16.04 安装以及要做的事情
    python学习使用
    图像相关
    不识别移动硬盘
    深度学习
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4654111.html
Copyright © 2011-2022 走看看