HTTP详解及代码实现

HTTP详解及代码实现

  • HTTP
    • 超文本
    • 传输
    • 协议
  • URL简述
  • 状态码
    • 常见的状态码
  • 请求方法
  • 请求报文
  • 响应报文
  • HTTP常见的Header
  • HTTP服务器代码

HTTP

  HTTP的也称为超文本传输协议。解释HTTP我们可以将其分为三个部分来解释:超文本,传输,协议。

超文本

  加粗样式超文本从字面意思就是超越了文本。在计算机发展初期,计算机只能传输使用文本数据,随着技术发展,出现了图片,视频,音频,超链接等,这些数据就可以统称为超文本

传输

  传输这个词从字面上很好理解,没有什么需要介绍的,事实也是如此。http中的传输意味着数据需要由发送方发送到接收方,这是废话,但是真正需要我们注意的是,HTTP是在两点之间传输的
  那可以实现多点之间传输吗?HTTP是基于TCP的,TCP是只能两点之间传输数据的。所以HTTP也只能是两点之间传输的。
  但是HTTP3.0是基于UDP的啊,可以多点传输吗?对于HTTP/3.0(基于QUIC),虽然它是基于UDP的,但它主要是为了解决传统TCP在性能上的一些限制而设计的,并不是为了直接支持多点传输。

协议

  协议这个词在我们的印象里面就是规则,在计算机世界里面,就是用来约束某些行为的规则。它是用计算机能够理解的语言,确立的一种计算机之间进行交流通信的一种规范,以及相关的控制和错误处理方式。


  所以HTTP是什么呢? 总结一下,就是在计算机世界里面,用来在两点之间传输图片,音频,视频,超链接等超文本数据的一种约定和规范。

URL简述

URL也叫做统一资源定位器,用来唯一定位全网中的资源。可以认为有了它就能够没有歧义的直接在网络中找到相应的资源。

https://editor.csdn.net/md?not_checkout=1&spm=1010.2135.3001.5352&articleId=137425440

上面这一串就是我当前写这篇博客的URL(当然你没有账号密码访问不了)。

  • https:// :这是协议名称,有http和https可选。
  • editor.csdn.net/ : 这是资源所在的服务器地址,也就是域名。
  • md : 这是资源的路径名。
  • ? : 这个是分割开资源路径名和查询参数的分隔符,**#**也有分隔的作用,不过上面URL中没有体现。
  • spm=1010.2135.3001.5352&articleId=137425440 : 这个是查询参数,用&分割开来,这些参数由客户端给服务端,用来指定资源。
  • # : 上面URL中没有体现这个。#后面是片段标识符id, 浏览器在加载该URL时会滚动到页面中对应的片段位置。

状态码

  HTTP的状态码是存在于响应报文中的。
它有以下五类:

  • 1** : 表示请求正在被处理,是一种中间状态。
  • 2** :表示请求成功被处理。
  • 3** :重定向状态码,这里的重定向指的是当前请求资源的位置发生变动,需要使用新的URL去请求新的资源。
  • 4** : 客户端的请求报文有误,服务端无法处理请求。
  • 5** : 服务端在处理请求时内部出现的问题导致无法正常处理请求。

常见的状态码

  • 200:请求成功,响应的头部会有body数据。
  • 204:请求成功,响应的头部没有body数据。
  • 301:永久重定向,请求的资源已经不存在了,需要使用新的URL请求资源。
  • 302:临时重定向,请求的资源还在,但是需要暂时的访问新的URL。
  • 304:这个是服务端告诉客户端,资源没有修改,浏览器本地缓存的资源依旧可以使用,重定向到本地资源。
  • 400:笼统的表示客户端发送的报文有误。
  • 403:服务器禁止访问,客户端并没有错误。
  • 404:在服务端中没有找到相应的资源或是资源不存在。
  • 500:笼统的表示服务端发生了错误。
  • 501:客户端请求的功能还不支持。
  • 502:通常是服务器作为网关或者代理的时候返回的状态码,表示自己没有问题,但是发送给后端服务器时发生了错误。
  • 503:服务器繁忙,暂时无法响应客户端。

请求方法

  出现在请求报文中,用来说明使用什么样的方法请求资源。
在这里插入图片描述

请求报文

  这是HTTP请求资源时发送的报文。
在这里插入图片描述
在这里插入图片描述
  首行包括:请求方法 + URL + HTTP版本号
在这里插入图片描述
  首行下面的就是请求头部,使用key:value的格式,简单且利于理解,每一对key:value占据一行,行末使用\r\n回车换行来分割每一对key:value。
  头部末尾空出一行来将头部和body分割开来。

在这里插入图片描述
  这是Body,可以发送一些数据来指定资源或者对指定资源做出处理,允许为空,若不为空,头部会使用Content-Length来表示Body长度。
  大家或许发现了Body中的数据和URL中?后面的参数很像,这并不是偶然。他们两个的作用都是为了获取指定资源或是对指定的资源做出处理,如果请求方法为POST,则参数在Body中,如果请求方法为GET,则参数在URL中,具体细节本文不做展开解释。当然Body中不仅仅局限于传递参数的作用。

