【linux】http协议

HTTP(超文本传输协议)是Web浏览器和服务器之间交换请求和应答报文的通信协议,是在应用层上面的一种协议。首先来了解一下HTTP协议的一些特性。
HTTP一共有两个特性:
(1)无状态性
HTTP协议在传输层使用的是TCP协议,为了提高Web浏览器的并发处理能力,协议的设定者规定Web服务器在接收到浏览器HTTP请求报文,返回应答报文之后不保存先关Web浏览器的任何信息。。因此,HTTP属于一种无状态的协议。(浏览器可以用cookie或者session来保存Web浏览器的信息)
(2)非持续性和持续性
首先来了解一下什么是非持续性和持续性?
非持续性就是当客户向服务器发送多个服务请求报文,服务器需要对每一个请求报文进行应答,并为每一个应答过程建立一个TCP连接的工作过程叫做非持续性连接。
持续性连接指的是多个客户与服务器之间的请求报文和应答报文可以通过一个TCP连接来完成。
下面来了解几个基本概念:
URL:
我们常说的网址就是url
这里写图片描述
这就是一个普通url的结构。
urlencode和urldecode
像/?这样的字符,已经被url当做特殊意义理解了,因此这种字符不能随意出现,比如某个参数中需要带有这些特殊字符,就必须先对特殊字符进行转义
转义的规则如下:
将需要转码的字符转到十六进制,然后从右到左,取4位(不足4位直接处理),每两位作为一位,前面加上%,编码成%XY格式。
例如:
这里写图片描述
“+”被转成了“%2B”
urldecode就是urlencode的逆过程
HTTP协议格式:
HTTP请求:
这里写图片描述
上面就是:一次HTTP请求的内容:
以空行为分界线上面的就是报头信息,下面的是数据信息
下面来大概介绍一下各字段分别代表什么含义:
第一行:[方法]+[url]+[版本]
Header:请求的属性,,冒号分割的键值对;每组属性之间用\n分隔,遇到空行代表头部结束
Body:空行后面的内容都是数据,数据信息允许为空,如果数据信息不为空,则在头部信息中会有一个字段Content-length属性来表示数据信息的长度
HTTP响应报文:
这里写图片描述
第一行:[版本号]+[状态码]+[状态码解释]
Header(头部):请求属性,冒号分割的键值对,每组属性之间使用\n分隔,遇到空行,表示头部结束
Body:空行后面都是数据信息,数据信息允许为空字符串,如果数据信息不为空,那么头部信息会出现一个Content-length字段,用来表示数据信息的长度,如果服务器返回一个html页面,那么html页面内容就是在数据信息中
HTTP的方法:
这里写图片描述
其中最常见的就是GET和POST方法:
HTTP的状态码:
这里写图片描述
最常见的状态码有:
200(OK),404(Not Found),403(Forbidden),302(Redirect,重定向),504(Bad Gateway)
HTTP常见头部选项:
Content-Type:数据选项(text/html等)
Conteht-Length:数据信息的长度
Host:客户端告知服务器,所请求的资源是在哪个主机的哪个端口上
User-Agent:声明用户的操作系统和浏览器版本信息
referer:当前页面是从哪个页面跳转过来的
location:搭配3xx状态码使用,告诉客户端下面该去哪里访问
Cookie:用于客户端存储少量信息,通常用于实现Session的功能
简单实现一个http服务器,该服务器的功能是在网页上显示一个hello world
代码如下:

#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("./server[ip][port]");

}
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        usage();
        return;
    }
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd<0)
    {
        perror("socket");
        return 1;
    }
    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");
        return 1;
    }
    ret = listen(fd,10);
    if(ret<0)
    {
        perror("listen");
        return 1;
    }
    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");
            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 1;
        }
        printf("[Request]%s",input_buf);
        char buf[1024] = {0};
        const char* hello = "<h1>hello world</h1>";
        sprintf(buf,"HTTP/1.0 200 OK\n\
                Content-Length:%lu\n\n%s",strlen(hello),hello);
        write(client_fd,buf,strlen(buf));
    }
    return 0;
}

编译并运行服务器:
这里写图片描述
使用网页连接服务器:
这里写图片描述
网页上能正常显示hello world
再看服务器的现象可得:
这里写图片描述
注意:我们常说http服务器端口号是80,但这只是常见用法,并不是不能使用其它端口号,经试验验证9999也是可以的嘛。

版权声明:本文为flowing_wind原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/flowing_wind/article/details/80725694