Linux网络编程 --- HTTP协议

前言

协议

协议是一种 “约定”. socket api的接口, 在读写数据时, 都是按 “字符串” 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢?

网络版计算器

我们通过一个例子来说明,如何传输一些“结构化”的数据。

例如, 我们需要实现一个服务器版的加法器. 我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算, 最后再把结果返回给客户端。
约定方案一:
客户端发送一个形如"1+1"的字符串,这个字符串中有两个操作数, 都是整形。两个数字之间会有一个字符是运算符, 运算符只能是 + ,数字和运算符之间没有空格;

约定方案二:
定义结构体来表示我们需要交互的信息,发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体,这个过程叫做 “序列化” 和 “反序列化”

头文件(序列化和反序列化)

#pragma once
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>

namespace self_protocol
{
    struct Request
    {
        /* data */
        int x;
        int y;
        char op;
        //构造函数初始化,注意初始化顺序跟声明顺序一样,或者是个随机值
        Request()
            :x(0),y(0),op('+')
        {}
    };
    struct Response
    {
        /* data */
        int code;//状态码,成功0,错误!0
        int result;//结果
        Response()
            :code(0)
            ,result(0)
        {}
    };
}

server.cc

#include "server.hpp"
static void Usage(std::string proc)
{
    std::cerr << "Usage: " << "\n\t" << proc << " port" << std::endl;
}
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = atoi(argv[1]);
    self_server::Server sev(port);
    sev.InitServer();
    sev.Loop();
    return 0;
}

client.cc

#include "client.hpp"
static void Usage(std::string port)
{
    std::cerr << "Usage: " << "\n\t" << port << "ip port" << std::endl;
}
int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string ip = argv[1];
    uint16_t port = atoi(argv[2]);//第二个参数
    self_client::Client cli(ip, port);

    cli.InitClient();
    cli.Run();

    return 0;
}

我们运行,看一下效果。
在这里插入图片描述
通过运行结果,我们可以看到网络计算器实现了。客户端和服务器端会按照我们自己写的这种协议进行一个序列化和反序列化。

相关说明:
1、序列化:将数据多变一的过程,一般是将一个结构体按照一个规则转换成字符串
2、反序列化:将数据一变多的过程,接受数据的时候按照序列化相同的规则再把字符串转换为结构体

  1. 为什么需要序列化?

这里是为了方便网络发送和接受,一个整体的数据肯定比多个数据更容易发送和接受。一次性发送比一次一次发送效率高。

  1. 为什么需要反序列化?

上层使用的时候是使用单个数据,而不是整个,所以反序列化是为了方便上层应用程序正常使用数据。

所以无论我们采用方案一, 还是方案二, 还是其他的方案, 只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解析, 在某种约定下, 就是 应用层协议。

HTTP协议

虽然我们说, 应用层协议是我们程序猿自己定的.但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一.

HTTP (超文本传输协议)是⼀个在计算机世界⾥专⻔在「两点」之间「传输」⽂字、图⽚、⾳频、视频等「超⽂本」数据的「约定和规范」。

认识URL

平时我们俗称的 “网址” 其实就是说的 URL
在这里插入图片描述

  • 协议:使⽤ http或https等协议⽅案名获取访问资源时要指定协议类型。不区分字⺟⼤⼩写,最后附⼀个冒号(:)。
  • 登录信息(认证): 指定⽤户名和密码作为从服务器端获取资源时必要的登录信息(身份认证)。此项是可选项。
  • 服务器地址 :必须指定待访问的服务器地址。现在一般是域名,通过DNS协议解析为对应的ip地址进行查询。
  • 服务器端⼝号:指定服务器连接的⽹络端⼝号。此项也是可选项,若⽤户省略则⾃动 使⽤默认端⼝号。
  • 带层次的⽂件路径:指定服务器上的⽂件路径来定位特指的资源。
  • 查询字符串:针对已指定的⽂件路径内的资源,可以使⽤查询字符串传⼊任意参 数。此项可选。
  • ⽚段标识符:使⽤⽚段标识符通常可标记出已获取资源中的⼦资源(⽂档内的某个 位置)。该项也为可选项。

urlencode和urldecode

像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.

转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式

例如:
在这里插入图片描述
在这里插入图片描述

“+” 被转义成了 “%2B”。urldecode就是urlencode的逆过程。
在线urlencode工具.

