Linux:http协议初步认识

文章目录

  • OSI七层模型
  • http协议
    • 域名
    • 路径信息
    • 请求和响应
  • 编写一个httpserver

OSI七层模型

在结束了前面对于序列化反序列化等内容的学习后,重新回到对于OSI模型的部分

在这里插入图片描述
在这里插入图片描述
如上所示的是对于OSI接口的示意图,在这当中可以看到会话层的概念,会话层的作用主要是建立断开连接管理的,相当于是在网络服务器中在TCP server中获取链接的过程,如果不需要这个链接,就在TCP server中把对应的链接关掉,而下面的表示层中写的是固有的数据格式和网络数据的转换,比如有接受不同形式的信息,文字,图像,声音等等,这个表示层其实就是在前面的部分中定义的协议

这个协议表示的就是固有的数据格式,比如说是序列化和反序列化这些内容,再比如有说网络序列转换为主机序列,或者是在缓冲区中定义了各种视频的名称格式等等,这些都是属于自定义协议的范畴,因此这些内容都是属于是表示层当中的信息

最后是应用层,应用层中有针对于特定应用的协议,比如说有电子邮件远程传输的问题,再比如有传输数据解析的问题,这些其实都是在应用层需要解决的问题

所以说这个OSI的这些层次结构就是已经提前定制好了未来的发展方式,把网络中需要的各个功能和网络中每一层的能力就都定制好了,那在表示层和应用层层相对比较好理解一些,无非就是定制协议的过程,那对于会话层的理解该如何深入理解呢?

对于会话的概念并不陌生,在将Linux终端的时候就有提及过这个session的概念,而当客户端链接到服务端后,如果一直不给服务器发送数据,那么对应的服务端就会一直阻塞在这里,那未来可以设置对应的一些策略,比如说超过5秒钟部进行发送消息,就把对应的链接自动关闭

因此,在定制OSI模型的时候,实际上会话表示应用这三层是不能定义在内核当中的,原因就是无论是这些当中的那一层,最终都必须要根据使用场景的不同,由程序员自己定义出对应的协议信息,然后才能有对应的序列化和反序列化的方法,如果用操作系统来全部实现,自然会引起一定的问题,所以就都交给用户自己来进行实现

http协议

域名

在前面的认知中,对于访问网络服务的概念是,可以使用一个ip地址和端口号来访问唯一一台主机上的唯一的一个进程,所以我们才可以用ip加端口号的方式来进行访问,但是现在的问题是,平时使用访问的都是使用一个网址来进行访问,没有使用端口号,这该如何理解呢?

事实上,的确在技术上用ip地址和端口号就可以实现这样的功能,但是在日常生活中作为用户会直接使用一个域名的内容来进行访问网站,因为域名的名字相比起来更加的好记忆,尤其是对于一些大型的网站都是直接用拼音来进行标注,方便用户来进行访问信息

所以就诞生了域名的概念,域名实际上在背后会被解析为对应的服务,这个技术上叫做是域名解析的概念,通过这个技术就能实现把域名转换为ip地址,因此当浏览器访问了特定的域名的时候,浏览器内部会内置一些地址,就能访问对应的域名解析的服务,这样就能转换为ip地址,我们以下面的这个例子为例

当访问百度一下这个网址的时候,都是直接访问这个www.baidu.com这个网址,而当在浏览器中访问的时候,其实在背后已经把这个域名转换成ip地址了,那这个怎么看呢?

在命令行中可以使用这样的命令来进行查看

在这里插入图片描述
由此我们就可以根据这个信息来进行访问百度了

在这里插入图片描述
https协议默认的端口号是80,所以本质上访问的是39.156.66.18:80/,关于这个问题后续再进行详谈

路径信息

对于每一个网址来说,其实是有固定的规则的:

在这里插入图片描述
未来会对带层次的文件路径进行解析,其他的字段不进行额外的讲解

请求和响应

下一步要谈论的主题是,关于http中的请求和响应的问题

http请求

http的请求是有固定格式的,下图画出http请求的具体格式:

在这里插入图片描述

