zoukankan      html  css  js  c++  java
  • 如何写一个简单的webserver(一):最简实现

    本文主要讲述如何用C/C++在Linux环境下写一个简单的支持并发的web服务器,并不考虑服务器的健壮性、安全性、性能等一系列因素。 
    在本文中,该服务器仅支持GET请求。 

    项目地址:https://github.com/imndszy/webserver 
    开发环境:ubuntu 16.04,

    在编写一个服务器之前,我们需要对socket以及网络协议尤其是http协议有基础的了解,如果不了解,请参阅Beej’s Guide to Network ProgrammingUNIX网络编程卷一

    当我们打开一个页面时,浏览器会向相应URL所绑定的IP地址发送请求,然后远端的webserver就解析并处理这个请求,比如说如果是GET请求,就会返回一个页面或其他数据。 
    那么一个webserver的工作流程是怎样的呢?在此我们只讨论一个最简单的服务器且对单个进程而言。 
    这里写图片描述 
    上图中,socket()用于创建一个套接字,该套接字用于监听某个端口,在bind()中套接字与端口绑定,当然还有一些其他参数,随后通过listen()进行监听,这时候就进入服务器程序的主循环,当有连接建立后,accpet()被调用并返回一个新的套接字用于处理连接,这时派生一个子进程进行处理,子进程中recv()从缓冲区读取数据交由相关函数处理,处理完毕后的结果通过send()发送出去,随后关闭用于处理的套接字,子进程退出。

    至此,一个简易webserver的雏形就显现出来了。

    首先是如何创建及设置套接字的代码:

    int sockfd;
    char *port;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    
    //从命令行参数读取要绑定到的端口号
    if(argc != 2){
        fprintf(stderr,"usage:%s <port>
    ",argv[0]);
        exit(1);
    }
    port = argv[1];
    
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    
    if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0){
        fprintf(stderr, "getaddrinfo:%s
    ", gai_strerror(rv));
        return 1;
    }
    
    for(p = servinfo;p != NULL;p = p->ai_next){
        if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
            perror("server: socket");
            continue;
        }
        if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
            perror("setsockopt");
            exit(1);
        }
        if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
            close(sockfd);
            perror("server:bind");
            continue;
        }
    
        break;
    }
    

    接下来是主循环部分:

    while(1){
        sin_size = sizeof(other_addr);
        connfd = accept(sockfd, (struct sockaddr *)&other_addr, &sin_size);
        if(connfd == -1){
            perror("accept");
            continue;
        }
    
        inet_ntop(other_addr.ss_family, get_in_addr((struct sockaddr*)&other_addr), s, sizeof(s));
        printf("server:got connection from %s
    ",s);
    
        if(!fork()){
            close(sockfd);                       //fork以后子进程中也会有一个sockfd
            if(recv(connfd, buf, MAXBUF, 0) == -1) {
                perror("receive");
                close(connfd);
                exit(1);
            }
    
            sscanf(buf,"%s %s %s",method,uri,version);
    
            if(!strcasecmp(method, "GET"))     //如果是GET请求
                process_http_get(connfd,uri,filename);
            else
                client_error(connfd,method,"501","Not Implemented","Webserver does not implement this method");
    
            close(connfd);
            exit(0);
        }
        close(connfd);
    }
  • 相关阅读:
    课堂作业04 2017.10.27
    课程作业 03 动手动脑 2017.10.20
    课程作业 03 2017.10.20
    HDU 3974 Assign the task
    POJ 2155 Matrix
    POJ 2481 Cows
    HDU 3038 How Many Answers Are Wrong
    CS Academy Array Removal
    POJ_1330 Nearest Common Ancestors LCA
    CF Round 427 D. Palindromic characteristics
  • 原文地址:https://www.cnblogs.com/ct20150811/p/9488048.html
Copyright © 2011-2022 走看看