Http特性

  1. http本身无连接
  • http底层是基于tcp的,但是http不关心底层的实现,一旦tcp建立链接成功,不需要http再次进行链接的建立。tcp建立链接和http无关,http直接向对方直接发送 http request即可
  1. http本身无状态
  • ⽆状态的好处,因为服务器不会去记忆 HTTP 的状态,所以不需要额外的资源来记录状态信息,这能减轻服务器的负担,能够把更多的CPU 和内存⽤来对外提供服务。
  • ⽆状态的坏处,既然服务器没有记忆能⼒,它在完成有关联性的操作时会⾮常麻烦(需要使用后面的cookie技术)。
  1. 简单、灵活和易于扩展、应⽤⼴泛和跨平台
  • HTTP 基本的报⽂格式就是 header + body ,头部信息也是 key-value 简单⽂本的形式, 易于理解。
  • HTTP协议⾥的各类请求⽅法、 URI/URL、状态码、头字段等每个组成要求都没有被固定死,都允许开发⼈员⾃定义和扩充。
  • 互联⽹发展⾄今, HTTP 的应⽤范围⾮常的⼴泛,从台式机的浏览器到⼿机上的各种 APP,从看新闻、刷贴吧到购物、理财、吃鸡, HTTP 的应⽤⽚地开花,同时天然具有跨平台的优越性。

http协议格式

在这里插入图片描述

http请求

  • 请求行:[方法] + [url] + [版本],常见方法一般为GET/POST
  • 请求报头(Header):请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
  • 空行:http request中空行的含义是将报头和有效载荷进行分离的特殊符号!
  • 请求正文(Body):空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度;GET方法可以不要正文,POST需要携带正文(需要上传数据到服务器),这些正文就是要上传的某些数据。
    在这里插入图片描述

http响应

  • 首行: [版本号] + [状态码] + [状态码解释]
  • 响应报头(Header): 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
  • 空行:http request中空行的含义是将报头和有效载荷进行分离的特殊符号!
  • 响应正文(Body): 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在body中.

在这里插入图片描述

http的方法

在这里插入图片描述
其中最常用的就是GET方法和POST方法。

GET方法

  • Get ⽅法的含义是请求从服务器获取资源,这个资源可以是静态的⽂本、⻚⾯、图⽚视频等。

⽐如,你打开我的⽂章,浏览器就会发送 GET 请求给服务器,服务器就会返回⽂章的所有⽂字及资源。

在这里插入图片描述
在这里插入图片描述

GET方法提交的数据,全部暴露在URL中。但URL的长度有限制,一般为2048字节,具体看对应的浏览器

POST方法

  • POST ⽅法则是相反操作,它向 URI 指定的资源提交数据,数据就放在报⽂的 body ⾥。

⽐如,你在我⽂章底部,敲⼊了留⾔后点击「提交」,浏览器就会执⾏⼀次 POST 请求,把你的留⾔⽂字放进了报⽂ body ⾥,然后拼接好 POST 请求头,通过 TCP 协议发送给服务器。
在这里插入图片描述

在这里插入图片描述

POST提交的用户名和密码显示在响应正文中,比GET方法更安全。

GET和POST对比

在这里插入图片描述

http状态码

状态码的职责:状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。
在这里插入图片描述
状态码如 200 OK,以 3 位数字和原因短语组成。数字中的第一位指定了响应类别, 后两位无分类。

响应类别有以下5 种:
在这里插入图片描述
常见响应码及其含义

  • 200 : 从状态码发出的请求被服务器正常处理。
    在这里插入图片描述

  • 204 : 服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分【即没有内容】。
    在这里插入图片描述

  • 206 : 部分的内容(如:客户端进行了范围请求,但是服务器成功执行了这部分的干请求)。
    在这里插入图片描述

  • 301 : 跳转,代表永久性重定向(请求的资源已被分配了新的URI,以后已使用资源,现在设置了URI)。
    在这里插入图片描述

  • 302 : 临时性重定向(请求的资源已经分配了新的URI,希望用户本次能够使用新的URI来进行访问)。
    在这里插入图片描述

  • 303 : 由于请求对应的资源存在的另一个URI(因使用get方法,定向获取请求的资源)。
    在这里插入图片描述

  • 304 : 客户端发送附带条件的请求时,服务器端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回了 304。
    在这里插入图片描述

  • 307 : 临时重定向【该状态码与302有着相同的含义】。

  • 400 : 请求报文中存在语法错误(当错误方式时,需修改请求的内容后,再次发送请求)。
    在这里插入图片描述

  • 401 : 发送的请求需要有通过HTTP认证的认证信息。
    在这里插入图片描述

  • 403 : 对请求资源的访问被服务器拒绝了。
    在这里插入图片描述

  • 404 : 服务器上无法找到请求的资源。
    在这里插入图片描述

  • 500 : 服务器端在执行请求时发生了错误。
    在这里插入图片描述

  • 503 : 服务器暂时处于超负载或者是正在进行停机维护,现在无法处理请求。
    在这里插入图片描述

