有关网站开发的文献或论文,太原免费静态网页制作网站,云服务器做网站,高端设计网站公司文章目录 一、基本概念1.HTTP2.域名3.默认端口号4.URL 二、请求与响应1.抓包工具2.基本框架3.简易实现3.1 HttpServer3.2 HttpRequest3.2.1 version13.2.2 version23.2.3 version3 总结尾序 一、基本概念 常见的应用层协议#xff1a; HTTPS (HyperText Transfer Protocol Sec… 文章目录 一、基本概念1.HTTP2.域名3.默认端口号4.URL 二、请求与响应1.抓包工具2.基本框架3.简易实现3.1 HttpServer3.2 HttpRequest3.2.1 version13.2.2 version23.2.3 version3 总结尾序 一、基本概念 常见的应用层协议 HTTPS (HyperText Transfer Protocol Secure)安全的超文本传输数据。FTP(File Transfer Protocol) 网络之间的文件传输。SMTP(Simple Mail Transfer Protocol)邮件传输。DNS(Domain Name System)域名解析。SSH(Secure SHell)加密的远程登录会话。 一般来讲大多数情况用现成的应用层协议即可但是如果做游戏引擎或者做一些比较私密对安全性要求很高的项目时可能需要内部指定自定义协议。 1.HTTP
HTTPHyperText Transfer Protocol是一种用于传输超文本数据的应用层协议。应用于Web服务器与Web浏览器之间进行通信。明文传输(可能会暴露个人隐私数据)因此不安全但是简单易用被广泛支持。
对于HTTP的不安全之后发展出了HTTPS即 安全的HTTP 。 浏览器简介 浏览器简单来看就是处理数据的一种工具浏览器可以解析一些常用的应用层协议的数据通过相应的连接方式向服务端发送请求接收响应并将文件给我们以相应的格式呈现出来具体如何呈现出一个完美的网页则是前端开发人员的工作了接下来的内容我们会制作一个简单的网页 ~市面上的浏览器多种多样因为掌握了浏览器也就掌握了进入网络的通道因此各大公司在早期为了发展争相竞争推动了浏览器技术的发展发展出了成熟的浏览器目前浏览器呈现的一般都是跟搜索引擎相结合的模式通过搜索网址和关键词从而使用户进入目标网站。现在由于ChatGpt的出现让信息可以通过对话的形式体现相比搜索引擎的关键词搜索更加的便利让我们获取知识的成本降低了不少博主也推荐使用ChatGpt之类的工具来提高学习效率。 2.域名 通过 www.baidu.com我们可以很明显的辨认出这是百度的网址其实这就是百度的域名那我们再来看39.156.66.14这里你可能会感觉有点懵逼其实这也是百度的网址不信博主复制粘贴到浏览器去访问一下下面截图为证 这一串数字是怎么得到的呢 按下 win r输入cmd按下回车。—— windows系统下 在命令窗口输入ping www.baidu.com 这其实是百度的IP地址通过它我们就可以定位唯 一 一 台主机进而访问百度的服务器获取相应的首页资源。此时我们再回到讨论的话题域名相比ip地址用户记忆的成本更低这就是域名的好处但从专业的角度来看域名背后其实绑定了ip地址而且可能还不止一个如果你ping的ip地址跟我的不一样就证明了这一点。
3.默认端口号 常见的默认端口号有 HTTP: 80HTTPS: 443FTP: 21SSH: 22Telnet: 23SMTP: 25POP3: 110IMAP: 143DNS: 53 端口号所在文件 /etc/services
这些端口号一般是不允许被修改的就像110在我们的脑中已经跟报警电话已经联系了起来80就是http协议的默认端口而且这些端口号在访问时一般浏览器是忽略的如果改了还得在后面跟上: 修改的端口号因为单凭ip地址只能锁定一台主机还得指定端口号与相应的进程才能进行联系因为网络的本质就是进程间通信。
4.URL
概念 URLUniform Resource Locator是统一资源定位符的缩写用于指定互联网上资源的位置和访问方式。简单的理解其实就是网址。 组成 图解 例1ssh登录 例二http协议 下面我们于查询字符串和片段标识符举两个例子
字符串查询 搜索引擎上输入C##等带特殊字符的关键词。 查看URL的查询参数: 如下图 可见这些特殊字符是被编码了的不过网上有现成的urlencode解码工具进去将此字符串复制进行转换可以查看到我们原来的查询的关键词。 如下图 因此我们可以简单的理解查询不只是简单的查询还要经过编码从而避免与网址的符号进行冲突。 片段标识符
当我们想要在网址中定位某一个网页的位置时需要通过片段标识符。博主上一篇文章的网址 : https://blog.csdn.net/Shun_Hua/article/details/136523510?spm1001.2014.3001.5501 。后面跟上和不跟上#_729对比效果即可明白片段标识符的作用。
如何找到片段标识符呢
在网页中右键选择选项中的检查。查看网页源代码。按下ctrl f 在搜索框 搜索id这个标签。
例 鼠标移动至此可在网页上看到对应的效果即标记位置信息。 二、请求与响应
1.抓包工具 fiddler需要输入认证信息之后才可进行下载。postman, 外网的访问会有些慢需要使用魔法或许访问不上。apifox国内的比较好用。 2.基本框架
我们先使用telnet工具进行简单的HTTP请求查看请求与响应的格式 因此可以大致列出请求与响应的基本框架 穿插知识 短连接浏览器通常建立连接只能发一个请求然后收一个响应之后断开连接。若想再发送一个请求只能再次申请连接这适用于无需多数据传输无需保持连接Http/1.0采用的是短连接。长连接浏览器通常建立连接之后会保持一段时间直接可以进行多次数据的传输可以一次发送多个请求接收多个响应在无数据传输之后会断开连接。相比短连接减少因频繁建立和关闭连接而产生的额外开销提高通信效率尤其适用于需要频繁交换数据的场景,Http/1.1版本支持长连接。说明在请求报头中如果有Connection: keep-alive,则意味申请长连接申请成功时会在响应报头处添加Connection: keep-alive。 3.简易实现 在简易的了解Http的请求和响应的框架之后我们可以通过代码编写一个简单的Http服务器并且制作一个简单的网页来逐步理解Http的请求和响应。
3.1 HttpServer 在之前的文章我们实现过守护进程日志封装基于TCP的socket等小组件下面避免代码冗余就不再给出下面的HttpServer其实就是一个基于TCP协议的服务端写多了不管什么类型的服务端就是一种套路: 随机绑定端口与IP地址进行初始化。对服务端进行初始化即创建绑定监听套接字。启动服务端接收请求建立链接提供服务。提供服务其实就是将接收信息并对信息进行处理并返回。 关键就在于这个处理逻辑按照什么方式处理就决定了服务端是什么类型的。 实现代码
#pragma once
#includeiostream
#includefstream
#includefunctional
//容器
#includevector
#includeunordered_map
//网络接口
#includesys/types.h
#includesys/socket.h
#includearpa/inet.h
#includenetinet/in.h//小组件
#include ../Tools/Log.hpp
#include ../Tools/Socket.hpp
using cal_t functionstring(string);
string default_ip 0.0.0.0;
uint16_t default_port 8080;
class HttpServer;
struct PthreadData
{PthreadData(int sockfd,HttpServer* hsp):fd(sockfd),hp(hsp){}int fd;HttpServer* hp;
};
class HttpServer
{
public:HttpServer(uint16_t port default_port,\cal_t signal nullptr,string ip default_ip):_sockfd(port,ip){}void Init(){_sockfd.Socket();//使端口号可以重复被使用之后的TCP内容中会详谈。int opt 1;setsockopt(_sockfd.GetSocket(),SOL_SOCKET,\SO_REUSEADDR|SO_REUSEPORT\,opt,sizeof(opt));_sockfd.Bind();_sockfd.Listen();}static void *Routine(void* args){pthread_detach(pthread_self());auto thp static_castPthreadData*(args);HttpServer* hp thp-hp;int fd thp-fd;hp-Server(fd);return nullptr;}void Run(){for(;;){sockaddr_in client;socklen_t len;int fd _sockfd.Accept(client,len);pthread_t tid;pthread_create(tid,nullptr,Routine\,new PthreadData(fd,this));}}void Server(int fd){string mes;for(;;){mes _sockfd.Read(fd);if(mes ) break;//处理信息string echo_mes cal(mes);int num _sockfd.Write(fd,echo_mes);if(num 0) break;}_sockfd.Close(fd);}
private:Sock _sockfd;cal_t cal;
};3.2 HttpRequest 如下是我们实现处理请求类的宏观框架读者有个大致的认识即可博主下面会分别行进行实现逐一进行讲解。 实现代码
struct HttpRequest
{ //构造函数。HttpRequest();//从请求中获取一个完整的报文string InCode(string str);//从报文中将请求的信息进行打散。bool Deserialize(string str);//对请求报头解析并获取对应的内容。void Prase()//从指定目录中读取相关消息并进行返回。string ReadFromFile(const string path)//获取返回网络的文件的类型。string GetContentType()//解析URL获取对应的网络资源。string GetSourse();//处理服务器收到的请求。string HanderHttpMes(string mes);
public://正文之前的部分vectorstring infors;//提供文件在网络中的类型。unordered_mapstring,string content_type;//请求方法大多数为POST和GET方法。string Method;//统一资源定位符。string Url;//URL里面可能有读取文件信息,请求的都是网页文件。string suffix .html;//HTTP的版本一般为1.1或者1.0的。string Version; //请求正文一般来说响应是没有的。string content;//获取资源在服务器的路径即根目录。const string root ./wwwroot;
};主程序
#includeiostream
#includememory#include httpserver.hppvoid Usage(char* pragma_name)
{cout endl Usage: pragma_name \ port[8000-8888] endl endl;
}
int main(int argc,char* argv[])
{if(argc ! 2){Usage(argv[0]);return 1;}uint16_t port stoi(argv[1]);HttpRequest req;std::unique_ptrHttpServer htp(new HttpServer(port,\bind(HttpRequest::HanderHttpMes,req,placeholders::_1)));//bind函数指定类域固定this指针以及参数从而封装//出了一个返回值为string类型参数为string的函数。htp-Init();htp-Run();return 0;
}对请求的处理和程序的运行有了宏观的认识之后下面我们先来编写一段代码在网页中打印出简单的消息。 HanderHttpMes的实现:
3.2.1 version1 version1打印出简单的信息。 string HanderHttpMes(string mes){//避免mes过长我们将其清空。mes ;//空行string empty_line \r\n; //状态行string state_line HTTP/1.1 200 OK\r\n;//正文string text hello world\r\n; //报文段string package_line Content-Length: \to_string(text.size()) empty_line;//响应string response state_line package_line \empty_line text;return response;}运行结果 效果
看到效果之后我们便可大致明白浏览器其实就是接收信息的客户端并按照自定义协议将信息给上层用户进行呈现。
运用知识 Content-Length:【空格】【正文段长度】【\r\n】—— 状态行信息用于浏览器的获取正文段数据并按照指定的方式呈现出来这里我们只是打印出了文字。 缺陷不管浏览器给我们发送什么请求我们都只会返回hello world进行响应。 3.2.2 version2 version2: 完成请求的解析提取出url返回对应的网页资源。 请求解析。 思路 1. 首先我们从缓存区中提取的不知道是否是一个完整的报文。 2. 因此我们应找到完整报文的解析符 —— \r\n\r\n。 3. 一般情况下浏览器是不会发送正文段的因此我们按照没有发送正文段的报文进行解析处理。拓展我们可以看已经截取的请求报头中查看是否有Content-Length字段如果有则有正文解析其后的数据长度截取正文段即可。 InCode string InConde(string str){string splite_str \r\n\r\n;size_t pos str.find(splite_str,0);//如果没有找到说明不是一个完整的报文。if(pos string::npos){return ;}int len pos splite_str.size();string package str.substr(0,len);//将报文进行丢弃,便于截取下一次请求的报文。str.erase(0,len);return package; }打散请求 思路 因为都是以\r\n以一行的形式进行呈现的因此我们只需以\r\n截取出每一行即可然后添加到类型为vectorstring 的infors即可。 Deserialize bool Deserialize(string str){//先看是否有完整的报文string datagram InConde(str);int cur 0;while(true){size_t pos datagram.find(line_break,cur);//从cur位置开始寻找。//如果没有就说明解析出错了。if(pos string::npos) return false;string line datagram.substr(cur,pos - cur); //截取pos - cur长度。cur pos line_break.size();//跳过line_breakif(line.empty()) break; //读取到空行。infors.push_back(line);}return true;}提取状态行。 思路 这里报文都存在infors中, 请求报头都在infors[0]中因此我们将其解析出来即可。格式为 [请求方法][空格][Url][空格][HTTP版本],以空格分隔出每一个元素即可。 除此之外因为我们要从url中解析出相应的返回资源下面我们列出第一次访问网址浏览器发送的两次请求 说明 第一次请求的是主页资源主页资源的url也可以为 /index.html第二次请求的是网页标签的logo。举个百度标签的logo: 根据url解析出相应的文件信息我们可以据此返回相应的资源了。
Prase void Prase(){//对一行的资源进行处理string state_line infors[0]; //[请求方法][空格][Url][空格][HTTP版本]auto left state_line.find(space);auto right state_line.rfind(space);//请求方法Method state_line.substr(0,left);//urlUrl state_line.substr(left 1,right - left - 1);//请求的HTTP版本。Version state_line.substr(right 1);//看URL中是否带有文件信息如果有则解析出来默认为 .htmlauto pos Url.rfind(.);if(pos ! string::npos){suffix Url.substr(pos);//默认为.htmlif(content_type[suffix] ) suffix .html;}}构造函数 HttpRequest(){content_type[.jpg] image/jpeg;content_type[.html] text/html;content_type[.ico] image/x-icon;}说明 响应时我们返回对应网页资源时得说明是什么类型的浏览器会按照响应的方式进行解析。我们只需再状态行添加[Content-Type:][空格][资源文件的类型]比如Content-Type: text/html 。 准备网页资源。
我们在当前目录下创建一个wwwroot作为根目录存放网页资源文件一般的网页以 .html 结尾。
因此我们成员变量设置了
const string root ./wwwroot; //获取资源在服务器的路径即根目录。我们这里创建一个index.html写一些网页信息
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleShun_Hua/title
/head
bodyh1 欢迎来到我的主页!/h1
/body
/html说明 首先博主采用的是vscode编写较为轻量写起来也很轻松按下! 加上 Tab 可以快速生成一个网页框架。这里涉及一些前端的知识博主在写项目时候总结了一下常用的具体可见详见目录前端编写模块 。 下面是如何找的过程首先我们要从url获取到文件的信息再跟网页的根目录进行拼接具体实现如下
GetSourse string GetSourse(){//根据Url,确定返回的资源string path root;//主页资源。if(Url / || Url /home.html)path /home.html;else{path Url;}//从文件中读取消息。return ReadFromFile(path);}下一步是从获取到的具体路径文件中读取文件信息作为正文段进行返回。
ReadFromFile string ReadFromFile(const string path){//从文件中读取对应的内容。std::ifstream fs(path,ios_base::in);if(!fs.is_open()) return 404 Not Found;string content;//直接读取到文件的结尾fs.seekg(0,fs.end);//获取文件的长度。auto len fs.tellg();//回退到文件的长度。fs.seekg(0,fs.beg);//直接将内容读取出来将内容打到进去这是比较暴力但是比较简单的做法。content.resize(len);fs.read((char*)content.c_str(),content.size());return content;}以上的代码写完之后我们可以再写一个更加高级的处理消息的函数
HanderHttpMes string HanderHttpMes(string mes){HttpRequest req;//首先对mes进行解析获取完整的报文,解析失败返回空串。if(!req.Deserialize(mes)) return ;//其次解析出报头信息。req.Prase();//从Url中获取相应的网页资源。string text req.GetSourse(); //正文string empty_line \r\n; //空行string state_line HTTP/1.1 200 OK\r\n;//状态行string package_line Content-Length: \ to_string(text.size()) empty_line;string content_type_line Content-Type: \ content_type[suffix] empty_line;string response state_line package_line empty_line text;return response;}效果 返回的响应 下面我们来一点前端的知识让页面更加丰富多采一点
增加网页标签logo 推荐网站免费Favicon.ico图标在线生成器 这里我输入文字舜华进行自动生成。或者直接用现成的也可以。 点击图片下载保存到能找到的文件夹。在Linux会话窗口使用:rz -E命令将.ico文件上传到Linux的存放网页文件的目录下。 然后我们再刷新网页看一看效果 有总比没有强虽然颜色有点重hhh。 此后我们可以直接在网页文件中编写内容服务器启动着浏览器刷新即可更新出新的网页内容。 说明以下所有更新文件都在 ./wwwroot 路径下。 更新网页内容
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleShun_Hua/title
/head
bodyh1 欢迎来到我的主页!/h1!-- 更新内容添加网页链接可以跳转到指定网页 --a hrefhttp://59.110.171.164:8888/ 回到主页 /a/br !-- 回车换行的意思--a hrefhttp://59.110.171.164:8888/tail.html 尾页 /a
/body
/html添加尾页内容
tail.html
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title尾页/title
/head
bodyh1欢迎来到尾页/h1pps:功能开发中……/pa hrefhttp://59.110.171.164:8888/ 回到主页 /a
/body
/html刷新界面 在尾页添加图片
图片 ——1.png tail.html
!-- 说明未补充内容同上 --
bodyh1欢迎来到尾页/h1pps:功能开发中……/pa hrefhttp://59.110.171.164:8888/ 回到主页 /abrimg src ./1.jpg alt实在抱歉 width200px height200px!-- 加载对应的图片设置图片加载失败时的提示设置图片的宽度和高度 --
/body效果 综上所述我们使用一点点前端知识将网页变的不至于那么单调简单的完成与用户进行交互。说明以上都是请求成功的情况那有没有请求失败的的情况呢下面我们继续深入了解响应行和响应报头。 3.2.3 version3 version3: 学习响应行和响应报头。 重定向 状态码3XX重定向需要进一步的操作以完成请求。这里使用 302 Found。状态行: 既然重定向了我们还得告诉浏览器的重定向的地址是什么这里我们使用302状态行表示成[Location:][空格][网址][\r\n]。 HanderHttpMes string HanderHttpMes(string mes){HttpRequest req;string state_line HTTP/1.1 302 Found\r\n;//状态行string location_line Location: https://www.baidu.com\r\n;string empty_line \r\n; //空行string response state_line location_line empty_line;return response;}效果 2. 网页资源不存在 状态码4XX客户端错误请求包含语法错误或无法完成请求。这里使用 404 Not Found。状态行: 既然找不到我们就返回一个表示找不到的网页即可。 HanderHttpMes string HanderHttpMes(string mes){//如果解析出来的Url不存在我们可以直接返回错误界面//这里我们只是简单的演示一下效果。mes.resize(0);HttpRequest req;string text ReadFromFile(root /errno.html) \r\n;string state_line HTTP/1.1 404 Not Found\r\n;//状态行string len_line Content-Length: to_string(text.size()) \r\n; string empty_line \r\n; //空行string response state_line len_line empty_line text;return response;}errno.html
!doctype html
html langen
head
meta charsetUTF-8
title404 Not Found/title
style
body {
text-align: center;
padding: 150px;
}
h1 {
font-size: 50px;
}
body {
font-size: 20px;
}
a {
color: #008080;
text-decoration: none;
}
a:hover {
color: #005F5F;
text-decoration: underline;
}
/style
/head
body
div
h1404/h1
p页面未找到br/p
p
您请求的页面可能已经被删除、更名或者您输入的网址有误。br
请尝试使用以下链接或者自行搜索:brbr
a hrefhttps://www.baidu.com百度一下/a
/p
/div
/body
/html说明网上有现成的直接拿来用即可。 效果
设置cookie 概念cookie是一种文本文件会进行存储记录用户的相关信息发送给服务器进行认证。 优点下一次登录时会直接用已经存储好的cookie文件无需再次登录认证。 图解
如何查看呢下面我们以CSDN的首页进行举例。 说明cookie文件是有保质期的过期了cookie会无效需要再次认证。 HanderHttpMes string HanderHttpMes(string mes){//如果解析出来的Url不存在我们可以直接返回错误界面//这里我们只是简单的演示一下效果。HttpRequest req;if(!req.Deserialize(mes)) return ;req.Prase();string text req.GetSourse();string state_line HTTP/1.1 200 OK\r\n;//状态行string len_line Content-Length: to_string(text.size()) \r\n;string cookie_line Set-Cookie: usershun_huapassword123456\r\n; string empty_line \r\n; //空行string response state_line len_line cookie_line empty_line text;return response;}效果 网页中的cookie文件 这里总结一下对响应和请求的大致分类
状态码
状态码状态描述1XX信息服务器收到请求需要请求者继续执行操作2XX成功操作被成功接收并处理3XX重定向需要进一步的操作以完成请求4XX客户端错误请求包含语法错误或无法完成请求5XX服务器错误服务器在处理请求的过程中发生了错误 当我们使用具体的状态码时查表即可但是我们要对状态码的分类比较清楚上面我们使用了404,302,200进行了演示。 Header
Header描述Content-Type:数据类型(text/html等)Content-Length:Body的长度Host:客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;User-Agent:声明用户的操作系统和浏览器版本信息;referer:当前页面是从哪个页面跳转过来的;location:搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;Cookie:用于在客户端存储少量信息. 通常用于实现会话(session)的功能 常用状态码与响应头 请求方法
请求方法描述GET请求指定的页面信息并返回实体主体。POST向指定资源提交数据进行处理请求例如提交表单或者上传文件。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。HEAD类似于 GET 请求只不过返回的响应中没有具体的内容用于获取报头PUT从客户端向服务器传送的数据取代指定的文档的内容。DELETE请求服务器删除指定的页面。CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。OPTIONS允许客户端查看服务器的性能。TRACE回显服务器收到的请求主要用于测试或诊断。PATCH是对 PUT 方法的补充用来对已知资源进行局部更新 。 说明大多数请求都是Get和Post其它的我们当做了解即可。 总结
我们认识了一些现成的应用层协议比如SMTPFTPSSH等。了解了Http的基本概念比如域名默认端口号统一资源定位符。介绍了三个抓包工具fiddlerpostmanapifox。使用telnet工具发送请求接收响应。并列出了请求和响应的框架据此学习了长连接和短连接的知识。编程实践编写一个网络的Server服务和Request类处理请求通过此学习了常用的请求行的状态码请求报头等一些网页的前端知识比如标题logo图片链接编写了一个简单网页。
下期预告
我们此文提及了cookie一般是含认证信和密码之类的信息但http是明文传输的这就导致了数据在网络中是不安全的这就涉及到了加密据此引出下篇文章要讨论的Https敬请期待。
尾序
我是舜华期待与你的下一次相遇