如何写一个简单的webserver(一):最简实现

来源:互联网 发布:阿里巴巴概念股 云计算 编辑:程序博客网 时间:2024/04/28 10:11

本文主要讲述如何用C/C++在Linux环境下写一个简单的支持并发的web服务器,并不考虑服务器的健壮性、安全性、性能等一系列因素。
在本文中,该服务器仅支持GET请求。
项目地址:https://github.com/imndszy/webserver
开发环境:ubuntu 16.04,

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

当我们打开一个页面时,浏览器会向相应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>\n",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\n", 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\n",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);}

其中process_http_get()是处理get请求的函数,client_error()是错误处理函数。

完整项目代码在 https://github.com/imndszy/webserver

0 0
原创粉丝点击