本文主要讲述如何用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>\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);
}

如何写一个简单的webserver(一):最简实现的更多相关文章

  1. 用Python写一个简单的Web框架

    一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...

  2. 如何写一个简单的http服务器

    最近几天用C++写了一个简单的HTTP服务器,作为学习网络编程和Linux环境编程的练手项目,这篇文章记录我在写一个HTTP服务器过程中遇到的问题和学习到的知识. 服务器的源代码放在Github. H ...

  3. 如何写一个简单的shell

    如何写一个简单的shell 看完<UNIX环境高级编程>后我就一直想写一个简单的shell来作为练习,因为有事断断续续的写了好几个月,如今写了差不多来总结一下. 源代码放在了Github: ...

  4. 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

    这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...

  5. 一步一步写一个简单通用的makefile(三)

    上一篇一步一步写一个简单通用的makefile(二) 里面的makefile 实现对通用的代码进行编译,这一章我将会对上一次的makefile 进行进一步的优化. 优化后的makefile: #Hel ...

  6. Java写一个简单学生管理系统

    其实作为一名Java的程序猿,无论你是初学也好,大神也罢,学生管理系统一直都是一个非常好的例子,初学者主要是用数组.List等等来写出一个简易的学生管理系统,二.牛逼一点的大神则用数据库+swing来 ...

  7. (2)自己写一个简单的servle容器

    自己写一个简单的servlet,能够跑一个简单的servlet,说明一下逻辑. 首先是写一个简单的servlet,这就关联到javax.servlet和javax.servlet.http这两个包的类 ...

  8. express 写一个简单的web app

    之前写过一个简单的web app, 能够完成注册登录,展示列表,CURD 但是版本好像旧了,今天想写一个简单的API 供移动端调用 1.下载最新的node https://nodejs.org/zh- ...

  9. 写一个简单的C词法分析器

    写一个简单的C词法分析器 在写本文过程中,我参考了<词法分析器的实现>中的一些内容.这里我们主要讨论写一个C语言的词法分析器. 一.关键字 首先,C语言中关键字有: auto.break. ...

随机推荐

  1. poj2299 Ultra-QuickSort(线段树求逆序对)

    Description In this problem, you have to analyze a particular sorting algorithm. The algorithm proce ...

  2. CSS3中的新特性

    一.CSS3新属性 CSS3还不属于W3C标准,所以不同浏览器的支持程度也不相同,对于不同浏览器,写法也不同,不同内核的浏览器要加不同的前缀,如下: transform:rotate(9deg); - ...

  3. 观察者(Observer)模式 * 委托事件

    观察者(Observer)模式:定义了一种一对多的依赖关系.让多个观察者对象同时监听某一个主题对象.   这个主题对象发生变化时会通知所有观察者对象,使他们字段更新自己 /* * 抽象主题(Subje ...

  4. Sharepoint2013搜索学习笔记之自定义查询规则(十)

    自定义查询规则,可以根据搜索的关键字将指定的一个或一堆搜索结果提升到第一的位置,如我搜索周杰伦,可以指定搜索最靠前的结果是sharepoint网站内周杰伦的视频如下图: 第一步,进入管理中心,点击管理 ...

  5. 平台播放声音(ext.js)

    首先把需要的两个js文件放在public/core路径下 (文件已经上传到博客了) 音频文件放在文件一级目录 代码:JxCustom.loadAudio("wav/NG.wav") ...

  6. Promise超时情况

    export const ERROR_PROMISE_TIMEOUT = 'ERROR_PROMISE_TIMEOUT'; export default function (promise, time ...

  7. C# 根据论文 像素差异算法【个人实验还是比较好使的】

    论文地址:http://www.docin.com/p-1081596986.html 具体代码: 我转YUV,再通过上面的论文的方式比较近. YVU 介绍:https://blog.csdn.net ...

  8. jvm学习笔记之对象详解

    一.对象的组成 对象头(Header): 运行时数据:存储对象运行时的数据,如哈希码.GC分代年龄.锁状态标志.线程持有的锁.偏向线程ID.偏向时间戳等,这部分数据官方成为“Mark Word”,它的 ...

  9. Java的引用和C++的指针de区别

    Java的引用和C++的指针都是指向一块内存地址的,通过引用或指针来完成对内存数据的操作,就好像风筝的线轴一样,通过线轴总是能够找到风筝,但是它们在实现,原理作用等方面却有区别. (1)类型:引用其值 ...

  10. Invalid bound statement (not found): com.taotao.mapper.TbItemMapper.selectByExample: 错误

    在Maven工程下,想通过controller接收url中的参数Id查询数据库的数据,并且以json形式显示在页面. 在浏览器输入url后出现的问题: 八月 22, 2016 1:45:22 下午 o ...