Linux:应用层协议
协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢?
无论我们采用什么方案, 只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解析, 就是ok的. 这种约定, 就是 应用层协议。
send()和write()方式一模一样,用于流式套接字发送;receive()和read()
自定义实现 序列化和反序列化+协议定制
自定义协议:定义一个结构化的对象,一定是x op y,op的取值,exitcode的规定。没人规定只能有一份协议,怎么让系统知道我们使用的哪种协议,在报头前再加报头表示协议编号。拿到协议编号对应创建请求和响应。
序列化和反序列化
json、protobuf、xml(java)
#else //序列化
Json::Value root;
root["datax"] = _data_x;
root["datay"] = _data_y;
root["oper"] = _oper;
Json::FastWriter writer;
*out = writer.write(root);
return true;
#endif
//反序列化
#else
Json::Value root;
Json::Reader reader;
bool res = reader.parse(in, root);//将in字符串的内容放到key-value的root对象
if(res)
{
_data_x = root["datax"].asInt();
_data_y = root["datay"].asInt();
_oper = root["oper"].asInt();
}
return res;
#endif
HTTP:通过Http协议从服务器拿下来对应的“资源”,凡是在网络中看到的都是资源,所有的资源都可以看作资源文件,放在服务器的磁盘上,浏览器请求时会在Linux服务器的磁盘上寻找。http是超文本传输协议,因为它能处理所有文件资源。
1.URL: 协议名:域名(映射成IP):端口(一般会省略与协议名强相关) /web根目录。
理解 /web根目录:自定义的前缀路径。const std::string default_root = "./wwwroot";可以在文件夹下创建配置文件更改,path = default_root;path = default_root;
// 3. 添加web默认路径
path = default_root; // ./wwwroot,
path += url; //./wwwroot/a/b/c.html, ./wwwroot/
if (path[path.size() - 1] == '/')//如果访问的是/就是根目录,会显示主页
path += home_page;//主页
urlencode和urldecode:像 / ? : 等这样的字符, 已经被url当做特殊意义理解了。因此这些字符不能随意出现。比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义。
转义的规则如下:将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。
2.HTTP请求和响应的格式:
2.1HTTP请求
这份请求通过套接字接口,传给传输层TCP,然后通过TCP链接,向服务器发送出去。
Host:表示未来要发给哪个服务端,代理服务器,客户端把请求推给一个服务器,该服务器通过Host转发给目的服务器。
Connection代表支持长链接。
HTTP基于请求与响应,当客户端请求时,客户端才会响应。
User-Agent表示客户端的信息,操作系统的版本... ...
Accept:我(浏览器)支持的文本格式;告诉服务端我浏览器都接收的什么样的文本格式。
2.2HTTP响应
根据TCP链接,向客户端发送响应
2.3请求和响应怎么保证应用层完整读取了呢?请求和响应是怎么做到序列化和反序列化的?
http请求按照字符串按行存,所以能够读取完整的一行数据,一直按行读取读到空行就能将报头读完。那怎么保证把正文读取?根据报头中存储的正文的属性(正文长度)去完整性读取正文。Http自己实现的序列化和反序列化,报头部分:将所有\r\n去掉,把多个字符串变成1个长字符串。所以http采用的方案是分隔符方案。(补充)请求和相应的正文部分可选,有时可以不带。
应用:http请求如果没有请求指定的资源,web server会显示默认的首页!
http请求会交换bs(请求和响应)通信双方的协议版本,http客户端和服务端版本可能不一致,根据客户端不同的版本适配。
//写一个http响应
std::string respline = "HTTP/1.1 200 OK\r\n";
std::string respheader = "Content-Type: text/html\r\n";//报头,表示响应html格式
std::string respblank = "\r\n"; //空行
std::string body = "<html ...>";//响应的网页内容
2.4 HTTP的方法
前端form表单提交,用post方法可以被明文抓到(例如输入用户名和密码)。
2.5HTTP状态码
2.6长连接
一个网页把资源从服务器要多次加载获取才能完整显示,但是多次请求多次获取建立连接,频繁创建连接带来消耗,所以我们建立一个长连接,通过这一条连接完成资源获取。连接是双向的,需要客户端和服务器协商好。
2.会话保持
不属于HTTP协议天然具备的,HTTP核心是把远端资源从服务器拉到本地。HTTP协议是无状态的,不会记录历史的请求,只负责当前请求。浏览器会做相关信息的缓存->因为用户需要。在一个网站进行网页跳转时不能每次都登陆,这些信息浏览器会保存。
首次登陆成功后,浏览器会把用户名和密码保存起来,往后只要访问同一个网站,浏览器会自动推送里是保留的信息。凡是有权限要求的网页,在被获取之前都需要做身份判断。
而我们把浏览器自动保存用户名密码的行为叫做cookie技术,这些信息保存在cookie文件,cookie文件分为文件级别和内存级别,浏览器本身是一个进程,当关闭浏览器(进程退出)还不需要登陆仍然保存,这就是文件级别,并不随着进程退出。
cookie文件在客户端一旦被盗取,就会造成信息泄露,所以在用户登录时会将cookie信息保存在服务器中形成session文件,每个session文件都要有唯一的名称ID(字符串),在全服务器唯一。浏览器不会再保存用户的私密信息,服务器会向浏览器返回sessionID文件,这个文件在浏览器依旧叫做cookie文件,下次访问网页向服务器提交cookie文件。
respheader += "Set-Cookie: name=1234567abcdefg; Max-Age=120\r\n";
//HTTP响应报头添加cookie:当通过浏览器输入网址(IP+port)发起http请求时,
//服务器会返回一个http响应(在报头添加了cookie--缓存着用户的数据),浏览器获得cookie信息后
//之后一定时间内每次向服务器发起http请求时,都会回传cookie便于服务器识别
3.基本工具(postman,fiddler)---针对HTTP本地抓包
4.https
4.1加密
对称加密(同一个密钥、速度快--按位异或),一个密钥用来加密和解密。
非对称加密(一个密钥用来加密,一个用来解密),公钥和私钥配对,两个可以互相进行加密和解密,算法强度高复杂,速度慢很多。
如何理解加密的安全性:所有的加密数据是可以破解的,但是需要时间算力。
数据指纹/摘要:不是一种加密机制,它将数据生成唯一的摘要,通过哈希映射存储它的原数据。应用:百度网盘,内部管理用户密码文档
因为对称加密解决不了密钥如何被对方看到的问题,所以只能使用非对称加密。客户端和服务器各自形成一对公钥私钥,发送数据时都用公钥加密,只有对方持有私钥