当前位置: 首页 > news >正文

网络协议——HTTP协议

目录

​编辑

一,HTTP协议基本认识

二,认识URL

三,http协议的格式

 1,发送格式

2,回应格式 

四,服务端代码

五,http报文细节

1,Post与Get方法

2,Content_lenth

 3,状态码

4,Location

5,content_type

6,cookie

​编辑


一,HTTP协议基本认识

      在我之前写的文章中,我实现过自定义协议。但是,在实际的网络编程中我们是不太需要定制协议的。因为前辈早就定制好了。而HTTP协议就是其中的一种。 http协议又被叫做超文本传输协议,这是因为http的本质其实就是按照http协议从服务端拿文件资源。而http协议能够拿走所有的文件资源,所以http协议又被叫做超文本传输协议。

二,认识URL

URL:Uniform Resource Locator,中文名叫统一资源定位符。

 URL的样子如下:

http://www.example.com/path/to/resource?query=string#fragment
  • http:// 是协议部分,表示这是一个使用 HTTP 协议的 URL。
  • www.example.com 是域名部分,表示资源所在的服务器的地址。
  • /path/to/resource 是路径部分,表示服务器上资源的具体位置。
  • ?query=string 是查询字符串部分,用于传递参数给服务器。
  • #fragment 是片段标识符部分,用于指定资源的某一部分,通常用于网页的导航。

域名其实就是ip地址,那为什么只要有ip地址就可以访问到主机上的唯一资源呢?

因为http的端口号是默认绑定的,是统一的不需要我们再来绑定。 

urlencode与urldecode

urlencode:在url中有些符号是被url默认使用了的。比如:?://。当我们的用户输入的url中带有这些字符时这些字符就会被encode。encode的规则是:将对应的字符的ASSCALL码转化为16进制,然后在前面加上%。urldecode就是反过来。当然,这个过程并不需要我们来做,有相应的工具可以帮我们完成:urlencode&&urldecode工具

三,http协议的格式

 1,发送格式

当我们以http为协议向服务端发送请求时,我们发送的数据会包含如下数据:

1,请求行

2,请求报文

3,一个空行

4,请求正文

在请求行,包含如下数据:

1,method   2,url   3,http version  4,"\r\n"

图示如下:

2,回应格式 

 当服务器在将数据发送回客户端时,会依照如下何时将数据返回:

1,状态行

2,响应报文

3,空行

4,响应正文

在状态行内,包含如下数据:

1,http version  2,状态码  3,状态码描述  4,“"\r\n"

图示如下:

四,服务端代码

在了解了http发送消息和响应消息的数据发送格式以后,我们便可以来动手写上一个能够按照http协议的格式进行响应的服务端。

实现如下:

1,为了能够更方便的使用创建套接字的接口,我对创建套接字的接口做如下封装

#pragma once
#include<iostream>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include<cstring>
#include<arpa/inet.h>
#include<unistd.h>//定义一些变量
#define blog 10
#define defaultport 8080class Socket
{public://构造函数Socket(): sockfd_(0){}public://创建套接字bool Sock(){sockfd_ = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字if (sockfd_ < 0){std::cerr <<  "创建套接字失败" << std::endl;return false;}int opt = 1;setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));return true; // 将创建好的套接字返回}//bind,服务端只要绑定端口号bool Bind(int port = defaultport){sockaddr_in server_addr;memset(&server_addr, 0, sizeof (server_addr));//清空数据server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);server_addr.sin_addr.s_addr = INADDR_ANY;int r1 = bind(sockfd_,(sockaddr*)&server_addr,sizeof server_addr);if(r1<0){std::cerr << "bind err" << std::endl;return false;}return true;}//监听bool Listen(){int r2 =  listen(sockfd_, blog);if(r2<0){std::cerr << "listen err" << std::endl;return 0;}return true;}//接收int Accept(std::string* ip,int* port){sockaddr_in cli_addr;socklen_t len = sizeof(cli_addr);int sockfd = accept(sockfd_, (sockaddr *)&cli_addr, &len);if(sockfd<0){std::cerr << "accept err" << std::endl;return -1;}char buff[64]={0};inet_ntop(AF_INET, &cli_addr, buff, sizeof(buff));*ip = buff;*port = ntohs(cli_addr.sin_port);return sockfd;}//连接bool Connect(std::string& ip,int16_t port){sockaddr_in addr_;addr_.sin_family = AF_INET;addr_.sin_port = htons(port);inet_pton(AF_INET, ip.c_str(), &(addr_.sin_addr));int r = connect(sockfd_, (sockaddr *)&addr_, sizeof (addr_));if(r<0){std::cerr << "connect err" << std::endl;return false;}return true;}//关闭void Close(){close(sockfd_);}public://成员int sockfd_;
};

