• 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.源代码

    1. #pragma once
    2. #include
    3. #include "log.hpp"
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. static const std::string sep = "\r\n";// http分隔符
    10. static const std::string blank = " "; //空格
    11. static const std::string headerSep = ": ";//请求头响应头分隔符
    12. static const std::string webroot = "./webroot";//服务器的根目录
    13. static const std::string httpVersion = "http/1.0";//http版本
    14. static const std::string suffixSep = ".";//文件类型分隔符
    15. static const std::string defaultpage = "index.html";//主页
    16. static const std::string argsep = "?";//get提交表单分隔符
    17. class httpReq;
    18. class httpRep;
    19. //using fun_t = std::function (std::shared_ptr&)>;
    20. using fun_t = std::functionshared_ptr(std::shared_ptr)>;
    21. class httpReq
    22. {
    23. private:
    24. std::string getOneLine(std::string &reqstr) // 获取请求的一行
    25. {
    26. if (reqstr.empty()) // 判断请求是否为空
    27. {
    28. Log(Error, "reqstr empty");
    29. return std::string();
    30. }
    31. auto pos = reqstr.find(sep);
    32. if (pos == std::string::npos) // 判断是否找到
    33. {
    34. Log(Error, "reqstr not found sep");
    35. return std::string();
    36. }
    37. std::string line = reqstr.substr(0, pos);
    38. reqstr.erase(0, pos + sep.size());
    39. return line.empty() ? sep : line; // 如line为空说明读到空行
    40. }
    41. public:
    42. httpReq(const std::string root = webroot, const std::string blanksep = sep)
    43. : _root(root), _blankLine(blanksep)
    44. {
    45. }
    46. void serialize()
    47. {
    48. }
    49. bool parseLine() // 解析请求行
    50. {
    51. if (_requestLine.empty())
    52. {
    53. return false;
    54. }
    55. // 解析请求行
    56. std::stringstream ss(_requestLine); // 1以空格为分隔符自动解析字符串
    57. ss >> _reqMethod >> _url >> _httpVersion;
    58. _path += webroot;
    59. // 解析参数
    60. if (strcasecmp(_reqMethod.c_str(), "get") == 0)
    61. {
    62. //Log(Debug, "before url %s", _url.c_str());
    63. auto pos = _url.find(argsep);
    64. if (pos != std::string::npos) // 有参数
    65. {
    66. _args = _url.substr(pos + argsep.size());
    67. //Log(Info, "args: %s", _args);
    68. _url.resize(pos);
    69. }
    70. //Log(Debug, "after url %s", _url.c_str());
    71. }
    72. _path += _url;
    73. if (_path[_path.size() - 1] == '/')//如果请求的是根目录,跳转到主页
    74. {
    75. _path += defaultpage;
    76. }
    77. for (auto s : _requestHeader)
    78. {
    79. auto pos = s.find(headerSep);
    80. std::string k = s.substr(0, pos);
    81. std::string v = s.substr(pos + headerSep.size());
    82. _kv.insert(std::make_pair(k, v));
    83. }
    84. return true;
    85. }
    86. bool Deserialize(std::string &reqstr) // 反序列化
    87. {
    88. _requestLine = getOneLine(reqstr);
    89. while (true)
    90. {
    91. std::string line = getOneLine(reqstr);
    92. if (line.empty()) // getOneline 失败
    93. {
    94. break;
    95. }
    96. else if (line == sep) // 读到空行
    97. {
    98. _text = reqstr;
    99. break;
    100. }
    101. else // 读到请求头
    102. {
    103. _requestHeader.push_back(line);
    104. }
    105. }
    106. return parseLine();
    107. }
    108. bool isServiceReq() //是否为路径服务请求
    109. {
    110. return !_text.empty() || !_args.empty();
    111. }
    112. const std::string &path()
    113. {
    114. return _path;
    115. }
    116. const std::string &method()
    117. {
    118. return _reqMethod;
    119. }
    120. const std::string &text()
    121. {
    122. return _text;
    123. }
    124. const std::string &args()
    125. {
    126. return _args;
    127. }
    128. void pprint()
    129. {
    130. std::cout << "###" << _reqMethod << std::endl;
    131. std::cout << "###" << _url << std::endl;
    132. std::cout << "###" << _path << std::endl;
    133. std::cout << "###" << _httpVersion << std::endl;
    134. for (auto it : _kv)
    135. {
    136. std::cout << "@@@" << it.first << ": " << it.second << endl;
    137. }
    138. std::cout << "$$$" << _text << std::endl;
    139. }
    140. std::string getSuffix()//获取返回资源的类型
    141. {
    142. if (_path.empty())
    143. {
    144. return std::string();
    145. }
    146. auto pos = _path.rfind(suffixSep);
    147. if (pos == std::string::npos)
    148. {
    149. return ".html";
    150. }
    151. else
    152. {
    153. return _path.substr(pos);
    154. }
    155. }
    156. private:
    157. std::string _requestLine; // http请求第一行
    158. std::vector _requestHeader; // http请求头
    159. std::string _blankLine; // 空行
    160. std::string _text; // http正文
    161. // 解析出每行具体内容
    162. std::string _root; // web的根目录
    163. std::string _reqMethod; // 请求方法
    164. std::string _url; // url
    165. std::string _httpVersion; // http版本
    166. std::string _path; // 访问资源的路径
    167. std::string _args; // 请求的参数
    168. std::unordered_map _kv; // 请求头的kv模型
    169. };
    170. class httpRep
    171. {
    172. public:
    173. httpRep(const std::string version = httpVersion, const std::string b = sep)
    174. : _httpVersion(version), _blankLine(b)
    175. {
    176. }
    177. void addStatusLine(const int code, const std::string &descrip)//添加状态行
    178. {
    179. _statuCode = code;
    180. _codeDescripetion = descrip;
    181. }
    182. void addHander(const std::string k, const std::string v)//添加响应头
    183. {
    184. _kv.insert(std::make_pair(k, v));
    185. }
    186. void addText(std::string &text)//添加响应文
    187. {
    188. _text = text;
    189. }
    190. std::string Serialize()
    191. {
    192. //序列化状态行
    193. _statusLine = _httpVersion + blank + std::to_string(_statuCode) + blank + _codeDescripetion + sep;
    194. //序列化响应头
    195. for (auto it : _kv)
    196. {
    197. _respondHeader += it.first;
    198. _respondHeader += headerSep;
    199. _respondHeader += it.second;
    200. _respondHeader += sep;
    201. }
    202. //构建应答
    203. std::string respond;
    204. respond += _statusLine;
    205. respond += _respondHeader;
    206. respond += sep;
    207. respond += _text;
    208. // std::cout << respond << std::endl;
    209. // Log(Info, "%s", _statusLine.c_str());
    210. // Log(Info, "%s", _respondHeader.c_str());
    211. return respond;
    212. }
    213. void pprint()
    214. {
    215. std::cout << "###" << _httpVersion << std::endl;
    216. std::cout << "###" << _statuCode << std::endl;
    217. std::cout << "###" << _codeDescripetion << std::endl;
    218. std::cout << "###" << _text << std::endl;
    219. }
    220. private:
    221. // 构建响应必要的字段
    222. std::string _httpVersion; // http版本
    223. int _statuCode; // 状态码
    224. std::string _codeDescripetion; // 状态码描述
    225. std::unordered_map _kv; // 响应报头的kv模型
    226. // 构建响应的必要行
    227. std::string _statusLine; // 状态行
    228. std::string _respondHeader; // 请求头
    229. std::string _blankLine; // 空行
    230. std::string _text; // 正文
    231. };
    232. class Factor
    233. {
    234. public:
    235. static std::shared_ptr BuildHttprequest() //使用智能指针构建应答
    236. {
    237. return std::make_shared();
    238. }
    239. static std::shared_ptr BuildHttprepond()
    240. {
    241. return std::make_shared();
    242. }
    243. };
    244. class httpserver
    245. {
    246. public:
    247. httpserver()
    248. {
    249. _mime.insert(std::make_pair(".html", "text/html"));
    250. _mime.insert(std::make_pair(".jpg", "image/jpeg"));
    251. _mime.insert(std::make_pair(".png", "application/x-plt"));
    252. _Statuscode_Descripetion.insert(std::make_pair(100, "continue"));
    253. _Statuscode_Descripetion.insert(std::make_pair(200, "ok"));
    254. _Statuscode_Descripetion.insert(std::make_pair(301, "Moved Permanently")); // 永久重定向
    255. _Statuscode_Descripetion.insert(std::make_pair(302, "Found")); // 临时重定向
    256. _Statuscode_Descripetion.insert(std::make_pair(400, "Bad Request"));
    257. _Statuscode_Descripetion.insert(std::make_pair(404, "Not Found"));
    258. _Statuscode_Descripetion.insert(std::make_pair(404, "Not Found"));
    259. }
    260. std::string readFileContent(const std::string &path, int &filesize)
    261. {
    262. // std::cout<< path <
    263. std::ifstream in(path, std::ios::binary);
    264. if (!in.is_open())
    265. {
    266. return std::string();
    267. }
    268. in.seekg(0, in.end);
    269. filesize = in.tellg();
    270. in.seekg(0, in.beg);
    271. // std::cout << filesize << std::endl;
    272. if (filesize < 0)
    273. {
    274. filesize = 0;
    275. }
    276. std::string content;
    277. content.resize(filesize);
    278. in.read((char *)content.c_str(), filesize);
    279. in.close();
    280. return content;
    281. }
    282. void addhander(std::string path, fun_t handler)
    283. {
    284. std::string tmp = webroot + path;
    285. _funcs.insert(std::make_pair(tmp, handler));
    286. }
    287. #define VERSION_1
    288. std::string httpHandler(std::string req)
    289. {
    290. #ifdef VERSION_1
    291. std::cout << req << std::endl;
    292. auto request = Factor::BuildHttprequest();
    293. request->Deserialize(req);
    294. //Log(Info, "method %s", request->method().c_str());
    295. // Log(Info,"s","redir ----------------------");
    296. // if(request->path() == "./webroot/redir")//进行重定向
    297. // {
    298. // code = 302;
    299. // respond->addHander("Location", "https://www.csdn.net/?spm=1011.2266.3001.4476");
    300. // respond->addStatusLine(code, _Statuscode_Descripetion[code]);
    301. // }
    302. if (request->isServiceReq())//当前请求的是一个服务
    303. {
    304. Log(Info, "method %s", request->method().c_str());
    305. Log(Info, "method %s", request->path().c_str());
    306. auto response = _funcs[request->path()](request);
    307. return response->Serialize();
    308. }
    309. else // 当前请求的是一个服务器资源
    310. {
    311. int code = 200;
    312. int filesize = 0;
    313. auto respond = Factor::BuildHttprepond();
    314. std::string content = readFileContent(request->path(), filesize);
    315. if (content.empty())//没有读到任何内容,说明请求不存在
    316. {
    317. code = 404;
    318. respond->addStatusLine(code, _Statuscode_Descripetion[code]);
    319. respond->addHander("Content-Type", ".html");
    320. std::string content404 = readFileContent("./webroot/404.html", filesize);
    321. respond->addText(content404);
    322. }
    323. else//请求存在
    324. {
    325. respond->addStatusLine(code, _Statuscode_Descripetion[code]);/
    326. std::string suffix = request->getSuffix();//获取资源的后坠
    327. respond->addHander("Content-Type", _mime[suffix]);
    328. respond->addHander("Content-Length", std::to_string(filesize));
    329. respond->addText(content);
    330. }
    331. return respond->Serialize();
    332. }
    333. #else
    334. std::cout << "version control" << endl;
    335. #endif
    336. }
    337. private:
    338. std::unordered_map _mime; // 文件后缀,对应的content type类型
    339. std::unordered_map<int, std::string> _Statuscode_Descripetion; // 状态码 对应的描述
    340. std::unordered_mapfun_t> _funcs; // 将请求回调出去
    341. };

  • 相关阅读:
    【Unity3D】发射(RayCast)物理射线(Ray)
    hypermesh学习总结(一)
    Codesys + BeagleBone PLC控制达到小儿科水平
    一个完整的测试流程包括哪些?测试人员需要做什么?
    用Python分析了30000+《独行月球》影评数据,看看观众们怎么说~
    Centos内网服务器搭建NTP时间同步服务
    python-opencv视频中的人脸检测
    OpenJudge NOI 2.1 15:Counterfeit Dollar
    【CSS布局】结构伪类选择器、伪元素、浮动
    el-cascader组件根据最后一级向上找到父级并设置默认值
  • 原文地址:https://blog.csdn.net/W2155/article/details/142219395