HTTP协议

什么是http协议?

http协议,HyperText Transfer Protocol,超文本传输协议。是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。HTTP是一个基于TCP/IP通信协议来传递数据的客户端服务器(C/S)模型的协议。HTTP协议 是无连接、无状态的协议。

概念名称释义
应用层功能负责应用程序之间的数据沟通
网络通信协议网络数据传输中数据格式的约定
自定制协议我们程序员自己设计的数据传输格式
应用层的知名协议HTTP协议(默认端口80)

关于以上概念我的理解:http请求是通过浏览器上体现的,属于应用层协议,在进行数据通信时候,我们需要让数据按照一定的格式去传输,包括不能改变的http协议格式和我们自制定的数据传输格式。

今天这篇博客就主要总结http协议格式,了解http协议通信原理。

序列化和反序列化

发送数据是将一个结构体按照一个规则转换成字符串,接受到数据再按照相同的规则把字符串转化回结构体的过程叫“序列化”和“反序列化”。

经过序列化的数据如果被抓包,截获者不一定能知道数据的转换规则,就无法很快知道数据内容。

//演示序列化和反序列化
//以什么样的格式存储就以什么样的格式读取
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>

typedef struct 
{
    int id;
    int sex;
    int age;
    char name[32];
}stu;

int main()
{
    stu s;
    s.id=10;
    s.age=23;
    s.sex=1;
    strcpy(s.name,"xiaoming");
    
    int fd=open("./tmp.txt",O_CREAT|O_RDWR,0664);
    if(fd<0){
        printf("open error");
        return -1;
    }
    write(fd,(void*)&s,sizeof(s));
    lseek(fd,0,SEEK_SET);//使文件指针指向文件开头
    char str[1024]={0};
    stu n;
    int ret=read(fd,(void*)&n,sizeof(s));
    if(ret<0){
        printf("read error");
        return -2;
    }
    printf("ID:%d\nAge:%d\nSex:%d\nName:%s\n",n.id,n.age,n.sex,n.name);
    close(fd);
}

在这里插入图片描述

http请求方法

在这里插入图片描述
http请求行总共有三项:请求访问、URI、http版本。
请求方法

  1. GET 请求指定的页面信息,并返回实体主体。
  2. HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。
  3. POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中POST请求可能会导致新的资源的建立和/或已有资源的修改。
  4. PUT 从客户端向服务器传送的数据取代指定的文档的内容。
  5. DELETE 请求服务器删除指定的页面。
  6. CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
  7. OPTIONS 允许客户端查看服务器的性能。
  8. TRACE 回显服务器收到的请求,主要用于测试或诊断。

认识URL

URL全称是统一资源定位符,俗称的“网址”就是不完整的URL。它可以唯一确定服务器上某一资源的位置,其中包括资源路径等信息。下面是URI的一般格式

scheme://userInfo@host:port/path/filename?query_string#fragment
字段中文含义释义
scheme协议方案常见的有http、https、ftp、telnet等
userinfo用户认证信息现在大多数URI已经没有该字段,原因很简单,存在信息泄露风险。
host服务器地址就是服务器的域名。
port服务器端口这里所说的端口是传输层所用的端口,http默认端口是80端口。
/path/filename资源路径请求访问的资源在服务的路径。
query_string查询字符串比如百度搜索C++,该字段内容就是C%2B%2B,表示C++。
fragment片段标识符表示资源内的某一位置。

URI编码(urlencode)和解码(urldecode)

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=C%2B%2B&rsv_pq=fe363a2200027b94&rsv_t=bc57iAA0kdbhJ8QId17ywUFgFLFeh8mpEPAIK6XUDoSzwlw%2FFUD09mst%2FdQ&rqlang=cn&rsv_enter=1&rsv_sug3=4&rsv_sug1=2&rsv_sug7=100&rsv_sug2=0&inputT=2260&rsv_sug4=3461
这是百度搜索C++的URI,在第一行后面,我找到了问号,我们知道问号之后就是查询字符串,我们可以看到这些查询字符串都是Key=Value&的格式。

我们可以看到URI中除了这些字段,还有@ ? # :这些符号用来将上述这些字段分隔开来,那么如果我们的查询字符串(查询字符串可以是任意字符串,比如你要搜索“我为什么这么帅?”就含有?)中含有这些字符,就会出现二义性,因此查询字符串中出现这些特殊字符就需要转义,汉字也需要转移。