下图展示的是http的一个请求:

在这里插入图片描述
如图所示的是http的一个请求,第一行表示的是POST方法,后面带有对应的URL网址信息,还有http协议版本,还有换行分割符这些信息,后续的内容都是对应的是请求报头,其中包含有对应的Key和Value信息,在结束之后是一个空行,也是作为一个分割的作用,最后一行的信息表示的是请求的正文,在这里表示的是一个用户名和密码的信息,后续会实现这个内容

这里对于这个\r\n进行一个理解:这两个表示的是,对于请求来说都是按行读取,这样可以读取到完整的一行,读取到完整的一行之后就能对于报头和有效载荷进行分离,进而进行后续的一些操作,那么现在的问题是在对于读取网络请求的时候,如何保证读取到的是一个完整的http请求呢?具体的做法是分析它的长度,并进行提取,这是我们之前的做法,而我们之前的做法本质上是一个自定义协议,而在对应的http协议如何保证?答案是保证不了,但是因为有这个\r和\n的存在,所以可以保证的是可以完整的读取到一个http的报头,之后就能进行解析,而在解析内容中就包含有长度这样的字段,所以说想要实现一个http的请求正确读取是一个非常繁琐的过程

http响应

那http响应该如何理解呢?在http的响应和请求几乎是完全一样的:

在这里插入图片描述

所以说此时对于请求和响应已经有了一个基本的视线了,那么下一步就是要进行序列化和反序列化,然后再进行对应的分割就可以,这都是可以解决的问题,所以在未来进行使用http实现网络通信的时候,就是一个发送请求,进行响应,再发送请求,再进行响应的一个过程

编写一个httpserver

那么下一步就直接进行编写一个httpserver来进行测试,这里我就直接用一份已经完备的httpserver来进行测试,主要想法是根据实验现象来理解http背后的细节原理