HTTP常见Header

  • Content-Type: 数据类型(text/html等)
  • Content-Length: Body的长度
  • Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
  • User-Agent: 声明用户的操作系统和浏览器版本信息;
  • referer: 当前页面是从哪个页面跳转过来的;
  • location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
  • Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

Cookie

为什么需要cookie?

HTTP的特点:

  1. HTTP本身是无连接的(底层是基于TCP协议的,http要发起所谓的http request的时候,不会先在http层建立链接)
  2. HTTP本身是无状态的(htto不会记录自己的发起http请求的上下文,不会对历史请求有任何记忆能力!)
  3. HTTP发起请求的时候,有基于长连接的,也有基于短链接的(之前的内容)

http协议本身无状态,没有记忆能力,这就给用户带来一个非常不好的体验。

比如当我登录上某些vip类的视频网站的时候,点播某些vip视频,因为http是无状态的,那么也就意味着,新打开的网页,以及里面的vip内容,我也无法查看(需要重新登录)。

解决办法:可以给http添加一些其他的技术特点,让http具有保存状态的能力! http的会话能力!
cookie + session!

那cookie到底是什么?

cookie就是一个浏览器文件,有内存级,也有文件级的(存储于硬盘中)。保存的信息都存储于cookie文件中。
在这里插入图片描述
下面是一个免登录的原理介绍。
在这里插入图片描述

总结一下,浏览器使用cookie的时候

  1. 每一个http request都会携带cookie的信息,发给服务器!一定需要服务器也支持cookie技术(其中认证的环节,一定不是http完成的,程序员自己完成认证的)。
  2. cookie"文件":有些浏览器配置的时候,cookie有内存级的,也有文件级别的!

只用cookie有什么风险?

cookie里面保存的是用户的私密信息,而且有可能是基于文件的,万一我的电脑被注入木马等恶意程序,盗取浏览器的所有cookie信息!比如:拿到了你的访问b栈的所有cookie信息,不法分子拿着你的cookie拷贝到自己的浏览器cookie路径下,然后自己访问b站,是不是就以你的身份访问了b站! qq也是类似一个网络程序,内部一定存在cookie。

  1. 有个人私密信息泄漏的风险
  2. 以你的身份从事违法的事情

cookie安全问题的解决(相对解决)

我们使用cookie+session技术来进程会话管理(会话保持),但这只是相对安全(原因后面解释)。

session原理:

  1. 浏览器第一次发起请求时,对应的私密信息会保存在服务器中的session文件中
  2. 服务器对session文件进行唯一标识(文件名),然后将session-id发送给浏览器
  3. 浏览器将session-id保存在自己对应的cookie文件中
  4. 浏览器再次发送请求的时候,浏览器会将cookie携带,然后服务器对cookie文件中的session-id进行一个确认,如果存在则认证成功,不存在则重复第一步。
  5. 浏览器和服务器后面都以cookie + session-id进行一个会话管理

在这里插入图片描述

但是也一定会存在cookie信息被盗取的风险,比如一些钓鱼网站,非法网站等

最重要的区别:用户的个人私密信息是保存在服务器端的,基本是安全的(有可能服务器数据泄漏),client只保留了session ID

另外我们要知道:

  1. cookie和session本身都是有时间限制的,如果到达一定时间就要求重新登录,确保安全。
  2. 我们登录的时候也可以通过位置来判断我们账号是否被盗取

HTTPS

http的缺陷

  1. 数据的明文传送,不加密,相当于暴露在外面,别人可以随意篡改。
  2. HTTP在传输客户端请求和服务端响应时, 唯一的数据完整性检验就是在报文头部包含了本次传输数据的长度, 而对内容是否被篡改不作确认

只有经过加密的数据,才能保证在理论上是安全的!

