美文网首页
web服务器

web服务器

作者: ustclcl | 来源:发表于2019-04-15 21:27 被阅读0次

    首先创建几个函数以方便我们调用

    • open_clinetfd: 创建一个网络socket,作为客户端,并且尝试连接主机
    • open_listenfd: 创建socket,作为主机,并开始监听
    #include "mynet.h"
    
    int open_clientfd(char *hostname, char *port){
        int clientfd;
        struct addrinfo hints, *listp, *p;
    
        memset(&hints, 0,sizeof(struct addrinfo));
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_NUMERICSERV;
        hints.ai_flags |= AI_ADDRCONFIG;
        getaddrinfo(hostname, port, &hints, &listp);
    
        for(p=listp;p;p=p->ai_next){
            if((clientfd = socket(p->ai_family, p->ai_socktype,p->ai_protocol))<0)
              continue;
            if(connect(clientfd,p->ai_addr,p->ai_addrlen)!=-1)
              break;
            close(clientfd);
        }
    
        freeaddrinfo(listp);
        if(!p) return -1;
        else return clientfd;
    }
    
    int open_listenfd(char *port)
    {
        struct addrinfo hints, *listp, *p;
        int listenfd, optval=1;
    
        memset(&hints, 0 ,sizeof(struct addrinfo));
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
        hints.ai_flags |= AI_NUMERICSERV;
        getaddrinfo(NULL, port, &hints, &listp);
    
        for(p=listp;p;p=p->ai_next){
            if((listenfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) < 0)
              continue;
            setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(const void *)&optval,sizeof(int));
    
            if(bind(listenfd,p->ai_addr,p->ai_addrlen)==0)
              break; //success
            close(listenfd); //bind fail, try next
        }
    
        freeaddrinfo(listp);
        if(!p)
          return -1;
        if(listen(listenfd,LISTENQ)<0){
            close(listenfd);
            return -1;
        }
        return listenfd;
    }
    

    我们的服务器有以下几个模块

    • int main(int argc, char** argv):从shell读取参数作为端口,使用上述open_listenfd创建一个监听端口,使用accept创建一个连接,进入do_it开始处理事务
    • void doit(int fd):do_it的参数是connfd,读取请求,调用parse_uri分析请求是静态请求还是动态请求,分别调用serve_static和serve_dynamic进行响应
    • int parse_uri(char *uri, char *filename, char *cgiargs):url不包含cgi-bin则认为是静态请求,读取请求的文件,若没有,默认返回home.html;否则认为是动态请求
    • void serve_static(int fd, char *filename, int filesize):发送header,再发送文件
    • void serve_dynamic(int fd, char *filename, char *cgiargs):服务动态内容,在cgi-bin找运行程序
    #include "mynet.h"
    
    void doit(int fd);
    void read_requesthdrs(int fd);
    int parse_uri(char *uri, char *filename, char *cgiargs);
    void serve_static(int fd, char *filename, int filesize);
    void get_filetype(char *filename, char *filetype);
    void serve_dynamic(int fd, char *filename, char *cgiargs);
    void clienterror(int fd, char*cause, char *errnum, char *shortmsg, char *longmsg);
    
    int main(int argc, char** argv)
    {
        int listenfd,connfd;
        char hostname[MAXLINE], port[MAXLINE];
        socklen_t clientlen;
        struct sockaddr_storage clientaddr;
    
        if(argc!=2){
            fprintf(stderr, "usage: %s <port>\n",argv[0]);
            exit(1);
        }
    
        listenfd = open_listenfd(argv[1]);
        while(1){
            clientlen = sizeof(clientaddr);
            connfd = accept(listenfd,(SA*)&clientaddr,&clientlen);
            getnameinfo((SA*)&clientaddr,clientlen,hostname,MAXLINE,port,MAXLINE,0);
            printf("Accepted connection from (%s, %s)\n",hostname,port);
            doit(connfd);
            close(connfd);
        }
    }
    
    
    void doit(int fd){
        int is_static;
        struct stat sbuf;
        char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
        char filename[MAXLINE], cgiargs[MAXLINE];
    
        read(fd, buf, MAXLINE);
        printf("Requset hears:\n");
        printf("%s",buf);
        sscanf(buf, "%s %s %s", method, uri, version);
        if(strcasecmp(method, "GET")){
            clienterror(fd, method, "501", "Not implementedd","Tiny does not implement this method");
            return;
        }
        //read_requesthdrs(fd);
        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 couldn'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 couldn't run the CGI program");
                return;
            }
            serve_dynamic(fd,filename,cgiargs);
        }
    }
    
    void read_requesthdrs(int fd){
        char buf[MAXLINE];
    
        read(fd,buf,MAXLINE);
        while(strcmp(buf, "\r\n")){
            read(fd,buf,MAXLINE);
            printf("%s",buf);
        }
        return;
    }
    int parse_uri(char *uri, char *filename, char *cgiargs){
        char *ptr;
    
        if(!strstr(uri, "cgi-bin")) {
            strcpy(cgiargs,"");
            strcpy(filename,".");
            strcat(filename,uri);
            if(uri[strlen(uri)-1] == '/')
              strcat(filename,"home.html");
            return 1;
        }
        else{   //dynammic content
            ptr = index(uri,'?');
            if (ptr) {
                strcpy(cgiargs, ptr+1);
                *ptr = '\0';
            }
            else
              strcpy(cgiargs, ptr+1);
            strcpy(filename,".");
            strcat(filename,uri);
            return 0;
        }
    }
    
    
    void serve_static(int fd, char *filename, int filesize){
        int srcfd;
        char *srcp, filetype[MAXLINE], buf[MAXLINE*10];
    
        get_filetype(filename, filetype);
        sprintf(buf, "HTTP/1.0 200 OK\r\n");
        sprintf(buf, "%sServer: Tiny Web Server\r\n",buf);
        sprintf(buf, "%sConnection: close\r\n",buf);
        sprintf(buf, "%sContent-length: %d\r\n",buf,filesize);
        sprintf(buf, "%sContent-type: %s\r\n\r\n",buf,filetype);
        write(fd,buf,strlen(buf));
        printf("Response headers:\n");
        printf("%s",buf);
    
        srcfd = open(filename,O_RDONLY, 0);
        srcp = mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
        close(srcfd);
        write(fd,srcp,filesize);
        munmap(srcp,filesize);
    }
    
    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,".png"))
           strcpy(filetype, "image/png");
        else if (strstr(filename,".jpg"))
           strcpy(filetype, "image/jpeg");
        else 
           strcpy(filetype, "image/plain");
    }
    
    void serve_dynamic(int fd, char *filename, char *cgiargs){
        char buf[MAXLINE],*emptylist[] = {NULL};
    
        sprintf(buf,"HTTP/1.0 200 OK\r\n");
        write(fd,buf,strlen(buf));
        sprintf(buf,"Server: Tiny Web Server\r\n");
        write(fd,buf,strlen(buf));
    
        if(fork()==0) {
            setenv("QUERY_STRING",cgiargs,1);
            dup2(fd,STDOUT_FILENO);
            execve(filename,emptylist,environ);
        }
        wait(NULL);
    }
    
    void clienterror(int fd, char*cause, char *errnum, char *shortmsg, char *longmsg){
        char buf[MAXLINE], body[100*MAXLINE];
        sprintf(body,"<html><title>Tiny Error</title>");
        sprintf(body,"%s<body bgcolor=""ffffff"">\r\n",body);
        sprintf(body,"%s%s: %s\r\n",body,errnum,shortmsg);
        sprintf(body,"%s<p>%s: %s\r\n",body,longmsg,cause);
        sprintf(body,"%s<hr><em>The Tiny Web server</em>\r\n",body);
    
        sprintf(buf, "HTTP/1.0 %s %s\r\n",errnum,shortmsg);
        write(fd,buf,strlen(buf));
        sprintf(buf, "Content-type: text/html\r\n");
        write(fd,buf,strlen(buf));
        sprintf(buf, "Content-length: %d\r\n\r\n",(int)strlen(body));
        write(fd,buf,strlen(buf));
        write(fd,body,strlen(body));
    }
    

    相关文章

      网友评论

          本文标题:web服务器

          本文链接:https://www.haomeiwen.com/subject/xiwswqtx.html