// socket.hpp
#pragma once#include <iostream>
#include <string>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"enum
{SocketErr = 2,BindErr,ListenErr,
};// TODO
const int backlog = 10;class Sock
{
public:Sock(){}~Sock(){}public:void Socket(){sockfd_ = socket(AF_INET, SOCK_STREAM, 0);if (sockfd_ < 0){lg(Fatal, "socker error, %s: %d", strerror(errno), errno);exit(SocketErr);}int opt = 1;setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));}void Bind(uint16_t port){struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = INADDR_ANY;if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, %s: %d", strerror(errno), errno);exit(BindErr);}}void Listen(){if (listen(sockfd_, backlog) < 0){lg(Fatal, "listen error, %s: %d", strerror(errno), errno);exit(ListenErr);}}int Accept(std::string *clientip, uint16_t *clientport){struct sockaddr_in peer;socklen_t len = sizeof(peer);int newfd = accept(sockfd_, (struct sockaddr*)&peer, &len);if(newfd < 0){lg(Warning, "accept error, %s: %d", strerror(errno), errno);return -1;}char ipstr[64];inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr));*clientip = ipstr;*clientport = ntohs(peer.sin_port);return newfd;}bool Connect(const std::string &ip, const uint16_t &port){struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));peer.sin_family = AF_INET;peer.sin_port = htons(port);inet_pton(AF_INET, ip.c_str(), &(peer.sin_addr));int n = connect(sockfd_, (struct sockaddr*)&peer, sizeof(peer));if(n == -1) {std::cerr << "connect to " << ip << ":" << port << " error" << std::endl;return false;}return true;}void Close(){close(sockfd_);}int Fd(){return sockfd_;}private:int sockfd_;
};
#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unordered_map>
#include "Socket.hpp"
#include "Log.hpp"const std::string wwwroot = "./wwwroot"; // web 根目录
const std::string sep = "\r\n";
const std::string homepage = "index.html";static const int defaultport = 8082;class HttpServer;class ThreadData
{
public:ThreadData(int fd, HttpServer *s) : sockfd(fd), svr(s){}public:int sockfd;HttpServer *svr;
};// 定义一个http的请求信息
class HttpRequest
{
public:// 对信息进行反序列化void Deserialize(std::string req){while (true){std::size_t pos = req.find(sep);if (pos == std::string::npos)break;std::string temp = req.substr(0, pos);if (temp.empty())break;req_header.push_back(temp);req.erase(0, pos + sep.size());}// 存储请求体的信息text = req;}// .png:image/png// 对信息进行解析void Parse(){// 解析请求的方法,URL,http版本std::stringstream ss(req_header[0]);ss >> method >> url >> http_version;// 设置默认寻找的路径是wwwroot这个目录file_path = wwwroot; // ./wwwroot// 对于URL文件的路径进行一定的拼接if (url == "/" || url == "/index.html"){file_path += "/";file_path += homepage; // ./wwwroot/index.html}elsefile_path += url; // /a/b/c/d.html->./wwwroot/a/b/c/d.html// 查找文件的后缀,默认是html,否则就进行合适的拼接auto pos = file_path.rfind(".");if (pos == std::string::npos)suffix = ".html";elsesuffix = file_path.substr(pos);}// 打印调试信息void DebugPrint(){for (auto &line : req_header){std::cout << "--------------------------------" << std::endl;std::cout << line << "\n\n";}// 打印当前识别出来的请求信息等等std::cout << "method: " << method << std::endl;std::cout << "url: " << url << std::endl;std::cout << "http_version: " << http_version << std::endl;std::cout << "file_path: " << file_path << std::endl;std::cout << text << std::endl;}public:// 请求信息中至少要包含下面的内容std::vector<std::string> req_header;std::string text;// 解析之后的结果std::string method;std::string url;std::string http_version;std::string file_path; // ./wwwroot/a/b/c.html 2.png// 文件后缀std::string suffix;
};// http服务端
class HttpServer
{
public:HttpServer(uint16_t port = defaultport) : port_(port){content_type.insert({".html", "text/html"});content_type.insert({".png", "image/png"});}bool Start(){// 进行套接字的创建,绑定,设置监听listensock_.Socket();listensock_.Bind(port_);listensock_.Listen();for (;;){std::string clientip;uint16_t clientport;// 从监听信息中提起对应的ip和端口号信息,当有用户连接的时候会进行接受对应的信息int sockfd = listensock_.Accept(&clientip, &clientport);if (sockfd < 0)continue;lg(Info, "get a new connect, sockfd: %d", sockfd);pthread_t tid;ThreadData *td = new ThreadData(sockfd, this);// 创建线程去执行对应的handle响应方法pthread_create(&tid, nullptr, ThreadRun, td);}}// 读取html的内容static std::string ReadHtmlContent(const std::string &htmlpath){std::ifstream in(htmlpath, std::ios::binary);if (!in.is_open())return "";in.seekg(0, std::ios_base::end);auto len = in.tellg();in.seekg(0, std::ios_base::beg);std::string content;content.resize(len);in.read((char *)content.c_str(), content.size());in.close();return content;}// 将后缀名替换为描述信息std::string SuffixToDesc(const std::string &suffix){auto iter = content_type.find(suffix);if (iter == content_type.end())return content_type[".html"];elsereturn content_type[suffix];}// 处理http的请求信息void HandlerHttp(int sockfd){char buffer[10240];// 进行收消息的过程ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0); // bugif (n > 0){buffer[n] = 0;std::cout << buffer << std::endl;// 将接受到的请求信息进行反序列化HttpRequest req;req.Deserialize(buffer);// 对于反序列化后的内容进行解析,解析为当前所需要的信息内容req.Parse();// 返回响应的过程std::string text;bool ok = true;text = ReadHtmlContent(req.file_path); // 失败?if (text.empty()){ok = false;std::string err_html = wwwroot;err_html += "/";err_html += "err.html";text = ReadHtmlContent(err_html);}// 设置响应状态行,默认失败是404状态std::string response_line;if (ok)response_line = "HTTP/1.0 200 OK\r\n";elseresponse_line = "HTTP/1.0 404 Not Found\r\n";// 进行字符串的拼接// response_line = "HTTP/1.0 302 Found\r\n";std::string response_header = "Content-Length: ";response_header += std::to_string(text.size()); // Content-Length: 11response_header += "\r\n";response_header += "Content-Type: ";response_header += SuffixToDesc(req.suffix);response_header += "\r\n";response_header += "Set-Cookie: name=haha&&passwd=12345";response_header += "\r\n";// response_header += "Location: https://www.qq.com\r\n";std::string blank_line = "\r\n"; // \nstd::string response = response_line;response += response_header;response += blank_line;response += text;// 把拼接好的字符串响应再发送回去,这样就完成了一次通信send(sockfd, response.c_str(), response.size(), 0);}close(sockfd);}static void *ThreadRun(void *args){// 对该线程进行设置,使得主线程不必关心这个线程pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);// 去执行对应的handle方法td->svr->HandlerHttp(td->sockfd);delete td;return nullptr;}~HttpServer(){}private:Sock listensock_;uint16_t port_;std::unordered_map<std::string, std::string> content_type;
};

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

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

相关文章

word文件如何转PDF格式?word转PDF的方法

在当今数字化时代&#xff0c;文档格式的转换已成为日常生活和工作中不可或缺的一部分。其中&#xff0c;将Word文档转换为PDF格式更是受到了广大用户的青睐。本文将详细介绍Word转PDF的方法&#xff0c;帮助读者轻松实现文档格式的转换&#xff0c;并探讨转换过程中的注意事项…

LeetCode 61. 旋转链表

给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3] 示例 2&#xff1a; 输入&#xff1a;head [0,1,2], k 4 输出&#xff1a;[…

yolov8直接调用zed相机实现三维测距(python)

yolov8直接调用zed相机实现三维测距&#xff08;python&#xff09; 1. 相关配置2. 相关代码3. 实验结果 相关链接 此项目直接调用zed相机实现三维测距&#xff0c;无需标定&#xff0c;相关内容如下&#xff1a; 1.yolov5直接调用zed相机实现三维测距&#xff08;python&#…

【C++练级之路】【Lv.16】红黑树(冰与火的碰撞,红与黑的史诗)

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C语言》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、红黑树的概念二、红黑树的模拟实现2.1 结点2.2 成员变量2.3 插入情况一&#xff1a;uncle在左&#xff…

工业互联网下的增强现实

工业互联网下的增强现实 1、 概述 增强现实&#xff08;Augmented Reality&#xff0c;简称AR&#xff09;&#xff0c;增强现实技术也被称为扩增现实&#xff0c;AR增强现实技术是促使真实世界信息和虚拟世界信息内容之间综合在一起的较新的技术内容&#xff0c;其将原本在现…

SQLAlchemy操作数据库

数据库是一个网站的基础。 比如 MySQL 、 MongoDB 、 SQLite 、 PostgreSQL 等&#xff0c;这里我们以 MySQL为例进行讲解。 SQLAlchemy 是一个 ORM 框架 我们会以 MySQL SQLAlchemy 组合进行讲解。 在操作数据库操作之前&#xff0c;先确保你已经安装了以下两个插件&#…

个人blog网站搭建1

写在前面 建立网站最好有一定计算机基础&#xff0c;需要了解以下几个概念&#xff1a;域名&#xff1a;网站必须需要地址&#xff0c;这样别人才能在浏览器中输入你的域名来访问你的网站&#xff0c;本质上是通过ip来访问你的网站&#xff0c;可以了解以下域名解析。服务器&a…

【每日跟读】常用英语500句(1~100)

【每日跟读】常用英语500句 What’s up? 怎么啦&#xff1f; I see. 我明白 Shut up. 闭嘴 Not bad. 还不错 I’ll do my best. 我会尽全力 Take it easy. 放轻松 On my way. 马上来 Are you serious? 你是认真的吗&#xff1f; See you later. 待会见 Good job. 做…

java Web餐馆订单管理系统用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 餐馆订单管理系统是一套完善的web设计系统&#xff0c;对理解JSP java 编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&#xff0c;使…

