如何写一个简单的webserver(一):最简实现
本文主要讲述如何用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);
}
如何写一个简单的webserver(一):最简实现的更多相关文章
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
- 如何写一个简单的http服务器
最近几天用C++写了一个简单的HTTP服务器,作为学习网络编程和Linux环境编程的练手项目,这篇文章记录我在写一个HTTP服务器过程中遇到的问题和学习到的知识. 服务器的源代码放在Github. H ...
- 如何写一个简单的shell
如何写一个简单的shell 看完<UNIX环境高级编程>后我就一直想写一个简单的shell来作为练习,因为有事断断续续的写了好几个月,如今写了差不多来总结一下. 源代码放在了Github: ...
- 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”
这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...
- 一步一步写一个简单通用的makefile(三)
上一篇一步一步写一个简单通用的makefile(二) 里面的makefile 实现对通用的代码进行编译,这一章我将会对上一次的makefile 进行进一步的优化. 优化后的makefile: #Hel ...
- Java写一个简单学生管理系统
其实作为一名Java的程序猿,无论你是初学也好,大神也罢,学生管理系统一直都是一个非常好的例子,初学者主要是用数组.List等等来写出一个简易的学生管理系统,二.牛逼一点的大神则用数据库+swing来 ...
- (2)自己写一个简单的servle容器
自己写一个简单的servlet,能够跑一个简单的servlet,说明一下逻辑. 首先是写一个简单的servlet,这就关联到javax.servlet和javax.servlet.http这两个包的类 ...
- express 写一个简单的web app
之前写过一个简单的web app, 能够完成注册登录,展示列表,CURD 但是版本好像旧了,今天想写一个简单的API 供移动端调用 1.下载最新的node https://nodejs.org/zh- ...
- 写一个简单的C词法分析器
写一个简单的C词法分析器 在写本文过程中,我参考了<词法分析器的实现>中的一些内容.这里我们主要讨论写一个C语言的词法分析器. 一.关键字 首先,C语言中关键字有: auto.break. ...
随机推荐
- markdown的图片外链
markdown的图片用本地的很不方便,今天试用了一下七牛的服务,感觉很好用.推荐一下,免费的服务够用并且比较友好.
- CSS3动画设置后台登录页背景切换图片
CSS3的动画很实用很好用,简单几句话就可以做出一个好看而且过渡平滑的body背景图片,不多说,来来来,上代码 body{ animation:mybg 7s; -webkit-animation:m ...
- using JSTL
http://docs.oracle.com/javaee/5/tutorial/doc/bnake.html JSTL(JSP Standard Tag Library)
- 设计模式03: Builder 生成器模式(创建型模式)
Builder生成器模式(创建型模式) Builder模式缘起假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分富于变化.如果使用最直观的设计方法,每个房屋部分的变化,都将 ...
- Nginx配置 简单写了个
#user nobody;worker_processes 1; #error_log logs/error.log;#error_log logs/error.log notice;#error_l ...
- Android app如何加密?
欢迎访问网易云社区,了解更多网易技术产品运营经验. Android App包含的内容有dex文件,so文件,res,assets资源文件.对应的加密按此内容分为三大方面:dex保护.so加密.资源保护 ...
- c++缓冲区------c++ Primer Plus
通常,通过使用缓冲区可以更高效地处理输入和输出.缓冲区是用作中介的内存块,它是将信息从设备传输到程序或从程序传输给设备的临时存储工具.通常,像硬盘驱动器这样的设备以512字节(或更多)的块为单位来传输 ...
- C# 接口(2)
接口的实现方式. 接口的实现分两种: 1 显示实现接口 2 实现接口. 我们前面所得的接口的实现均为实现接口.也就是第二种方式.那么我们来来看第第一种实现方式: interface IHuman { ...
- 第0篇 Python前言
1.注释 1)注释的作用: 用自己熟悉的语言在代码中添加注释,方便后期自己查看和理解,也方便其他人查看和理解代码含义. 2)单行注释: 以#号开头,#后面的所有内容均不会被程序执行,起到辅助说明的作用 ...
- IO模型《一》IO模型介绍
IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞 ...