LINUX网络编程:http

目录

1.认识http请求的字段

2.HTTP请求类

3.认识HTTP应答字段

4.HTTP应答类

5.源代码


协议就是一种约定,http也并不例外,使用http也无非就是,定义一个http请求的结构体,将结构体序列化为字符串,发送给服务器,服务器接收字符串,将字符串反序列化为结构化的数据,处理这些数据,将结果返回给客户端。

1.认识http请求的字段

这就是一个完整的http请求,这请求是由浏览器发送。

两张图对照着看

请求方法:GET

URI:/ 是请求服务器的根目录(请求服务器的哪一个目录或者服务)

HTTP版本:HTTP/1.1 

Host,Connettion,User_Agent等等都是浏览器添加的请求报头。

因为有一个空行并且请求正文是空的,所以报头后面有两个空行。

2.HTTP请求类

因为请求是浏览器发送的,所以http请求类是不需要反序列化的,将http发送给我的请求序列化即可。

http请求发过来就是一个长字符串,我们要做的就是将字符串一个一个的解析出来。

1.第一步以"\r\n"为分隔符,将每一行拆分出来。

2.读到的第一行一定是状态行,将状态行的每个字段都拆出来。

如果请求方法是GET还有判断URI中是否有参数,因为GET方法提交表单的时候,参数是在URI中的,参数通常以?分割。

就像这样49.233.244.186:8888/login?user=41234&password=1234123

49.233.244.186:8888/login?user=41234&password=1234123将参数分离之后还需要判断URI请求的服务或者目录是否存在,如果URI访问的目录或者服务不存在返回404页面。

3.读到空行之前,读到的一定是请求报头,以": "为分隔符,将报头的key和value分离出来,并存储到unordered_map中。

4.读到空行之后说明,从此刻开始,剩下的只有正文部分了,直接保存起来即可。

3.认识HTTP应答字段

HTTP状态码:对请求的应答结果,可以去查一下http状态码表。

响应正文:例:可以返回一个网页,或图片,浏览器就会对你返回的内容做解析和渲染。

响应报头:这也是有一张表的,可以去查看一下,如果响应正文不是空的,响应报头就必须添加Content-Lenth,Content-Type,这样浏览器才知道你返回的内容到底是什么。

4.HTTP应答类

判断http请求是资源还是服务

1.如果http请求的是一个服务器的资源,要以二进制的方式将服务器的资源保存到字符串中,因为资源可能是图片,可能是视频。

判断读到的内容是否为空,如果为空说明,http请求了一个不存在的资源,这时候需要将状态码设置为404,构建应答,返回404页面。

不为空就添加对应的状态码,

添加响应头"Content-Type"和Content-Length,

添加响应正文

将应答返回

2.如果http请求是一个服务,需要将这个服务回调出去,将服务于http协议解耦。

5.源代码