对这些特殊字符进行转义,对转义之后的表单进行排列的过程叫URL编码(urlencode),在对端对转义字符进行释义,对数据重新组织的过程称为URL解码(urldecode)。

编码规则:将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。比如+的二进制是0010 1011,转换成十六进制是2B,C++转移之后就是C%2B%2B。

请求报头

请求报头字段都是以key:空格Value的形式存在,一个键值对占一行。以下是我通过fiddler抓取的百度首页的http请求包

GET https://www.baidu.com/ HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie:字段过长,后面会详细说

字段释义
Referer记录的当前页面是从哪一个页面跳转过来的
Connectionkeep-alive持久连接
Content-Length正文的长度
Content-Type数据类型(text/html等)
Host:请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的
User-Agent声明用户的操作系统和浏览器版本信息;
location搭配3xx状态码使用, 重定向地址
Transfer_Encodingchunked分块传输

chunked分块传输

当返回的数据比较大时,如果等待生成完数据再传输,这样效率比较低下。相比而言,服务器更希望边生成数据边传输。可以在响应头加上以下字段标识分块传输:
1)当选择分块传输时,响应头中可以不包含Content-Length。
2)服务器会先回复一个不带数据的报文(只有响应行和响应头和\r\n),然后开始传输若干个数据块。
3)当传输完若干个数据块后,需要再传输一个空的数据块;当客户端收到空的数据块时,则客户端知道数据接收完毕。

http响应-----状态码

在这里插入图片描述
状态码是用来显示http请求的响应状态的标识。HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型。

分类分类描述最常见的栗子
1**信息,服务器收到请求,需要请求者继续执行操作100 Continue 继续。客户端应继续其请求
2**成功,操作被成功接收并处理200 - 请求成功
3**重定向,需要进一步的操作以完成请求301 - 资源(网页等)被永久转移到其它URL
4**客户端错误,请求包含语法错误或无法完成请求404 - 请求的资源(网页等)不存在
5**服务器错误,服务器在处理请求的过程中发生了错误500 - 内部服务器错误

Cookie和Session

为什么需要cookie和session?我们知道TCP通信需要建立连接,应用层数据需要等待1.5RTT才能发出,对于HTTP短连接来说,这个等待时间意味着响应缓慢。所以客户端第一次访问服务器时候,在建立连接过程中,服务器在第二次连接报文中给客户端颁发cookie,可以使得客户端在一段时间内访问服务器,无需等待就可以发送应用数据。

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
在这里插入图片描述
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

Cookie和Session的对比

1)cookie数据存放在客户的浏览器上,session数据放在服务器上;
2)cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session;
3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE;
4)单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K
5)expires过期或者max-age最大生存周期,都是用来标记Cookie字段的有效期的。

最简单的http服务器代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>

int main(int argc,char*argv[])
{
    if(argc!=3){
        printf("USage:./httpser ip port\n");
        return -1;
    }
    int sockfd=-1;
    sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(sockfd<0){
        perror("socket error");
        return -1;
    }
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port=htons(atoi(argv[2]));
    addr.sin_addr.s_addr=inet_addr(argv[1]);
    socklen_t len=sizeof(addr);

    int ret=-1;
    ret=bind(sockfd,(struct sockaddr*)&addr,len);
    if(ret<0){
        perror("bind error");
        close(sockfd);
        return -1;
    }
    ret=listen(sockfd,5);
    if(ret<0){
        perror("listen error");
        close(sockfd);
        return -1;
    }
    while(1){
        struct sockaddr_in cli;
        int newfd=accept(sockfd,(struct sockaddr*)&cli,&len);
        if(newfd<0){
            perror("accept error");
            continue;
        }
        char header[1024]={0};
        ret=recv(newfd,header,1023,0);
        if(ret<=0){
            perror("recv error");
            close(newfd);
            continue;
        }
        printf("header;[%s]\n",header);

        //响应
        char* first ="HTTP/1.1 302 GO\r\n";
        char head[1024]={0};
        char *body="<html><body><h1>Hello,World!</h1></body></html>";
        sprintf(head,"Content-Length: %d\r\n",strlen(body));
        strcat(head,"Location: http://www.baidu.com/\r\n\r\n");
        send(newfd,first,strlen(first),0);
        send(newfd,head,strlen(head),0);
        send(newfd,body,strlen(body),0);
        close(newfd);
    }
    return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值