美文网首页
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));
}

相关文章

  • <HTTP权威指南>读书笔记 ---- Web服

    Web服务器 Web服务器的实现 Web服务器会对HTTP请求进行处理并提供响应。术语"Web服务器"可以用来表示...

  • 《HTTP权威指南》学习笔记

    Web及HTTP基础 Web客户端和服务器Web 内容都是存储在 Web 服务器上的。 Web 服务器所使用的是 ...

  • php中的数据库

    Xampp分为数据库服务器与web服务。web服务分为静态web服务器与动态web服务器访问用:localhost...

  • Tomcat知识小结

    一 web 1 服务器: 硬件服务器 软件服务器 2 web服务器: 提供资源供别人访问 3 web: 网页的意思...

  • Web框架与Web服务器

    1. Web框架与服务器区别 ​ web服务器:典型Web服务器Apache、Nginx、Tomcat,作用是接...

  • WSGI

    简介 Web服务器网关接口(WSGI)是用于Python编程语言的Web服务器(Web Server)和Web应用...

  • node web模块 (服务器端和客户端)

    node web模块 web服务器 web服务器指网站服务器,指驻留在因特网上的某种程序,web浏览器的基本功能,...

  • Flask+uWSGI+Nginx模型

    Web服务器层 Web服务器主要是接收 HTTP 请求并返回响应。常见的 web服务器有 Nginx,Apache...

  • 常见的web服务器有哪些?

    WEB服务器也可以称为网站服务器,可以用来放置网站文件,供用户浏览。那么常见的WEB服务器有哪些呢? web服务器...

  • 网站的基本概念

    服务器 web服务器,提供web服务(网站访问),就需要安装 web服务软件 apche tomcat iis ...

网友评论

      本文标题:web服务器

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