#pragma once
#include <iostream>
#include "log.hpp"
#include <vector>
#include <string>
#include <unordered_map>
#include <fstream>
#include <sstream>
static const std::string sep = "\r\n";// http分隔符
static const std::string blank = " "; //空格
static const std::string headerSep = ": ";//请求头响应头分隔符
static const std::string webroot = "./webroot";//服务器的根目录
static const std::string httpVersion = "http/1.0";//http版本
static const std::string suffixSep = ".";//文件类型分隔符
static const std::string defaultpage = "index.html";//主页
static const std::string argsep = "?";//get提交表单分隔符class httpReq;
class httpRep;
//using fun_t = std::function<std::shared_ptr<httpRep> (std::shared_ptr<httpReq>&)>;using fun_t = std::function<std::shared_ptr<httpRep>(std::shared_ptr<httpReq>)>;
class httpReq
{
private:std::string getOneLine(std::string &reqstr) // 获取请求的一行{if (reqstr.empty()) // 判断请求是否为空{Log(Error, "reqstr empty");return std::string();}auto pos = reqstr.find(sep);if (pos == std::string::npos) // 判断是否找到{Log(Error, "reqstr not found sep");return std::string();}std::string line = reqstr.substr(0, pos);reqstr.erase(0, pos + sep.size());return line.empty() ? sep : line; // 如line为空说明读到空行}public:httpReq(const std::string root = webroot, const std::string blanksep = sep): _root(root), _blankLine(blanksep){}void serialize(){}bool parseLine() // 解析请求行{if (_requestLine.empty()){return false;}// 解析请求行std::stringstream ss(_requestLine); // 1以空格为分隔符自动解析字符串ss >> _reqMethod >> _url >> _httpVersion;_path += webroot;// 解析参数if (strcasecmp(_reqMethod.c_str(), "get") == 0){//Log(Debug, "before url %s", _url.c_str());auto pos = _url.find(argsep);if (pos != std::string::npos) // 有参数{   _args = _url.substr(pos + argsep.size());//Log(Info, "args: %s", _args);_url.resize(pos);}//Log(Debug, "after url %s", _url.c_str());}_path += _url;if (_path[_path.size() - 1] == '/')//如果请求的是根目录,跳转到主页{_path += defaultpage;}for (auto s : _requestHeader){auto pos = s.find(headerSep);std::string k = s.substr(0, pos);std::string v = s.substr(pos + headerSep.size());_kv.insert(std::make_pair(k, v));}return true;}bool Deserialize(std::string &reqstr) // 反序列化{_requestLine = getOneLine(reqstr);while (true){std::string line = getOneLine(reqstr);if (line.empty()) // getOneline 失败{break;}else if (line == sep) // 读到空行{_text = reqstr;break;}else // 读到请求头{_requestHeader.push_back(line);}}return parseLine();}bool isServiceReq() //是否为路径服务请求{return !_text.empty() || !_args.empty();}const std::string &path(){return _path;}const std::string &method(){return _reqMethod;}const std::string &text(){return _text;}const std::string &args(){return _args;}void pprint(){std::cout << "###" << _reqMethod << std::endl;std::cout << "###" << _url << std::endl;std::cout << "###" << _path << std::endl;std::cout << "###" << _httpVersion << std::endl;for (auto it : _kv){std::cout << "@@@" << it.first << ": " << it.second << endl;}std::cout << "$$$" << _text << std::endl;}std::string getSuffix()//获取返回资源的类型{if (_path.empty()){return std::string();}auto pos = _path.rfind(suffixSep);if (pos == std::string::npos){return ".html";}else{return _path.substr(pos);}}private:std::string _requestLine;                // http请求第一行std::vector<std::string> _requestHeader; // http请求头std::string _blankLine;                  // 空行std::string _text;                       // http正文// 解析出每行具体内容std::string _root;                                // web的根目录std::string _reqMethod;                           // 请求方法std::string _url;                                 // urlstd::string _httpVersion;                         // http版本std::string _path;                                // 访问资源的路径std::string _args;                                // 请求的参数std::unordered_map<std::string, std::string> _kv; // 请求头的kv模型
};class httpRep
{
public:httpRep(const std::string version = httpVersion, const std::string b = sep): _httpVersion(version), _blankLine(b){}void addStatusLine(const int code, const std::string &descrip)//添加状态行{_statuCode = code;_codeDescripetion = descrip;}void addHander(const std::string k, const std::string v)//添加响应头{_kv.insert(std::make_pair(k, v));}void addText(std::string &text)//添加响应文{_text = text;}std::string Serialize(){//序列化状态行_statusLine = _httpVersion + blank + std::to_string(_statuCode) + blank + _codeDescripetion + sep;//序列化响应头for (auto it : _kv){_respondHeader += it.first;_respondHeader += headerSep;_respondHeader += it.second;_respondHeader += sep;}//构建应答std::string respond;respond += _statusLine;respond += _respondHeader;respond += sep;respond += _text;// std::cout << respond << std::endl;// Log(Info, "%s", _statusLine.c_str());// Log(Info, "%s", _respondHeader.c_str());return respond;}void pprint(){std::cout << "###" << _httpVersion << std::endl;std::cout << "###" << _statuCode << std::endl;std::cout << "###" << _codeDescripetion << std::endl;std::cout << "###" << _text << std::endl;}private:// 构建响应必要的字段std::string _httpVersion;                         // http版本int _statuCode;                                   // 状态码std::string _codeDescripetion;                    // 状态码描述std::unordered_map<std::string, std::string> _kv; // 响应报头的kv模型// 构建响应的必要行std::string _statusLine;    // 状态行std::string _respondHeader; // 请求头std::string _blankLine;     // 空行std::string _text;          // 正文
};class Factor
{
public:static std::shared_ptr<httpReq> BuildHttprequest() //使用智能指针构建应答{return std::make_shared<httpReq>();}static std::shared_ptr<httpRep> BuildHttprepond(){return std::make_shared<httpRep>();}
};class httpserver
{
public:httpserver(){_mime.insert(std::make_pair(".html", "text/html"));_mime.insert(std::make_pair(".jpg", "image/jpeg"));_mime.insert(std::make_pair(".png", "application/x-plt"));_Statuscode_Descripetion.insert(std::make_pair(100, "continue"));_Statuscode_Descripetion.insert(std::make_pair(200, "ok"));_Statuscode_Descripetion.insert(std::make_pair(301, "Moved Permanently")); // 永久重定向_Statuscode_Descripetion.insert(std::make_pair(302, "Found"));             // 临时重定向_Statuscode_Descripetion.insert(std::make_pair(400, "Bad Request"));_Statuscode_Descripetion.insert(std::make_pair(404, "Not Found"));_Statuscode_Descripetion.insert(std::make_pair(404, "Not Found"));}std::string readFileContent(const std::string &path, int &filesize){// std::cout<< path <<std::endl;std::ifstream in(path, std::ios::binary);if (!in.is_open()){return std::string();}in.seekg(0, in.end);filesize = in.tellg();in.seekg(0, in.beg);// std::cout << filesize << std::endl;if (filesize < 0){filesize = 0;}std::string content;content.resize(filesize);in.read((char *)content.c_str(), filesize);in.close();return content;}void addhander(std::string path, fun_t handler){std::string tmp = webroot + path;_funcs.insert(std::make_pair(tmp, handler));}#define VERSION_1std::string httpHandler(std::string req){
#ifdef VERSION_1std::cout << req << std::endl;auto request = Factor::BuildHttprequest();request->Deserialize(req);//Log(Info, "method %s", request->method().c_str());// Log(Info,"s","redir ----------------------");//  if(request->path() == "./webroot/redir")//进行重定向//  {//      code = 302;//      respond->addHander("Location", "https://www.csdn.net/?spm=1011.2266.3001.4476");//      respond->addStatusLine(code, _Statuscode_Descripetion[code]);// }if (request->isServiceReq())//当前请求的是一个服务{Log(Info, "method %s", request->method().c_str());Log(Info, "method %s", request->path().c_str());auto response = _funcs[request->path()](request);return response->Serialize();}else // 当前请求的是一个服务器资源{int code = 200;int filesize = 0;auto respond = Factor::BuildHttprepond();std::string content = readFileContent(request->path(), filesize);if (content.empty())//没有读到任何内容,说明请求不存在{code = 404;respond->addStatusLine(code, _Statuscode_Descripetion[code]);respond->addHander("Content-Type", ".html");std::string content404 = readFileContent("./webroot/404.html", filesize);respond->addText(content404);}else//请求存在{respond->addStatusLine(code, _Statuscode_Descripetion[code]);/std::string suffix = request->getSuffix();//获取资源的后坠respond->addHander("Content-Type", _mime[suffix]);respond->addHander("Content-Length", std::to_string(filesize));respond->addText(content);}return respond->Serialize();}#elsestd::cout << "version control" << endl;
#endif}private:std::unordered_map<std::string, std::string> _mime;            // 文件后缀,对应的content type类型std::unordered_map<int, std::string> _Statuscode_Descripetion; // 状态码 对应的描述std::unordered_map<std::string, fun_t> _funcs;                  // 将请求回调出去
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1534295.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

2024年06月中国电子学会青少年软件编程(图形化)等级考试试卷(一级)答案 + 解析

青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;一级&#xff09; 分数&#xff1a;100 题数&#xff1a;37 一、单选题 音乐Video Game1的时长将近8秒&#xff0c;点击一次角色&#xff0c;下列哪个程序不能完整地播放音乐两次&#xff1f;&#xff0…

【Hot100】LeetCode—169. 多数元素

目录 1- 思路题目识别技巧 2- 实现⭐136. 只出现一次的数字——题解思路 3- ACM 实现 原题链接&#xff1a;169. 多数元素 1- 思路 题目识别 识别1 &#xff1a;统计数组中出现数量多余 [n/2] 的元素 技巧 值相同&#xff0c;则对 count 1&#xff0c;如果不相同则对值进行…

【C#】VS插件

翻译 目前推荐较多的 可以单词发言&#xff0c;目前还在开发阶段 TranslateIntoChinese - Visual Studio Marketplace 下载量最高的(推荐) Visual-Studio-Translator - Visual Studio Marketplace 支持翻译的版本较多&#xff0c;在 Visual Studio 代码编辑器中通过 Googl…

vue使用TreeSelect设置带所有父级节点的回显

Element Plus的el-tree-select组件 思路&#xff1a; 选中节点时&#xff0c;给选中的节点赋值 pathLabel&#xff0c;pathLabel 为函数生成的节点名字拼接&#xff0c;数据源中不包含。 在el-tree-select组件中设置 props“{ label: ‘pathLabel’ }” 控制选中时input框中回…

【信创】推荐一款好用的免费在线流程图思维导图工具 _ 统信 _ 麒麟 _ 方德

原文链接&#xff1a;【信创】推荐一款好用的免费在线流程图思维导图工具 | 统信 | 麒麟 | 方德 Hello&#xff0c;大家好啊&#xff01;今天给大家推荐一款非常好用的免费在线流程图和思维导图工具——ProcessOn。无论是项目管理、数据分析、头脑风暴还是日常办公&#xff0c;…

RFID读写器:零部件加工中的高效识别与管理利器

RFID读写器&#xff1a;零部件加工中的高效识别与管理利器 在传统零部件加工行业&#xff0c;面临着提高生产效率、保证生产计划执行、系统化管控产品质量以及有效管理库存等多方面的挑战&#xff0c;而 RFID 读写器在应对这些挑战的过程中扮演着至关重要的角色。 传统识别方式…

健身管理|基于java的健身管理系统小程序(源码+数据库+文档)

健身管理系统|健身管理系统小程序 目录 基于java的健身管理系统小程序 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&…

内幕!smardaten无代码平台全方位测评,这些细节你绝对想不到!

目录 一、引言二、测评要点2.1、前后端交互嵌套2.2、兼容性与可扩展性2.2.1、页面集成2.2.2、数据集成2.2.3、接口集成2.2.4、权限集成2.2.5、代码扩展支持 2.3、UI定制2.4、开发环境的隔离2.5、OEM定制2.6、多语言切换2.7、AI大模型能力 三、总结 一、引言 作为一枚IT从业者&…

Mega Stamp Bundle 地形合集捆绑包峡谷沙丘山脉

终极套装,满足所有地形雕刻需求! 自2015年Gaia发布以来,我们团队就发明了印章技术,欢迎来到Mega Stamp Bundle! 本套装包含14个印章包,单次购买即可享受大幅折扣,共获得140个专业设计的印章。 这些印章可与Unity Terrain Tools、Gaia以及任何使用印章高度图图像的工具…

memcmp函数的使用

目录 1.头文件 2.memcmp函数讲解 小心&#xff01;VS2022不可直接接触&#xff0c;否则&#xff01;没这个必要&#xff0c;方源面色淡然一把抓住&#xff01;顷刻炼化&#xff01; 1.头文件 memcmp函数的使用需要包括头文件 #include<string.h> 2.memcmp函数讲解 简述…

HTTPS原理详解

学习记录&#xff0c;仅供参考&#xff01; 一、HTTPS和HTTP的区别 二、HTTP的工作流程 三、实现原理 四、应用 01.准备工作 在客户端&#xff08;Windows&#xff09;生成证书&#xff0c;然后安装到服务端&#xff08;Linux&#xff09;。 安装OpenSSL工具 OpenSSL中包含…

C++速通LeetCode简单第5题-回文链表

解法1&#xff0c;堆栈O(n)简单法&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListN…

jdk环境变量配置+eclipse配置jdk

文章目录 安装jdkjdk环境变量配置eclipse里边配置jdkeclipse覆盖率插件——EclEmma的安装和使用 安装jdk 在安装前可以先建两个文件夹&#xff0c;注意不要文件夹用英文&#xff0c;不要用中文&#xff0c;如图&#xff1a; 然后我们开始安装 然后就看我们有没有安装成功…

【Unity踩坑】No cloud project ID was found by the Analytics SDK

在编译默认的URP 2D项目时&#xff0c;出现这样一个错误&#xff1a;No cloud project ID was found by the Analytics SDK. This means Analytics events will not be sent. Please make sure to link your cloud project in the Unity editor to fix this problem. 原因&…

【目标检测数据集】厨房常见的水果蔬菜调味料数据集4910张39类VOC+YOLO格式

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4910 标注数量(xml文件个数)&#xff1a;4910 标注数量(txt文件个数)&#xff1a;4910 标注…

JVM面试真题总结(九)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 描述CMS垃圾收集的工作过程 CMS&#xff08;Concurrent Mark Swee…

牛客练习赛(下)

Cidoai的平均数对 题目描述 登录—专业IT笔试面试备考平台_牛客网 运行代码 #include <iostream> #include <vector> using namespace std; int main() {int n, k;cin >> n >> k;int totalAns 0;int rSum 0;vector<int> ex, weights;for (i…

情感AI:科技赋能情感计算的新时代

一、引言 随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;情感AI&#xff08;Affective AI&#xff09;成为了人工智能领域中的一大热门话题。情感AI&#xff0c;或称情感计算&#xff08;Affective Computing&#xff09;&#xff0c;指的是通过计算机技术…

buildroot移植qt报错Info: creating stash file (补充qt添加字库)

移植qt库&#xff0c;编译文件报错Info: creating stash file /home/rbing/QT/uart/.qmake.stash Project ERROR: Unknown module(s) in QT: serialport rbingouc:~/QT/uart$ /home/rbing/linux/tool/buildroot-2022.02.9/output/host/usr/bin/qmake Info: creating stash fil…

Redis——常用数据类型hash

目录 hash常用命令hsethgethdelhkeyshvalshgetallhmgethlenhsetnxhincrbyhdecrby 哈希的编码方式哈希的应用 hash 常用命令 hset HSET key field value [field value ...]//时间复杂度O(1) //返回值&#xff1a;设置成功的键值对的个数hget HGET key field//hdel HDEL key…