FPGA高端项目:解码索尼IMX390 MIPI相机转HDMI输出,提供FPGA开发板+2套工程源码+技术支持

目录 1、前言2、相关方案推荐本博主所有FPGA工程项目-->汇总目录我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、个人 FPGA高端图像处理开发板简介5、详细设计方案设计原理框图IMX390 及其配置MIPI CSI RX图像 ISP 处理图像缓存HDMI输出工程源码架构 6、工程源码…

美团一面:说一说Java中的四种引用类型?

引言 在JDK1.2之前Java并没有提供软引用、弱引用和虚引用这些高级的引用类型。而是提供了一种基本的引用类型&#xff0c;称为Reference。并且当时Java中的对象只有两种状态&#xff1a;被引用和未被引用。当一个对象被引用时&#xff0c;它将一直存在于内存中&#xff0c;直到…

选择最佳图像处理工具OpenCV、JAI、ImageJ、Thumbnailator和Graphics2D

文章目录 1、前言2、 图像处理工具效果对比2.1 Graphics2D实现2.2 Thumbnailator实现2.3 ImageJ实现2.4 JAI&#xff08;Java Advanced Imaging&#xff09;实现2.5 OpenCV实现 3、图像处理工具结果 1、前言 SVD(stable video diffusion)开放了图生视频的API&#xff0c;但是限…

C#多态性

文章目录 C#多态性静态多态性函数重载函数重载 动态多态性运行结果 C#多态性 静态多态性 在编译时&#xff0c;函数和对象的连接机制被称为早期绑定&#xff0c;也被称为静态绑定。C# 提供了两种技术来实现静态多态性。分别为&#xff1a; 函数重载 运算符重载 运算符重载将…

基于React的低代码平台开发实践

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;在线地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

2023混合多比特层-RDHEI Based on the Mixed Multi-Bit Layer Embedding Strategy

RRBE 本文仅供自我学习记录,切勿转载和搬运,如有侵权联系立删! 方法总框架 首先,发送者将载体图像进行两轮的不重叠块分割,分为可用隐藏块(AHB)和不可用隐藏块(UHB),然后通过依次处理可用块的像素信息产生location图来创造空间,接着通过密钥将载体进行加密,最后使用…

ElasticSearch启动报错:Exception in thread “main“ SettingsException

Exception in thread "main" SettingsException[Failed to load settings from [elasticsearch.yml]]; nested: ParsingException[Failed to parse object: expecting token of type [START_OBJECT] but found [VALUE_STRING]]; 这个报错说明elasticsearch.yml这个配…

如何在VS Code上搭建 C/C++开发环境

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、什么是VScode VScode&#xff08;Visual Studio Code&#xff09;是一款由微软开发的免费开源的轻量级代码编辑器。它…

机器视觉学习(七)—— 卷积、边缘和滤波器

目录 一、卷积运算 1.1 卷积运算的公式 1.2 卷积操作 二、垂直边缘与水平边缘 2.1 cv2.filter2D()函数 2.2 Sobel算子 三、滤波器 一、卷积运算 1.1 卷积运算的公式 卷积运算是一种图像处理的基本操作&#xff0c;常用于图像滤波、边缘检测等应用中。 卷积运算的基本思…

【Linux】 centos7安装卸载SQL server(2017、2019)

一、安装配置 准备一个基础Linux配置&#xff1a; 内存为20GB 运行内存为2GB的系统&#xff08;数据库小于2GB安装不了&#xff09; 1、网络配置 我们需要进行网络的连接 进入 cd /ect/sysconfig/network-script/ 编辑文件ifcfg-ens33 vi ifcfg-ens33 Insert键进行编辑 把ONBOO…

公平锁和非公平锁,为什么要“非公平”?

公平锁和非公平锁&#xff0c;为什么要“非公平”&#xff1f; 主要讲一讲公平锁和非公平锁&#xff0c;以及为什么要“非公平”&#xff1f; 什么是公平和非公平 首先&#xff0c;我们来看下什么是公平锁和非公平锁&#xff0c;公平锁指的是按照线程请求的顺序&#xff0c;…