文章目录
HTTP的引入
在当今社会我们已经离不开网络了,基本上我们随时随地都能上网,那你知道上网的实质是干啥吗?
其实很简单:我们做的所有互联网行为都是两种操作:
- 把服务器上的数据拿下来。
- 把自己的数据传到服务器上去。
当然上网必不能缺少HTTP协议了,我们知道了HTTP是位于应用层的协议,接下来让我们具体来学习HTTP的内容吧!
HTTP基本特征
- 无连接 :TCP建立连接和http式无关的,http直接向对方发送http request即可。
- 无状态 :http本身是无状态的,并不会记录任何用户信息,记录你的基本信息的技术是cookie + session
- 简单快速 : 短链接进行文本传输(http/1.0) 长连接(http/1.1)
认识URL
平时我们所说的“网址”,指的就是URL,是用来定位互联网上的资源的,通常以路径的形式展现(资源所处的路径)。
urlencode和urldecode
这俩的作用相当于编码和解码。
因为像 / ? :这样的字符会被url当作特殊意义理解。因此这些字符不能随意出现。
要是某个参数中需要带有这些字符,那就必须对这些特殊字符进行转义。
转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式
例:
HTTP构成结构图解:
HTTP请求: 对照图解理解更深
首行: [方法] + [url] + [版本]
- Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
- Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度;
HTTP响应:
首行: [版本号] + [状态码] + [状态码解释]
- Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
- Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个
- Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在
body中.
HTTP的方法:
其中最长用的就是GET方法和POST方法:
两者的区别:
- 在都传参的情况下,GET通过url传参,POST通过正文传参。 因此POST比GET更私密。
- GET传参内容有限,POST理论上可以传更多的参数
HTTP状态码:
HTTP常见的Header
- Content-Type: 数据类型(text/html等)
- Content-Length: Body的长度
- Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
- User-Agent: 声明用户的操作系统和浏览器版本信息;
- referer: 当前页面是从哪个页面跳转过来的;
- location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
- Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能
HTTP 状态性的保证
由于http是无状态的,所以用户体验会极差,因此需要维护用户的体验感,那么是怎样做的呢??下面我们看图理解一下:
cookie的作用:
当然我们要是只用cookie,这个对于用户来说是不安全的,因为当服务器会将用户的信息发送回来,这样其实就相当于你的私密信息在网上“裸奔”,你的私密信息极容易被恶意窃取。那么有没有相对安全的技术呢??下面我们来具体介绍:
cookie+session(相对安全)
这样在传输的时候只是sid暴漏在外面,你的信息存储在服务器中,当然服务器的安全性肯定要比我们自身的浏览器要高!!!
一个简单的http服务器
实现一个最简单的HTTP服务器, 只在网页上输出 “hello world”;
// httpSever.hpp
#pragma once
#include<iostream>
#include<string>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<signal.h>
#include<strings.h>
#define BACKLOG 5
using namespace std;
class httpSever{
private:
int port;
int lsock;
public:
httpSever(int _p)
:port(_p),lsock(-1)
{}
void InitSever()
{
lsock=socket(AF_INET,SOCK_STREAM,0);
if(lsock < 0)
{
cerr<<"socket error!!"<<endl;
exit(2);
}
struct sockaddr_in local;
bzero(&local,sizeof(local));
local.sin_family=AF_INET;
local.sin_port=htons(port);
local.sin_addr.s_addr=htonl(INADDR_ANY);
if( bind(lsock,(struct sockaddr*)&local,sizeof(local))< 0)
{
cerr<<"bind error!!"<<endl;
exit(3);
}
if(listen(lsock,BACKLOG)< 0)
{
cerr<<"listen error!!"<<endl;
exit(4);
}
}
void server(int sock)
{
char request[2048];
ssize_t s=recv(sock,request,sizeof(request),0);// 假设一次能读完一次请求
if(s>0){
request[s]=0;
cout<<request<<endl;
// 构建响应
string response="HTTP/1.0 200 OK\r\n"; //响应行
response +="Content-type: text/html\r\n"; // 响应报头
response +="\r\n"; //空行
response +="<!DOCTYPE html>\ //一个网页
<html>\
<head>\
<title>guokk</title>\
</head>\
<body>\
<h1>Welcome</h1>\
<p>hellow world</p>\
</body>\
</html>";
send(sock,response.c_str(),response.size(),0);
}
close(sock);
}
void start()
{
signal(SIGCHLD,SIG_IGN);
struct sockaddr_in peer;
for(;;)
{
socklen_t len=sizeof(peer);//len每次都要求
int sock=accept(lsock,(struct sockaddr*)&peer,&len);
if(sock<0)
{
cerr<<"accept error!!"<<endl;
continue;
}
cout << "get a new connect ..."<< endl;
if(fork()==0)
{
close(lsock);
server(sock);
exit(0);
}
close(sock);
}
}
~httpSever()
{
if(lsock!=-1)
close(lsock);
}
};
//##################################
// httpSever.cc
#include"httpSever.hpp"
void Usage( string proc )
{
cout<<"Usage \n\t";
cout<<proc << " port "<<endl;
}
int main(int argc,char*argv[])
{
if(argc !=2)
{
Usage(argv[0]);
exit(1);
}
httpSever*hp= new httpSever(atoi(argv[1]));
hp->InitSever();
hp->start();
delete hp;
return 0;
}
结果展示:
HTTPS
https和http 都是超文本传输,但是https有很多安全性考量,因此https会比http慢。
对称加密和非对称加密
-
对称加密
-
非对称加密
那么有的人就会问了,为什么并不直接通过非对称加密传输数据呢??而是费那么大的劲把对称加密的密钥传输过去??
原因很简单:因为非对称加密采用的算法复杂,效率较低,而非对称加密的效率高。 -
中间服务器监听问题
由于服务器被监听所以有两个问题必须解决:
-
如何防止中间信息被篡改的问题?
数据摘要+数据签名技术
-
远端服务器的身份认证问题?(怎么保证你访问的服务器是合法的)