1. 互联网时代的诞生
2. HTTP的基本特点
2.1客户端-服务端模型
2.2 无状态协议
2.3 可靠性
2.4 文本协议
3. HTML,CSS和JS
4. HTTP的各个组件
4.1 客户端
4.2 服务端
4.3 代理
5. URI和URL
6. HTTP报文
- HTTP报文分为两种——请求报文和响应报文。
6.1 GET请求示例
注意:C++中的类不用调用c中的mem_系列函数 来处理。
单线程阻塞服务端
#include <54func.h>
#include <iostream>
#include<string>
using std::cerr;
using std::string;
class HttpServer
{
public:
HttpServer(const string &ip,unsigned short port)
:_ip(ip),_port(port)
{}
~HttpServer()
{
if(_sockfd>0)
{
close(_sockfd);// 注意这里不需要作用域限定符号,而bind需要,因为std中也有bind函数
}
}
void start();
void recvAndShow();
private:
string _ip;
unsigned short _port;
int _sockfd;
};
void HttpServer::start()
{
_sockfd = socket(AF_INET,SOCK_STREAM,0);
if(_sockfd < 0)
{
perror("socket");
exit(1);
}
int reuse = 1;
int ret = setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
if(ret < 0)
{
perror("setsockfd");
exit(1);
}
struct sockaddr_in serverAddr;
memset(&serverAddr,0,sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(_port);
serverAddr.sin_addr.s_addr = inet_addr(_ip.c_str());
ret = ::bind(_sockfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
if(ret < 0)
{
perror("bind");
exit(1);
}
listen(_sockfd,10);
}
void HttpServer::recvAndShow()
{
while(true)
{
int netfd = ::accept(_sockfd,nullptr,nullptr);
char buf[4096] = {0};
ssize_t sret = recv(netfd,buf,sizeof(buf),0);
printf("sret = %ld,buf = %s\n",sret,buf);
close(netfd);
}
}
int main()
{
HttpServer server("10.102.1.35",1234);
server.start();
server.recvAndShow();
return 0;
}
6.2 POST请求示例
6.3 请求报文详解
方法
路径
版本
- 1.0和1.1的区别
- HTTP2.0是二进制协议不是文本协议,典型的应用场景是grpc
首部字段
Content-Length,因为TCP是一个流式协议,需要使用类似于我们的火车头协议。包的长度。
Host:域名,处理一个IP对应多个域名的情况
Connection:长连接或者短连接
user-agent:客户端的类型
MIME
- 本质就是文件类型
- 格式:大类型/小类型:text/html,text/css,text/javascript
请求体
6.4 响应报文
响应的状态
- 200 ok
- 300配合浏览器生效,重定向
- 404找不到
- 403 客户端有错误
- 500 服务器有错误
#include <54func.h>
#include <iostream>
#include<string>
using std::cerr;
using std::string;
class HttpServer
{
public:
HttpServer(const string &ip,unsigned short port)
:_ip(ip),_port(port)
{}
~HttpServer()
{
if(_sockfd>0)
{
close(_sockfd);// 注意这里不需要作用域限定符号,而bind需要,因为std中也有bind函数
}
}
void start();
void recvAndShow();
string response();
private:
string _ip;
unsigned short _port;
int _sockfd;
};
void HttpServer::start()
{
_sockfd = socket(AF_INET,SOCK_STREAM,0);
if(_sockfd < 0)
{
perror("socket");
exit(1);
}
int reuse = 1;
int ret = setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
if(ret < 0)
{
perror("setsockfd");
exit(1);
}
struct sockaddr_in serverAddr;
memset(&serverAddr,0,sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(_port);
serverAddr.sin_addr.s_addr = inet_addr(_ip.c_str());
ret = ::bind(_sockfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
if(ret < 0)
{
perror("bind");
exit(1);
}
listen(_sockfd,10);
}
void HttpServer::recvAndShow()
{
while(true)
{
int netfd = ::accept(_sockfd,nullptr,nullptr);
char buf[4096] = {0};
ssize_t sret = recv(netfd,buf,sizeof(buf),0);
printf("sret = %ld,buf = %s\n",sret,buf);
string repo = response();
send(netfd,repo.c_str(),repo.size(),0);
close(netfd);
}
}
int main()
{
HttpServer server("10.102.1.35",1234);
server.start();
server.recvAndShow();
return 0;
}
string HttpServer::response()
{
string startLine = "HTTP/1.1 200 ok\r\n";
string headers = "Server: MyHttpServer\r\n";
string body = "<html>Hello World!</html>";
headers+="Content-Type: text/html \r\n";
headers+="Content-Length" + std::to_string(body.size()) + "\r\n";
string emptyLine = "\r\n";
return startLine+headers+emptyLine+body;
}
浏览器直接下载
- 重定向
7. RESTful的设计风格
目的:HTTP接口用起来像对象的方法调用
幂等性
- 重复发请求,对结果有无影响。
- get,delete,put是幂等的。
- post增加是不幂等的。
8. HTTPs的原理
8.1 对称加密和非对称加密
8.2 TLS的实现机制
- 两个步骤
- 1.非对称加密(引入证书机关)
-
- 对称加密
- 对称加密
TLS流程
HTTPS = HTTP + SSL(TLS)。
SSL 即安全套接层(Secure Sockets Layer),处于 OSI 七层模型中的会话层。
TLS握手的原因:为了验证身份、交换信息从而生成秘钥,为后续加密通信做准备。TLS 四次握手是在 TCP 建立连接之后进行的。因此,HTTPS 首次通信需要 7 次握手!
加密算法
- 对称加密:加、解密使用的同一串密钥,DES,AES 等。
- 非对称加密:加、解密使用不同的密钥,速度很慢,RSA,ECC 等。
- 混合加密:TLS 里使用了 “混合加密” 的方式博采众长:在通信刚开始的时候使用 非对称加密 算法,解决密钥交换的问题。后续全都使用 对称加密 进行通信。
数字证书(证书本身是由权威、受信任的证书颁发机构 (CA) 授予的。)一般有两个作用:
- 服务器向浏览器证明自己的身份,毕竟秘钥、甚至服务器域名都是可以伪造的。
- 把公钥传给浏览器。
RSA 握手(非对称加密)
1.浏览器向服务器发送随机数 client_random,TLS 版本和供筛选的加密套件列表。
2.服务器接收到,立即返回 server_random,确认好双方都支持的加密套件
以及数字证书 (证书中附带公钥 Public key certificate)。
3.浏览器接收,先验证数字证书。若通过,接着使用加密套件的密钥协商算法 RSA
算法生成另一个随机数 pre_random,并且用证书里的公钥加密,传给服务器。
4.服务器用私钥解密这个被加密后的 pre_random,参考 “非对称加密”。
XML
tinyxml2
#include <iostream>
#include"tinyxml2.h"
using namespace tinyxml2;
int main()
{
XMLDocument doc;
doc.LoadFile("test.xml");
XMLElement *root = doc.FirstChildElement("sites");
for(XMLElement *site = root->FirstChildElement("site"); site != nullptr; site=site->NextSiblingElement("site"))
{
XMLElement *name = site->FirstChildElement("name");
XMLElement *url = site->FirstChildElement("url");
std::cerr<<"name:"<<name->GetText() <<",url:"<<url->GetText()<<std::endl;
}
return 0;
}
构建的代码
解析的代码
Json解析
简介
nlohmann/json的使用
nlohmann/json是一个header-only的C++ json解析库,可以用于构造和解析JSON对象。
键值必须是字符串
- 数据-》字节流:序列化/编码
- 字节流-》数据:反序列化。解码
{
"sites":
[
{
"site":
{
"name":"王道论坛",
"url":"www.baidu.com"
}
},
{
"site":
{
"name":"google",
"url":"www.google.com"
}
},
{
"site":
{
"name":"微博",
"url":"www.weibo.com"
}
}
]
}
序列化
#include <iostream>
#include <nlohmann/json.hpp>
using Json = nlohmann::json;
int main(){
Json sites1 =
{
{
"sites",
{
{{"name", "王道论坛"}, {"url", "www.cskaoyan.com"}},
{{"name", "google"}, {"url", "www.google.com"}},
{{"name", "微博"}, {"url", "www.weibo.com"}}
}
}
};
Json sites2;
sites2["sites"].push_back({{"name", "王道论坛"}, {"url",
"www.cskaoyan.com"}});
sites2["sites"].push_back({{"name", "google"}, {"url", "www.google.com"}});
sites2["sites"].push_back({{"name", "微博"}, {"url", "www.weibo.com"}});
Json object;
object["key1"] = "value1";
object["key2"] = 2;
// 使用[]运算符可以增加键值对
// 使用push_back方法可以增加数组元素
std::cout << sites1.dump() << "\n";
std::cout << sites2.dump() << "\n";
std::cout << object.dump() << "\n";
}
反序列化
#include <iostream>
#include<nlohmann/json.hpp>
using Json = nlohmann::json;
int main() {
std::string json_string = R"(
{
"sites":
[
{ "name":"王道论坛" , "url":"www.cskaoyan.com" },
{ "name":"google" , "url":"www.google.com" },
{ "name":"微博" , "url":"www.weibo.com" }
]
})";
// 解析JSON字符串
Json sites = Json::parse(json_string);
// 遍历站点信息并打印
for (const auto& site : sites["sites"]) {
std::cout << "Name: " << site["name"] << ", URL: " << site["url"] <<std::endl;
//另一种写法
//std::cout << "Name: " << sites["sites"][i]["name"] << ", URL: " <<
// sites["sites"][i]["url"] << std::endl;
}
return 0;
}