文章目录
- URL---网址
- 对http协议的宏观认识
- http协议的请求方法
- http响应的状态码
- 最简单的http协议服务器
- 关于http协议的一些概念性知识
URL—网址
首先,http协议是应用层协议, 是超文本传输协议。
urlencode : 转码
urldecode : 解码
将 ++ ---- > %2B%2B就是转码的过程
%2B%2B -----> ++ 就是解码的过程
对http协议的宏观认识
我们知道:网络通信的本质是通过网络文件(fd)来盲读的
那如何保证:每次读取到的是一个完整的request , 并且读不到下一个request呢?
首先: 空行 ------> 保证读完 hander, 然后 hander中有一个Content_Length来表明正文的字节大小
如果没有正文呢? ------ > 也就没有Content_Length
关于相关的报头属性:
Content-Type: 数据类型(text/html等)
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
http协议的请求方法
了解主要的三个就行了。
关于HEAD方法: 只返回报头数据(header) 不会返回body(正文)部分。 没什么好说的
关于GET 和 POST方法
1,两者最主要的区别是 : 当需要提交参数的时候(输入账号 + 密码), GET方法是将参数信息放在了URL(网址中)
而POST方法是将其放入了body(正文)
2, 参数提交的位置不同,就会导致,POST方法比较私密, 不会显示参数信息了URL输入框中
3, 另外的话, URL是有大小限制的, body(正文)是无大小限制的。
再度分析http协议,
如何处理呢? : 本质就是文本分析。
读取 首行 -------> 获得相关属性然后解析
读取 报头 -------> 获得相关属性然后解析
读取 正文--------> 获取相关属性然后解析
http响应的状态码
3xx状态码的特殊含义:
1, 301 永久重定向
2, 302 or 307 临时重定向
永久重定向: 当我们访问某一个网站的时候, 可能会让我们跳转到另一个网址
临时重定向: 当访问某种资源的时候, 提示登录,输入账号 + 密码 然后又跳转回来。
最简单的http协议服务器
Sock.hpp ------> 提供各种接口 : socket() , bind(), connect(), accept(),
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h> //struct sockaddr_in
#include <arpa/inet.h>
using namespace std;
class Sock
{
public:
//创建套接字, 本质是创建网络文件
static int Socket()
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
cout << "sock error" << endl;
exit(1);
}
return sock;
}
//服务端需要绑定, 客户端不需要绑定,由OS自动绑定
static void Bind(int sock, uint16_t port)
{
struct sockaddr_in local;
local.sin_family = AF_INET; //ipv4协议
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY; //链接服务器上的任意一台主机
if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
{
cout << "bind error" << endl;
exit(2);
}
}
//服务端需要监听----监听状态
static void Listen(int sock)
{
if(listen(sock, 5) < 0)
{
cout << "listen error" << endl;
exit(3);
}
}
//服务端需要接受,新的fd实际上提供服务的文件,旧的sock是用来监听的----> "饭馆的拉客少年"
static int Accept(int sock)
{
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int fd = accept(sock, (struct sockaddr*)&peer, &len); //peer是输出型参数,返回的是客户端相关属性
if(fd < 0)
{
cout << "accept error" << endl;
exit(4);
}
return fd;
}
//客户端需要链接的是服务端 需要 ip + port
static void Connect(int sock, string ip, uint16_t port)
{
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip.c_str());
if(connect(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
{
cout << "connect error" << endl;
exit(5);
}
cout << "connect success" << endl;
}
};
http.cpp -----> 接受请求 后 并且返回 一个响应
#include "Sock.hpp"
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
void* handlerHttp(void* argc)
{
int sock = *(int*)argc;
delete (int*)argc;
pthread_detach(pthread_self());
char buff[10240];
memset(buff, 0, sizeof(buff));
ssize_t s = recv(sock, buff, sizeof(buff) - 1, 0);
if(s > 0)
{
buff[s] = 0;
cout << buff << endl;
string response = "http/1.0 200 ok \n";
response += "Content-Type: text/plain\n"; //text/plain 就是普通文本
response += '\n'; // 报头和正文的分界线
response += "Do you eat breakfast good morning good ningt";
send(sock, response.c_str(), response.size(), 0);
}
close(sock);
return nullptr;
}
void Usage(const char* proc)
{
cout << "Usage:" << endl;
cout << "./http" << " proc" << endl;
}
// ./http port
int main(int argc, char* argv[])
{
if(argc != 2)
{
Usage(argv[0]);
return 1;
}
//创建套接字, 本质是创建文件
int sock = Sock::Socket();
//绑定
Sock::Bind(sock, atoi(argv[1]));
//监听状态
Sock::Listen(sock);
//接受状态
while(1)
{
int fd= Sock::Accept(sock);
if(fd > 0)
{
int* pram = new int(fd);
pthread_t td;
pthread_create(&td, nullptr, handlerHttp, pram);
}
}
return 0;
}
关于http协议的一些概念性知识
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD (但是http1.1也是支持的)
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT
下面三个都是应用层协议
SMTP:简单邮件协议
FTP:文件传输协议
TELNET:Internet远程登录服务的标准协议
UDP:用户数据报协议 (这是传输层协议)
http状态码中,(2xx )表示访问成功,( 4xx)表示坏请求,(5xx )表示服务不可用。
坏请求 : 客户端的错
服务不可用: 服务端的错
HTTP协议,是TCP/IP协议栈中应用层的协议
Cookie数据是在HTTP协议头部字段中传输
HTTP协议在目前1.1版本中支持了长连接管理,也就是支持在一定时间内保持TCP连接建立,用于发送/接收多次请求**(keep-alive)**
HTTP协议是无状态的协议,在最初设计的时候HTTP协议是一种简单的请求-响应协议,即一次建立连接中,完成一次请求一次响应后,通信结束关闭连接,所以是无状态的
GET请求提交参数是放在URL中的, 有长度限制,
POST请求提交参数是放在body(正文中), 无长度限制。
POST请求不会被缓存 ----> 对数据长度无限制(body) -------> 无法从浏览器中找到
GET请求可以缓存,可以从浏览记录中找到 ------->数据长度有限制(URL)
对与PUT方法而言:-------一定会有资源
PUT方法请求服务器去把请求里的实体存储在请求URI(Request-URI)标识下。
如果请求URI(Request-URI)指定的的资源已经在源服务器上存在,那么此请求里的实体应该被当作是源服务器关于此URI所指定资源实体的最新修改版本。
如果请求URI(Request-URI)指定的资源不存在,并且此URI被用户代理定义为一个新资源,那么源服务器就应该根据请求里的实体创建一个此URI所标识下的资源。如果一个新的资源被创建了。
HEAD请求是没有响应体的,仅传输状态行和标题部分 (首行 + header)
DELETE方法用来删除指定的资源,它会删除URI给出的目标资源的所有当前内容
PUT方法用于将数据发送到服务器以创建或更新资源,它可以用上传的内容替换目标资源中的所有当前内容
403:禁止访问,服务器拒绝接收到请求但拒绝提供服务,原因较多,比如权限不足,IP被拉入黑名单…
4xx:客户端的错
503: 表示服务器端暂时无法处理请求 -----> 服务端的错误 ----->5xx