2,服务端代码

 在做好上述封装工作以后便可以来构建服务端了,服务端的创建步骤如下:

1,类成员

1,listensockfd_:  Sock类成员。主要是为了调用创建套接字的接口。

2,port_:端口号,主要是为了绑定时使用。

2,构造函数

初始化port_ 

3,Init函数

创建套接字  bind套接字  监听套接字

4,Start函数

1,循环接收服务端发来的连接请求,然后创建线程执行相应的任务。

2,读出客户端发来的请求。

3,然后根据http协议将请求处理出来到req中。

4,根据url判断客户端想要请求的资源是服务器那个资源。

5,读出资源发送回客户端。 

 在理清上面创建服务端的过程以后,便可以写出如下代码:


struct ThreadData
{int sockfd;
};class HttpServer
{public:HttpServer(int port):port_(port){}  void Init(){listensocket_.Sock();//创建套接字listensocket_.Bind(port_);//绑定套接字端口listensocket_.Listen();//监听套接字}bool Start(){while (true){// 建立连接std::string ip;int port;int sockfd = listensocket_.Accept(&ip, &port_);lg(Debug, "link->%s:%d sucess,sockfd:%d", ip.c_str(), port_,sockfd);// 创建线程执行任务pthread_t td;ThreadData ts;ts.sockfd = sockfd;pthread_create(&td, nullptr, ThreadRun, &ts);}return true;}static void* ThreadRun(void*args){pthread_detach(pthread_self());//与主线程分离ThreadData* ts = static_cast<ThreadData*>(args);Helper(ts->sockfd);//处理客户端发来的消息delete ts;return nullptr;}private:Socket listensocket_;int port_;};

 如何处理客户端发来的消息?

代码如下:

static void Helper(int sockfd){// 接收消息并打印char buff[1024] = {0};int n = recv(sockfd, buff, sizeof(buff), 0);if (n > 0){   //显示读出来的消息buff[n] = 0;std::cout << buff << std::endl;//读出来的消息进行解析处理,得到客户端想要访问什么资源Request req;req.Deserialize(buff);req.prase(buff);std::string path = req.Select_path();path = rootpath + path;std::cout << "debug: " << std::endl;req.Debugprint();//根据http协议的方式将资源发送会给客户端std::string text = Readrequest(path);std::string response;std::string sep = "\r\n";std::string line = "HTTP 1.1  1  OK";line += sep;std::string head = "contentlenth:";std::string len = std::to_string(text.size());head += len;head += sep;head += sep;response+=line;//状态行response += head;//报头response += text;//正文send(sockfd, response.c_str(), response.size(), 0);}}

如何对客户端的发来的消息进行处理呢? 

 创建一个Request类,这个类里面含有如下成员:

1, std::vector<std::string> arr  :对内容进行分割   

2, std::string text   :将正文提取出来

######################################

3,std::string method :接收方法                      

4,std::string url   :显示网址

5,std::string http_version :显示http的版本  

 6, std::string path :表示路径

类方法如下:

1,Deseralize: 对从客户端接收到的消息里的请求行和报文进行打散,打散到我的arr数组里面。并将正文提取出来。

2,prase:打散后,arr[0]便代表着请求行,包含着三个信息:method   url    http version。通过prase函数将这些消息获取出来。

3,DebugPrint:显示相应的消息。用于debug。

4,select_path:选择路径。

实现如下:

class Request
{public:void Deserialize(std::string message){while (true)//循环读取{int pos = message.find(sep);if(pos == std::string ::npos){break;}std::string str = message.substr(0, pos);if(str.empty())break;arr.push_back(str);message.erase(0, pos + 1);//读一行消一行}text = message;}void prase(std::string message)//将状态行的信息散开{std::stringstream s (message);s >> method >> url >> http_version;}void Debugprint(){for(auto e:arr){std::cout << e <<" "<<std::endl ;}std::cout << "method:" << method << std::endl;std::cout << "url:" << url << std::endl;std::cout<< "http_version:" << http_version << std::endl;}std::string Select_path(){if(url == "/"||url == "/html.index"){path = rootpath+"/";}else {path = url;}return path;}private:std::vector<std::string> arr;std::string text;std::string method;std::string url;std::string http_version;std::string path;
};

返回消息:

当我们处理了客户端发来的消息以后,便可以得到客户端想要的资源在那个路径下。于是我们便可以将该路径对应的文件的内容读出来并返回给客户端显示。

读取文件的函数如下:

std::string Readrequest(std::string path)//从文件内读取
{   std::ifstream in(path);if(!in.is_open())return "404";std::string line;std::string content;while(getline(in,line)){content += line;}return content;//这个消息会拼接到正文,也就是text
}

五,http报文细节

1,Post与Get方法

 在http的请求报头当中,经常使用的请求方法有如下两个:1,Post   2,Get

Post:

Post方法在提取form表单的参数时,通常会将参数放到正文部分来提交参数。

Get:

Get方法在提取表单的参数时,通常会将参数放到url的后面来提交参数。

相对于Get方法,Post方法提交参数的方式比较隐蔽。但是两种提交参数的方式都是不安全的。因为通过抓包都可以将报文抓取然后获取报文的所有内容。如果想要安全就得加密,加密协议就是https协议。

2,Content_lenth

在相应报文的报头里面有一个Content_lenth的字段,代表着正文的长度。报头与正文之间通过一个空行来分隔,分割以后,正文内容的大小由Content_lenth来指定,进而进行读取。

 3,状态码

在http报文当中,相应报文内的状态行中会有一串数字表示响应的状态。

比如,200就代表正常,状态码描述便是ok。

通常,状态码对应的消息如下

1xx:信息型状态码。

2xx:代表请求ok,如200。

3xx:代表重定向,如301(永久重定向) 302(临时重定向)。

4xx:代表客户端请求错误,如404。

5xx:代表服务端内部错误,如501。

4,Location

Location字段一般都是和重定向状态3xx搭配使用的。当我的客户端申请访问我们已经移动后的资源时,服务端的Location字段便会指引客户端去访问移动后的资源。

5,content_type

content_type标识的是正文的文件类型。这个,content_type放在报头,指明文件类型,进而让客户端以正确的类型收取文件资源显示文件资源。

6,cookie

cookie字段的作用是储存少量信息,用于搭建临时会话。

在我们的浏览器上,其实每次访问一个资源都是需要认证的。比如你在一个浏览器上第一次访问b站,我们是不是要进行登录认证呢?是的吧,那我们看b站上的视频需不需要进行认证呢?其实也是需要的,但是cookie已经帮你吧认证信息存储起来了,所以会帮你自动登录认证。

分类:

cookie文件一般分为内存文件和硬盘文件。为了安全,一般都会设置为内存文件(会定时清理)。比如在edge 浏览器上便是内存文件。 

更完整细节: 

HTTP方法:

相关文章:

网络协议——HTTP协议

目录 ​编辑 一&#xff0c;HTTP协议基本认识 二&#xff0c;认识URL 三&#xff0c;http协议的格式 1&#xff0c;发送格式 2&#xff0c;回应格式 四&#xff0c;服务端代码 五&#xff0c;http报文细节 1&#xff0c;Post与Get方法 2&#xff0c;Content_lenth 3&…...

八股面试——数据库——索引

索引的概念 B树的概念&#xff1a; 索引的作用 聚簇索引与非聚簇索引 聚簇索引就是主键值&#xff0c;在B树上&#xff0c;通过主键大小&#xff08;数据在B树叶子节点按主键顺序排序&#xff09;寻找对应的叶子节点&#xff0c;叶子节点保存的一整条记录。 非聚簇索引&#x…...

【二分查找】Leetcode 二分查找

题目解析 二分查找在数组有序可以使用&#xff0c;也可以在数组无序的时候使用&#xff08;只要数组中的一些规律适用于二分即可&#xff09; 704. 二分查找 算法讲解 当left > right的时候&#xff0c;我们循环结束&#xff0c;但是当left和right缩成一个点的时候&#x…...

Python+Vuecil笔记

Nginx 进入目录: C:\nginx-1.20.2\nginx-1.20.2 start nginx 开始 nginx -s stop 停止 nginx -s quit 退出CSS 通过标签去写css 循环展示数据 JS 点击时执行事件 Django 配置media 在seetings里面修改 STATIC_URL /static/ MEDIA_URL /upload/ MEDIA_ROOT os.pat…...

C语言关于随机数知识点的总结

在C语言中&#xff0c;随机数的生成通常依赖于特定的库函数&#xff0c;最常用的是 <stdlib.h> 头文件中的 rand() 函数。以下是对随机数知识点的总结、举例和分析&#xff1a; 随机数知识点总结 1.随机数种子&#xff1a;rand() 函数生成的随机数是伪随机数&#xff0…...

网络应用层和传输层

网络中有很多协议这些协议的不同导致了分层这一现象&#xff0c;不同层的主要功能不一样。 应用层&#xff1a;应用程序。数据具体如何使用 传输层&#xff1a;关注起点和终点 网络层&#xff1a;关注路径规划 数据链路层&#xff1a;关注相邻节点的转发 物理层&#xff1…...

Vue3:优化-从响应式数据中获取纯数据

一、情景说明 我们知道&#xff0c;Vue3中&#xff0c;创建变量时&#xff0c;常用ref、reactive来包裹&#xff0c;这样&#xff0c;这个变量就是响应式数据 然而&#xff0c;有时候&#xff0c;我们只需要纯数据 例如&#xff0c;我们在调用后端接口的时候&#xff0c;我们只…...

C#.手术麻醉系统源码 手麻系统如何与医院信息系统进行集成?

C#.手术麻醉系统源码 手麻系统如何与医院信息系统进行集成&#xff1f; 手术麻醉系统与医院信息系统的集成是一个关键步骤&#xff0c;它有助于实现信息的共享和流程的协同&#xff0c;从而提高医疗服务的效率和质量。手麻系统与lis、his、pacs等系统的对接是医院信息化建设的重…...

学习CSS Flexbox 玩flexboxfroggy flexboxfroggy1-24关详解

欢迎来到Flexbox Froggy&#xff0c;这是一个通过编写CSS代码来帮助Froggy和朋友的游戏! justify-content 和 align-items 是两个用于控制 CSS Flexbox 布局的属性。 justify-content&#xff1a;该属性用于控制 Flexbox 容器中子项目在主轴&#xff08;水平方向&#xff09;…...

springboot项目如何配置跨域?

在Spring Boot项目中配置跨域&#xff08;CORS&#xff0c;Cross-Origin Resource Sharing&#xff09;主要是为了允许来自不同源&#xff08;不同的协议、域名或端口&#xff09;的前端应用能够访问后端API。Spring Boot提供了多种方式来配置跨域支持。 1. 使用CrossOrigin注…...

实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类

devc 5.11编译环境 dll编译环境设置参考 Dev c C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 插件 DLL代码和主程序代码如下 注意 dll 代码中的class 类名需要 和主程序 相同 其中使用了函数指针和强制类型转换 函数指针教程参考 以动态库链接库 .dll 探索结构体…...

算法第三十九天-验证二叉树的前序序列化

验证二叉树的前序序列化 题目要求 解题思路 方法一&#xff1a;栈 栈的思路是「自底向上」的想法。下面要结合本题是「前序遍历」这个重要特点。 我们知道「前序遍历」是按照「根节点-左子树-右子树」的顺序遍历的&#xff0c;只有当根节点的所有左子树遍历完成之后&#xf…...

Rust---复合数据类型之字符串与切片(2)

目录 字符串操作删除 (Delete)连接 (Concatenate)字符串转义前情回顾: Rust—复合数据类型之字符串(1) 字符串操作 删除 (Delete) 删除方法仅适用于 String 类型,分别是: pop(),remove(),truncate(),clear(),此外还有drain() 方法。 pop 方法:pop() 方法返回一个 O…...

iOS 应用内网络请求设置代理

主要通过URLSessionConfiguration 的connectionProxyDictionary 属性 为了方便其他同学使用&#xff0c;我们可以通过界面来进行设定&#xff08;是否开启代理、服务端、端口&#xff09;&#xff0c;从而达到类似系统上的设定 具体链接参考&#xff1a;为 iOS 网络请求设置代理…...

什么是MariaDB

2024年4月6日&#xff0c;周六晚上 今晚在Debian12上安装mysql时&#xff0c;运行后却发现是MariaDB MariaDB是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支和替代品。MariaDB由MySQL的原始开发者之一Michael "Monty&qu…...

【面试八股总结】传输控制协议TCP(三)

参考资料 &#xff1a;小林Coding、阿秀、代码随想录 一、TCP拥塞控制⭐ 1. 慢启动 – Slow Start 慢启动是指TCP连接刚建立&#xff0c;一点一点地提速&#xff0c;试探一下网络的承受能力&#xff0c;以免直接扰乱了网络通道的秩序。 慢启动算法&#xff1a; 初始拥塞窗口…...

今年过去了多少天?(switch)

//今年已经过去了几天&#xff1f; #include <stdio.h> int monthday(int year,int month){switch(month){case 1:return 31;case 2:if ((year % 4 0 && year % 100 ! 0)||year % 400 0){return 29;}else{return 28;}break;case 3:return 31;case 4:return 30;…...

提升团队工程交付能力,从“看见”工程活动和研发模式开始

作者&#xff1a;张裕、雅纯 理想中的研发团队应当具有以下特征&#xff1a; 总是工作在最高优先级的事项上 理想的研发团队能够识别并始终集中精力在当前最紧迫和最有价值的任务上。这需要团队具备出色的项目管理能力和决策能力&#xff0c;以便能够正确评估优先级&#xff0…...

前端学习之DOM编程案例:全选反选案例

代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>全选反选</title> </head> <body><input type"checkbox" id"all">全选<ul><li><…...

golang map

1.底层实现 2.如何解决hash冲突 3.扩容机制 4.无序 5.非线程安全 6.不可寻址 runtime/map.go 1.底层实现 底层基于hash表实现&#xff0c;实现有2个结构体hmap&#xff0c;bmap&#xff0c;map由若干个桶存储&#xff0c;每个桶存8个元素&#xff0c;使用链地址解决hash冲突 …...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

【C++】纯虚函数类外可以写实现吗?

1. 答案 先说答案&#xff0c;可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...