HTTP协议

协议
协议是一种“约定”,socket api的接口,在读写数据时都是按“字符串”的方式来发送的。如果我们要传输一些“结构化的数据”该怎么办?

应用层
程序员写的一个个解决实际问题的,满足日常需求的网络程序,都是工作在应用层的。

http分层解剖
在这里插入图片描述
与HTTP有关的一些协议:
在我之前的博客有总结,附上链接:
TCP:https://blog.csdn.net/aixintianshideshouhu/article/details/90147529
IP:https://blog.csdn.net/aixintianshideshouhu/article/details/90213726
数据链路层:https://blog.csdn.net/aixintianshideshouhu/article/details/90214227
DNS:https://blog.csdn.net/aixintianshideshouhu/article/details/90265960

HTTP协议的特点
客户端/服务器模式;
简单快速,因为HTTP服务器规模小,通信速度块;
灵活,可传输任意类型的数据,Content-Type来标记正在传输的类型;
无连接,基于请求响应(客户端发起http请求,服务器响应请求,链接断开);
无状态,不会保留之前的一切请求或响应;

URI和URL的区别
URI:用来唯一的表示一个资源;
URL:是一种具体的URI,不仅唯一的表示了一个资源,还指明了如何定位该资源;
嗯,简单来说,可以认为,如果把一个资源唯一的表示出来,就可以认为该标识就是URI,如果这个标识还可以定位该资源,那么它也可以是一个URL;

URL格式

http://host["":port][url]
如没有给URL,则浏览器自动以“/”的形式输出

在这里插入图片描述
urlencode和urldecode
象/?:等这样的字符,已经被url当做特殊意义理解了,因此这些字符不能随意出现。
比如,某个参数中需要带有这些特殊字符,就必须先对特殊字符进行转义。

转义规则如下:
将需要转码的字符转为16进制,然后从右到左,取四位(不足四位直接处理),没两位做一位,前面加上%,编码成%XY格式

"+"被转义成了“%2B”
urldecode就是urlencode的逆过程。

HTTP请求与相应格式
在这里插入图片描述
请求
请求行:包括方法,url和版本,用空行做间隔,以换行符分割请求报头;
请求报头:属性都采用name: value的形式,(注意value前面有空格),每个属性以换行符分割;遇到空行就表示走完了头部,所以空行有效的划分了头部和数据;
请求正文:可以为空,如果正文存在,则在报头中有一个Content-Length字段来标识正文的大小。

响应
状态行:包括版本,状态码,状态码描述,以换行符结束。
响应报头:格式与请求报头相同;
响应正文:可以为空,如果正文存在,则在报头中有一个Content-Length字段来标识正文的大小。

http请求方法
根据HTTP标准,HTTP请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

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

其中最常用的就是GET和POST方法。

GET和POST的区别:

        1、GET请求的数据是放在HTTP包头中的,也就是URL之后,通常是像下面这样定义格式的:
login.action?name=hyddd&password=idontknow&verify=%E4%BD%E5%A5%BD
其中,以?来分隔URL和数据;以&来分隔参数;如果数据是英文或数字,原样发送;如果数据是中文或其它字符,则进行BASE64编码。
而Post是把提交的数据放在HTTP正文中的。
        2、GET提交的数据比较少,最多1024B,因为GET数据是附在URL之后的,而URL则会受到不同环境的限制的,比如说IE对其限制为2K+35,而POST可以传送更多的数据(理论上是没有限制的,但一般也会受不同的环境,如浏览器、操作系统、服务器处理能力等限制,IIS4可支持80KB,IIS5可支持100KB)。
        3、Post的安全性要比Get高,因为Get时,参数数据是明文传输的,参数直接暴露在url中,所以不能用来传递敏感信息。而且使用GET的话,还可能造成Cross-site request forgery攻击。而POST数据则可以加密的,但GET的速度可能会快些。
        4、get请求只能进行url编码,而post支持多种编码方式;get请求会浏览器主动cache,而post支持多种编码方式;get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
        5、GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
        6、GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

http状态码

状态码分五类,分别是1开头,2开头,3开头,4开头,5开头。
在这里插入图片描述
常见状态码总结:
200:客户端的请求被正确处理
204:请求被正确处理,但是请求正文为空
206:表示客户读服务器进行了范围请求,服务器成功处理,响应报头中有一个属性Content-Range指明范围。

301:永久重定向,表示客户端请求的资源已经被分配了新的url
302:临时重定向,表示客户端请求的资源已经被分配了新的url,让用户本次使用新的url访问
307:也是临时重定向


301和302的区别,举个例子:
一个店,换地方开了,那就是301.
如果 因为装修啥的,暂时搬到了别的地方,过段时间又回来继续开,就是302.
303:也是临时重定向,但明确使用GET方法定向获取请求的资源。
当301,302,303作为状态码返回,几乎所有的浏览器都会把POST改成GET方法,即使301,302进制将POST改成GET方法。
307:也是临时重定向,但是307不会吧POST改成GET

400:表示请求报文中存在语法错误,需修改后在请求
403:表示客户端请求的资源被服务器拒绝
404:not found,表示服务器上没有客户端请求的资源

500:表示服务器在响应时发生错误
503:标识服务器处于超负载或正在维护,无法处理请求

http常见的header
Content-Type: 数据类型(text/html等)
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

模拟实现简单的http服务器
要想实现一个简答的http服务器,只在网页上输出"hello world";只需要按照http协议的要求构造数据就好了。

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

void Usage()
{
    printf("Usage: ./server [ip] [port]\n");
}

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        Usage();
        return 1;
    }
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd < 0)
    {
        perror("socket error");
        return 2;
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));

    int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0)
    {
        perror("bind error");
        return 3;
    }
    ret = listen(fd, 10);
    if(ret < 0)
    {
        if(ret < 0)
        {
            perror("listen error");
            return 4;
        }
    }
    for(;;)
    {
        struct sockaddr_in client_addr;
        socklen_t len;
        int client_fd = accept(fd, (struct sockaddr*)&client_addr, &len);
        if(client_fd < 0)
        {
            perror("accept error");
            return 5;
            continue;
        }
        char input_buf[1024*10] = {0};//用足够大的缓冲区把数据读完
        ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf)-1);
        if(read_size < 0)
        {
            return 6;
        }
        printf("[Request]%s", input_buf);
        char buf[1024] = {0};
        const char* hello = "<h1>hello world!!!<h1>";
        sprintf(buf, "HTTP1.1 302 OK\nContent-LengthLocation:www.baidu.com:%lu\n\n%s", strlen(hello), hello);
        write(client_fd, buf, sizeof(buf));
    }
    return 0;
}

编译,启动服务,在浏览器中输入http://[ip]:[port],就能看到显示的结果“hello world”
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值