http与 https有哪些区别?

  1. HTTP 是超⽂本传输协议,信息是明⽂传输,存在安全⻛险的问题。 HTTPS 则解决 HTTP 不安全的缺陷,在TCP 和 HTTP ⽹络层之间加⼊了 SSL/TLS 安全协议,使得报⽂能够加密传输。
  2. HTTP 连接建⽴相对简单, TCP 三次握⼿之后便可进⾏ HTTP 的报⽂传输。⽽ HTTPS 在 TCP 三次握⼿之后,还需进⾏ SSL/TLS 的握⼿过程,才可进⼊加密报⽂传输。
  3. HTTP 的端⼝号是 80, HTTPS 的端⼝号是 443。
  4. HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

https的推出

HTTPS ,是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。

在这里插入图片描述

HTTPS 在 HTTP 与 TCP 层之间加⼊了 SSL/TLS 协议,可以很好的解决了上述的⻛险:

  • 信息加密:交互信息⽆法被窃取,但你的号会因为「⾃身忘记」账号⽽没。
  • 校验机制:⽆法篡改通信内容,篡改了就不能正常显示,但百度「竞价排名」依然可以搜索垃圾⼴告。
  • 身份证书:证明淘宝是真的淘宝⽹,但你的钱还是会因为「剁⼿」⽽没。

其中的SSL、TLS解读:

  1. SSL:安全套接字层
  2. TLS:传输层安全

这里所谓的加密解密的软件层,本质是在用户层!SSL也是分层,两层

  1. 封装加密解密
  2. https握手

对称加密

对称加密(只有一个秘钥),客户端将数据用秘钥加密后发送给服务器端,服务器端通过秘钥对其解密,就叫做对称加密。

但是怎么保证加密后的结果对应的安全?可以想象成一种异或运算

  1. 假设秘钥为mmm 数据为 999
  2. 客户端对其加密后的结果:999 ^ mmm = data
  3. 服务器端对其解密:data ^ mmm = 999

非对称加密

非对称加密有两种密钥:公钥、私钥。公钥用来加密,私钥用来解密。

通信流程:服务器将公钥发给客户端,客户端用公钥将自己的密钥加密以后发给服务器,然后服务器用私钥进行解密,拿到客户端发来的密钥。

采⽤「混合加密」的⽅式的原因:

  1. 对称加密只使⽤⼀个密钥,运算速度快,密钥必须保密,⽆法做到安全的密钥交换
  2. ⾮对称加密使⽤两个密钥:公钥和私钥,公钥可以任意分发⽽私钥保密,解决了密钥交换问题但速度慢

对公钥和私钥不理解的话:公钥就是锁,私钥就是钥匙,锁只有一把,只能持有钥匙的人来打开把锁。

https的通信过程

在这里插入图片描述

  1. 客户端在浏览器中输入一个https网址,然后连接到server的443端口
  2. 采用https协议的server必须有一套数字证书(一套公钥和密钥(公钥和密钥)) 首先server将证书(公钥)传送到客户端
  3. 客户端解析证书,验证成功,则生成一个随机数(私钥),并用证书将该随机数加密后传回server
  4. server用密钥解密后,获得这个随机值,然后将要传输的信息和私钥通过某种算法混合在一起(加密)传到客户端
  5. 客户端用之前的生成的随机数(私钥)解密服务器端传来的信息

相关说明:

  • 1、客户端拿到证书之后,会从内置的证书列表中索引,找到服务器下发证书对应的机构,如果没有找到,此时就会提示用户该证书是不是由权威机构颁发,是不可信任的。如果查到了对应的机构,则取出该机构颁发的公钥。
  • 2、找到对应证书后,客户端会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值。然后用证书对该随机值进行加密。这些都通过认证时,浏览器就可以安全使用证书中的网站公钥了。
  • 3、通过算法对信息和私钥加密,除非找到私钥,否则无法获取内容,客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。

解决中间信息被篡改的问题?

  1. 数据经过加密算法(摘要算法)加密后,形成与数据具有映射关系(哈希映射)的数据摘要(也叫做数据签名/指纹),并对数据摘要用密钥加密,服务器将数据和数据摘要都发给客户端。
  2. 一旦对内容进行了修改,客户端通过加密算法产生的数据摘要就会与服务器发来的数据摘要不相同,客户端就能识别到内容被修改了。
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨轩(爵丶迹)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值