响应报文

  响应报文是服务端用来对客户端请求的响应的。
在这里插入图片描述

  • 首行:版本号 + 状态码 + 状态码解释
  • 响应头部:跟请求头部一样使用key:value的格式。
  • Body:如果有Body,则Body和头部之间会有一个空行(\r\n),上图中的Body里面就是一个html代码,向客户端返回了一个html页面。

HTTP常见的Header

  • Host:请求报文中。用于指明请求的服务器的域名。
  • Connection:请求和响应报文中都有。用于说明是否使用长连接,如果使用,则设为 keep-alive。如果不使用长连接,也就是使用短连接,则设为:clone
  • Content-Type:请求报文和响应报文都有。其中的value是Body数据的长度。Header和Body的区分是通过一个空行实现的,有了Content-Type字段,也就可以确定了Body的界限了。
  • Content-Type:响应报文中。用来告诉客户端返回的数据是什么格式的。
  • Accept-Type:请求报文中,用来告诉服务端自己能够接受什么类型的。
  • Content-Encoding:响应报文。用来告诉服务器返回的数据使用了什么压缩格式。
  • Accept-Encoding:请求报文:用来告诉服务端自己能够接受什么压缩格式。
  • Cookie: 请求报文和响应报文都有。用于存储客户端的少量信息. 通常用于实现会话(session)的功能;
  • Location:响应报文中。当状态码为3**时,说明为重定向,Location字段就是指明了重定向的位置,可以为URL外部资源,也可以指向本地资源(比如304)。
  • Referer: 当前页面是从哪个页面跳转过来的;

HTTP服务器代码

// http.cpp
#include <iostream>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <jsoncpp/json/json.h>
#include <fstream>
#include <stdio.h>
#include <string>
#include <fstream>#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>#define ROOT "./wwwroot"
#define HOMEPAGE "a.html"#include "Util.hpp"int main(int argc, char *argv[])
{if (argc != 3){std::cout << "You should " << argv[0] << " ip port\n";return 1;}int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0){std::cout << "Fail to sock: " << strerror(errno) << std::endl;return 2;}int opt = 1;struct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(atoi(argv[2]));local.sin_addr.s_addr = inet_addr(argv[1]);int bind_flag = bind(sock, (struct sockaddr *)&local, sizeof(local));if (bind_flag < 0{std::cout << "Fail to bind: " << strerror(errno) << std::endl;return 3;}int listen_flag = listen(sock, 10);if (listen_flag < 0){std::cout << "Fail to listen: " << strerror(errno) << std::endl;return 4;}// Start Serverwhile (true){struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int client_sock = accept(sock, (struct sockaddr *)&client_addr, &client_len);if (client_sock < 0){std::cout << "Fail to accept: " << strerror(errno) << std::endl;continue;}// char input_buffer[1024 * 10] = {0};// ssize_t input_size = read(client_sock, input_buffer, sizeof(input_buffer) - 1);// if (input_size < 0)// {//     std::cout << "Fail to read: " << strerror(errno) << std::endl;//     close(client_sock);//     continue;// }// char Server_buffer[1024 * 10] = {0};// std::cout << "[client request] " << input_buffer << std::endl;// Json::Value root;// int fd = open("../a.html", O_RDONLY);// const char *buf[1024 * 10];// read(fd, buf, sizeof(buf));// root["a"] = buf;// //Json::StyledWriter writer; // 这样会竖式的表示出来,便于调试// Json::FastWriter writer; // 这样会横式的表示出来// std::string s = writer.write(root);// const char *hello = "<br><br><br><br><br><h1>          你好你好!!我是汤环!!!</h1>";// sprintf(Server_buffer, "HTTP/1.0 200 OK\nConnection: keep-alive\nContent-Length: %lu\n\n%s", sizeof(hello), hello);char buffer[10240];ssize_t s = recv(client_sock, buffer, sizeof(buffer) - 1, 0);if (s > 0){buffer[s] = 0;std::cout << buffer << "--------------------\n"<< std::endl;}std::vector<std::string> vLine;Util::cutString(buffer, "\r\n", &vLine);std::vector<std::string> vBlock;Util::cutString(vLine[0], " ", &vBlock);std::string file = vBlock[1]; // 得到客户端请求中的文件路径std::string target = ROOT;target += file;std::string content;std::ifstream in(target);if (!in.is_open()){}else{std::string line;while (getline(in, line)){content += line;}in.close();Z}std::string HttpResponse;if (content.empty())HttpResponse = "HTTP/1.1 404 NOT FOUND\r\n";elseHttpResponse = "HTTP/1.1 200 OK\r\n";HttpResponse += "\r\n";HttpResponse += content;send(client_sock, HttpResponse.c_str(), HttpResponse.size(), 0);// write(client_sock, HttpResponse.c_str(), HttpResponse.size());close(client_sock);}return 0;
}
// Util.hpp#pragma once#include <iostream>
#include <vector>class Util
{
public:static void cutString(const std::string &s, const std::string &sep, std::vector<std::string> *out){std::size_t start = 0;while (start < s.size()){auto pos = s.find(sep, start);if (pos == std::string::npos)break;out->push_back(s.substr(start, pos - start));start += (pos - start);start += sep.size();}if (start < s.size())out->push_back(s.substr(start));}
};
// makefilehttp:http.cppg++ -o $@ $^ -std=c++11 -ljsoncpp.PHANY:clean
clean:rm -f http

     😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上线部署流程

