当前位置: 首页 > 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冲突 …...

微信聊天记录永久保存与智能分析:WeChatMsg完全使用指南

微信聊天记录永久保存与智能分析&#xff1a;WeChatMsg完全使用指南 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeC…...

3分钟打造macOS级桌面体验:开源光标主题全攻略

3分钟打造macOS级桌面体验&#xff1a;开源光标主题全攻略 【免费下载链接】apple_cursor Free & Open source macOS Cursors. 项目地址: https://gitcode.com/gh_mirrors/ap/apple_cursor 你知道吗&#xff1f;每天在电脑前工作8小时&#xff0c;你的鼠标指针会出现…...

终极指南:如何使用Rainmeter构建内存使用趋势预测模型(ARIMA/SVM应用)

终极指南&#xff1a;如何使用Rainmeter构建内存使用趋势预测模型&#xff08;ARIMA/SVM应用&#xff09; 【免费下载链接】rainmeter Desktop customization tool for Windows 项目地址: https://gitcode.com/gh_mirrors/ra/rainmeter Rainmeter作为一款强大的Windows桌…...

OpenClaw+Qwen3.5-4B-Claude:5个提升效率的CLI增强技能

OpenClawQwen3.5-4B-Claude&#xff1a;5个提升效率的CLI增强技能 1. 为什么需要CLI增强技能 作为一个长期与终端打交道的开发者&#xff0c;我发现自己每天要重复输入大量相似命令。比如查看日志时要反复输入tail -f加路径&#xff0c;管理Docker时要不断敲docker ps -a。更…...

Hunyuan-MT-7B应用案例:国际展会AI同传助手系统后端架构设计

Hunyuan-MT-7B应用案例&#xff1a;国际展会AI同传助手系统后端架构设计 1. 项目背景与需求分析 国际展会现场的同声传译一直是技术难题。传统人工翻译成本高昂&#xff0c;且难以覆盖所有语言组合。随着多语言大模型的发展&#xff0c;AI同传系统成为可行的解决方案。 Huny…...

从数组到哈夫曼树:用Python代码图解软考数据结构核心算法

从数组到哈夫曼树&#xff1a;Python实战软考核心数据结构 1. 线性结构的Python实现 1.1 顺序栈与队列的实现 Python的列表(list)天然适合实现顺序存储结构。我们先来看栈的实现&#xff1a; class ArrayStack:def __init__(self, capacity10):self._items []self._capacity …...

还在手工整理IT报表?这套自动化模板让你彻底解放双手

在不断变化的IT管理环境中&#xff0c;透明度和合规性已成为企业生存和发展的基石。面对日益繁杂的法规与标准&#xff0c;组织需要精细的报表与审计流程来支撑业务稳健运行。作为一款专为现代IT打造的尖端平台&#xff0c;Endpoint Central不仅大幅减轻了合规负担&#xff0c;…...

从Siwave导入模型到Q3D仿真,如何避免‘幽灵’solder导致的网络报错?

从Siwave到Q3D的模型迁移&#xff1a;彻底解决"幽灵焊料"引发的网络冲突 当你在Ansys电子设计自动化工具链中切换工作环境时&#xff0c;是否遇到过这样的困扰&#xff1a;从Siwave精心准备的模型导入Q3D后&#xff0c;突然冒出各种莫名其妙的网络重叠报错&#xff…...

【Mojo+Python混合部署失效真相】:92%开发者忽略的编译期符号冲突、运行时上下文隔离与调试断点丢失问题

第一章&#xff1a;MojoPython混合部署失效真相全景概览Mojo 作为新兴的高性能系统编程语言&#xff0c;设计初衷是与 Python 生态无缝互操作&#xff1b;然而在真实生产部署中&#xff0c;“Mojo Python 混合部署”常出现静默失败、ABI 不兼容、运行时崩溃或性能断崖式下降等…...

压力型旋流喷嘴内喉部一点横向流体运动

&#xff08;一&#xff09;单图逐段解读图 1&#xff1a;0~0.0045s 全时段曲线&#xff08;含完整瞬态 准稳态&#xff09;分段特征与机理瞬态冲击段&#xff08;0~0.0002s&#xff09;曲线特征&#xff1a;极端剧烈的高频正负震荡&#xff0c;峰值接近 2m/s&#xff0c;是全…...