本篇文章不会涉及到很多复杂的概念,也没有写很难读懂的模板函数,代码简单可读,本篇文章送给每一个想自己用c++写一个http服务器的小伙伴!高手们、大佬们当然可以不用看的啦!
正文
怎么写一个简单的http服务器阿?很简单,只需要返回最基本的3个东西即可。
状态码
发送文件的长度
发送文件的类型
状态码如200(找到请求文件)、404(未找到请求文件),我实现的也比较简单,就实现了这两个状态码。
文件长度比如客户请求的是index.html页面,浏览器如何知道收到的这个文件什么时候结束呢?就靠是文件的长度
文件类型 html的类型是html格式,css的是css格式,图片有图片的格式,zip有zip格式文件格式对应的文件类型表(https://tool.oschina.net/commons)
返回给客户端三个这种东西加上请求的文件即可(存在请求文件的情况下)可以了
http工作流程 在这个部分大概介绍一下大概的http的工作流程。客户端通过网址访问到你的网站(一定要记住客户端是主动请求连接的,服务端是被动连接的),实则就是通过ip+port访问的,只不过http的默认端口号是80。比如你还没有域名、云服务器这些东西,那如何在本地测试呢?就是在浏览框输入ip:port,例如127.0.0.1:9996,按下回车就可以在本地访问自己的http服务器了。当然了http要给客户(请求者)一个首页,当客户没有指定网页,单纯的打出域名或者127.0.0.1:9996,就给他一个默认的首页,这也是我们要实现的事情。客户写了请求文件,我们来判断是否存在,存在就返回状态码200和请求文件的内容。不存在就直接返回404。那我们如何判断啊,拿最简单的get为例子吧,其他也大同小异,有兴趣的同学可以自行研究其他的。我们利用正则表达式来解析客户发来的请求是get还是post还是其他请求,在解析出来要请求文件。再利用状态机思想来文件是否存在,若存在在判断文件的类型。大概的流程就是这些。
http.h #pragma once#include #include #include #include #include class tcpclient;class http{ // 文件的根目录 const std::string path_ = ./www/dxgzg_src; std::string filepath_;// 具体文件的绝对路径 std::string filetype_;// 请求文件的类型 std::string header_; // http头response int filesize_; int filefd_; struct stat filestat_; // post请求的话将留言保存到本地文件中 bool ispostmode_ = false;public: http() = default; void addheader(const std::string& head); void header(bool flag); // 把一些头文件的信息都加进来,只有成功的时候调用这个函数, // 并返回文件中的数据 void processhead(); // 把请求文件的路径加上 void addfilepath(const std::string& requestfile); // 获取文件的类型 void analysefiletype(const std::string& requestfile); bool analysefile(const std::string& request); void sendfile(int clientfd,bool isrequestok); bool fileisexist(); // 用户自定义的回调函数要正确的处理异常和自己负责关闭套接字 void readcallback(tcpclient* t);}; http.cpp #include http.h#include tcpclient.h#include logger.h#include #include #include #include #include // 用于test#include using namespace std;void http::addheader(const string& head){ if (!head.empty()) { header_ += head; header_ += ; // console.writeline(我在这里 head!= null + header_); } // 自动加个结尾 else { header_ += ; // console.writeline(我在这里 head == null + header_); }}void http::header(bool flag){ // 判断要发送的头部 true 表示200 false 表示404 if(flag == true) { header_ = http/1.1 200 ok; } else { header_ = http/1.1 404 notfoundcontent-length:0; }}void http::processhead(){ string contenttype = content-type:; if (filetype_ == html) { contenttype += text/html; } else if(filetype_ == js) { contenttype += application/x-javascript; } else if(filetype_ == css) { contenttype += text/css; } else if(filetype_==jpg || filetype_== png) { contenttype += image/ + filetype_; } else if (filetype_== zip || filetype_ == tar) { contenttype += application/ + filetype_; } addheader(contenttype); // 代完善,要打开文件 filepath_是请求文件的路径 filesize_= filestat_.st_size; string contentlength = content-length: + to_string(filesize_); addheader(contentlength); // 最后加了一个结尾 addheader(); // console.writeline(process filecontent_: + );}void http::addfilepath(const string& requestfile){ filepath_ += requestfile;}void http::analysefiletype(const string& requestfile){ for (int i = 0; i < requestfile.size(); ++i) { if (requestfile[i] == '.') { // 获取请求文件以什么结尾的 filetype_ = requestfile.substr(i + 1); } }}bool http::fileisexist(){ filefd_ = ::open(filepath_.c_str(),o_cloexec | o_rdwr); if (filefd_ < 0) { // 说明为找到请求的文件 return false; } return true;}bool http::analysefile(const string& request){ // 调用header的 // 在[]的^是以什么什么开头,放在[]里面的是非的意思 string pattern = ^([a-z]+) ([a-za-z./1-9-]*); regex reg(pattern); smatch mas; regex_search(request,mas,reg); // 因为下标0是代表匹配的整体 if(mas.size() < 3){ log_info(不是正常请求); // 啥都不是直接返回false return false; } string requestmode = mas[1]; if(requestmode == post){ ispostmode_ = true; cout << post请求!!!!! << endl; } // 请求的具体文件 string requestfile = mas[2]; // 先获取请求的文件 bool flag; if (requestfile == /) { // 如果是/的话就给默认值 filepath_.clear(); // 先清个零 filepath_ = path_; filepath_ += /run.html; // 文件的类型也要给人家加上 filetype_ = html; } else { filepath_.clear(); // 先清个零 filepath_ = path_; addfilepath(requestfile); // 利用open函数 } flag = fileisexist(); // 未找到文件的话 if(!flag){ log_info(未找到客户要的文件); cout << filepath_ << endl; return false; } ::fstat(filefd_,&filestat_); // 如果文件不存在的话也就不需要解析类型 analysefiletype(requestfile); return true;}void http::sendfile(int clientfd,bool isrequestok){ long len = 0; // 头部一定是有的。 while(len < header_.size()){ len += ::send(clientfd,header_.c_str(),header_.size(),0); cout << len header << header_ <
closecallback(); return; } buff[r] = ''; string str = buff; cout << str 在补充一点就是,http协议是 结尾。最后还有一个 ,就比如404,http/1.1 404 notfound content-length:0 ,最后面再跟一个 ,结束一段跟一个。
关于功率MOS管烧毁的原因总结
中兴AXON10Pro5G获3C认证 将于下月正式发售
台湾太落后?大陆移动支付领先一大截
Cree成为大众汽车集团FAST项目SiC碳化硅独家合作伙伴
高速微型存储器接口时序-High-Speed Micro M
用C++写一个http服务器
加密芯片ATSHA204A用于固件保护与方案防抄板
vivoX20颜值满分+创意满分,处理器硬伤!高价低配还要玩到什么时候
储能连接器的连接方式和使用
无需外部电源的传感器供电问题如何解决?
能量回馈制动原理_能量回馈制动的特点
汇顶科技与思立微专利互诉战开打
NVIDIA携手奔驰共筑智能驾驶舱未来
无人机全自动应该如何来打造
cpol和相位coha电路图全解析
智慧水稻种植管理系统设计方案解读
【出海日系列活动】谷歌开发者社区 | 开发者扬帆出海,北京站报名启动
智能锁市场持续加温,众多传统企业及资本涌入这一行业
电阻性电路的电路模型和电路定律解读
微软推出首款折叠屏电脑,且支持无线充电