音频地址&#xff1a;上线部署流程_小蒋聊技术在线播放免费听 - 喜马拉雅手机版 时间&#xff1a;2024年04月06日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 背景 大家好&#xff0c;欢迎来到小蒋聊技术&#xff0c;小蒋准…

正排索引 vs 倒排索引 - 搜索引擎具体原理

阅读导航 一、正排索引1. 概念2. 实例 二、倒排索引1. 概念2. 实例 三、正排 VS 倒排1. 正排索引优缺点2. 倒排索引优缺点3. 应用场景 三、搜索引擎原理1. 宏观原理2. 具体原理 一、正排索引 1. 概念 正排索引是一种索引机制&#xff0c;它将文档或数据记录按照某种特定的顺序…

Python 基于列表实现的通讯录管理系统(有完整源码)

目录 通讯录管理系统 PersonInformation类 ContactList类 menu函数 main函数 程序的运行流程 完整代码 运行示例 通讯录管理系统 这是一个基于文本的界面程序&#xff0c;用户可以通过命令行与之交互&#xff0c;它使用了CSV文件来存储和读取联系人信息&#xff0c;这…

开源数学计算软件Maxima基础学习

在Maxima中计算四则运算可以直接使用数学符号&#xff0c;在输入完公式后使用 EnterShift 快捷键进行计算 (%i1)11 输出 (%o1)2 这里面的 (%i1) 代表 input1 第1号输入&#xff0c;(%o1) 代表 output1 第1号输出。在执行计算后&#xff0c;(%i1)11 这一行命令后会出现一个…

2_5.Linux存储的基本管理

实验环境&#xff1a; 系统里添加两块硬盘 ##1.设备识别## 设备接入系统后都是以文件的形式存在 设备文件名称&#xff1a; SATA/SAS/USB /dev/sda,/dev/sdb ##s SATA, dDISK a第几块 IDE /dev/hd0,/dev/hd1 ##h hard VIRTIO-BLOCK /de…

【Python毕业设计】Python二手房拍卖网抓取工具设计与实现(源码+毕业论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

【攻防世界】FlatScience

dirsearch 扫描发现四个文件 在login.php 中发现 输入 http://61.147.171.105:61912/login.php/?debug 发现源码 <?php if(isset($_POST[usr]) && isset($_POST[pw])){$user $_POST[usr];$pass $_POST[pw];$db new SQLite3(../fancy.db);$res $db->query(…

SpringBoot新增员工模块开发

需求分析与设计 一&#xff1a;产品原型 一般在做需求分析时&#xff0c;往往都是对照着产品原型进行分析&#xff0c;因为产品原型比较直观&#xff0c;便于我们理解业务。 后台系统中可以管理员工信息&#xff0c;通过新增员工来添加后台系统用户。 新增员工原型&#xf…

设置你的第一个React应用

目录 一、React入门 1.1 你好React 1.2 创建React 1.3 应用结构 二、总结 2.1 定义组件 2.2 组件源码 三、组件详解 注意事项 3.1 组件三部曲 3.2 组件通信 —— props 3.3 对象数组迭代 —— map() 3.4 事件处理 3.5 钩子函数 —— useState() 初次学习最终效果…

深入浅出 -- 系统架构之负载均衡Nginx环境搭建

引入负载均衡技术可带来的收益&#xff1a; 系统的高可用&#xff1a;当某个节点宕机后可以迅速将流量转移至其他节点。系统的高性能&#xff1a;多台服务器共同对外提供服务&#xff0c;为整个系统提供了更高规模的吞吐。系统的拓展性&#xff1a;当业务再次出现增长或萎靡时…

重点:二维数组首地址的三种表示方式

上代码&#xff1a; 1. 表示子数组首地址的三种方法&#xff1a; arr是父亲地址 arr[0]是子数组的数组名 难点&#xff1a;arr[0] 是子数组的首地址 等价于 *(arr0) :0行0列 为什么等价呢&#xff1f; 因为当arr是二维数组的时候 *arr取的是列&#xff0c;子数组的地…

碘浊度法与红外相机联用测定食品中维生素C

&#x1f31e;欢迎来到看论文的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f4c6;首发时间&#xff1a;&#x1f339;2024年4月6日&…