计算机网络——http协议

http协议

本质是文本分析:1.http协议本身的字段;2.提取参数(如果有的话)

URL/网址:

统一资源定位服务,定位网络资源的一种方式

IP+Port:唯一确定一个进程
IP:唯一确定一台主机
绝对路径:唯一确定一个资源(Linux下所有资源都是以文件形式保存的)
所以,IP+Linux路径可以唯一确定一个网络资源

举例

https://blog.csdn.net/qq_56101220?type=blog
协议+域名+资源路径
https:协议方案名
blog.csdn.net:ip
qq_56101220:资源路径
?type=blog:查询字符串

请求的结构:(自顶向下)

请求的结构
请求行:请求方法 /url /http版本
请求报文(多行)(key:value\n)
空行
请求正文:用户提交的数据

响应的结构:

响应的结构
状态行:http版本 /状态码 /状态码描述
响应报头(多行)
空行
响应正文:html、css、音乐、图片、视频等

http的请求和响应:
被看作是一个大的字符串,
http的解包和封装:
空行:特殊字符,用空行将长字符串一切为二,解包时将报头按行读取,读到空行说明报头读取结束,剩下的内容是有效载荷;封装时构建http请求,之后加上空行,空行之后才是有效载荷
分用:
不是http解决,而是具体的应用代码解决的,http需要有接口来帮助上层获取参数

代码实现

#include "socket.hpp" //套接字方法的封装
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
using namespace ns_sock;
void *Routine(void *args)
{
    int sock = *(int *)args;
    delete (int *)args;
    pthread_detach(pthread_self());
    #define SIZE 1024*10
    char buf[SIZE];
    memset(buf,0,sizeof(buf));
    ssize_t s = recv(sock,buf,sizeof(buf),0);//read
    if(s>0){
        buf[s] = 0;
        std::cout<<buf;
        std::string http_response = "HTTP1.0 200 OK\n";
        http_response+="Content-Type:text/plain\n";
        http_response+="\n";
        http_response+="hello\n";
        send(sock,http_response.c_str(),http_response.size(),0);//write

    }
    close(sock);
}
void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " port" << std::endl;
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = atoi(argv[1]);
    int sock = Sock::Socket();
    Sock::Bind(sock, port);

    Sock::Listen(sock);

    for (;;)
    {
        int new_sock = Sock::Accept(sock);
        pthread_t pid;
        int *parm = new int(new_sock);
        pthread_create(&pid, nullptr, Routine, parm);
    }
}

浏览器显示的结果:
在这里插入图片描述

http请求的结果:
在这里插入图片描述

第一行:请求行
中间部分:请求报文
最后:空行

http中的重要属性(Header):

(1)Content-Type:用于定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件,比如text/html 表示html文件 content-type对照表
(2 )Content-Length:响应正文的长度
(3)Location:搭配3XX状态码,告诉客户端接下来去哪里访问
(4)connection:长/短连接;短连接:每个资源都要发起http请求,Http/1.0;长连接:客户端发起请求设置一个字段connection:keep-alive(保持活跃),http/1.1之后
短连接:一个大网页由多个元素组成,访问这个网页时需要多次进行http请求,而http协议是基于tcp协议的,因此每次请求都需要进行建立连接、传送数据、断开连接的过程,耗费时间
长连接:建立一个连接,网页中的资源都可以通过这一个连接得到,通过减少频繁建立tcp连接,来达到提高效率的目的
(5)Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
(6)User-Agent: 声明用户的操作系统和浏览器版本信息;
(7)referer: 当前页面是从哪个页面跳转过来的;
(8)Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

GET:获取资源

参数提交到url中
默认一般获取所有的网页都是GET方法,GET通过URL来进行参数拼接,从而将参数提交给服务端
在这里插入图片描述

在这里插入图片描述

POST:传输实体主体

一般通过正文提交参数
在这里插入图片描述

在这里插入图片描述

对比:

1.参数提交的位置不同,POST方法比较私密,GET方法不私秘,会将信息回显到url输入框中,增加了被盗取的风险
2.GET通过url传参,url通常有大小限制,具体和浏览器有关,POST通过正文传参,没有大小限制

结论:

GET和POST是前后端交互的重要请求方法,如果提交的参数不敏感且长度短,可以选择GET,否则就使用POST方法

源码:

// http.cc
#include "socket.hpp"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fstream>
#define PATH "./wwwroot/"
#define FILE_NAME "index.html"
using namespace ns_sock;
void *Routine(void *args)
{
    int sock = *(int *)args;
    delete (int *)args;
    pthread_detach(pthread_self());

#define SIZE 1024 * 10
    char buf[SIZE];
    memset(buf, 0, sizeof(buf));
    ssize_t s = recv(sock, buf, sizeof(buf), 0);
    if (s > 0)
    {
        buf[s] = 0;
        std::cout << buf;
        // 文件版
        std::string http_file = PATH;
        http_file += FILE_NAME;

        std::ifstream in(http_file);
        if (in.is_open())
        {
            // std::cout << "open success" << std::endl;
            std::string http_response = "HTTP/1.0 200 OK\n";
            struct stat st;
            stat(http_file.c_str(), &st);
            http_response += "content-type: text/html; charset=utf8\n";
            http_response += "content_length:";
            http_response += std::to_string(st.st_size);
            http_response += "\n";
            http_response += "\n";
            std::string content;
            std::string line;
            while (getline(in, line))
            {
                content += line;
            }
            http_response += content;
            // std::cout << http_response << std::endl;
            in.close();

            send(sock, http_response.c_str(), http_response.size(), 0);
        }
    }
    close(sock);
}
void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " port" << std::endl;
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = atoi(argv[1]);
    int sock = Sock::Socket();
    Sock::Bind(sock, port);

    Sock::Listen(sock);

    for (;;)
    {
        int new_sock = Sock::Accept(sock);
        pthread_t pid;
        int *parm = new int(new_sock);
        pthread_create(&pid, nullptr, Routine, parm);
    }
}
<!-- wwwroot下的index.html文件  -->
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
</head>

<body>
    <h3>首页</h3>
    
    <h5>表单</h5>
    <!-- get方法 -->
    <form action="/" method="post"> 
        姓名:<input type="text" name="name"><br/>
        密码:<input type="password" name="password"><br/>
        <input type="submit" value="登录"/>
    </form>

</body>

</html>

HTTP状态码

类别原因短语
1XX信息性状态码接收的请求正在处理
2XX成功状态码请求正常处理完成
3XX重定向状态码需要进行附加操作以完成请求
4XX客户端错误状态码服务器无法处理请求
5XX服务器错误状态码服务器处理请求出错

常见状态码

200:ok;404:not found;403:forbidden;504:bad gateway;301:永久重定向;302/307:临时重定向
重定向:访问某一个网站时跳转到另一个网址,或者比如支付时的自动跳转
永久重定向:Permanently moved新的域名替 换旧的域名,如网站搬迁,域名更换,书签的网址也会更换
临时重定向:Found,一般是业务的某个环节,比如登录后、支付后自动跳转的情况

cookie和session

http是一种无状态协议
cookie:
浏览器角度:是一个保存用户私密信息的文件(内存版(关掉浏览器就没了)和文件版(重启电脑也在))
在这里插入图片描述

http协议角度:在对有cookie信息的网站发起任何请求时,都会在request中携带cookie信息

网页登录一次后自动登录的原理:第一次登录成功后将账号密码等私密信息保存在cookie中,在后续的请求中,浏览器会在每一个请求的请求报头属性中自动携带对应的cookie
set-cookie:服务器向浏览器设置一个cookie
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

风险:
如果别人盗取了我们的cookie文件,那么他就可以以我的身份进行认证访问特定的资源,还可以得到我的账号密码,因此单纯使用cookie是具有安全隐患的

session:
本质:将用户的私密信息保存在服务端
客户端用户发送携带账号密码的http请求进行登录 ,服务端对输入的内容进行认证,接下来给该用户形成一个保存他的私密信息的session文件,而每个session文件有它唯一的会话id:session_id,之后服务端再构建http响应,给对应客户设置Cookie,其中保存了session_id。
所有的http请求,都会由浏览器自动携带cookie内容,即当前用户的session_id,实现会话保持功能(server可以做到认识client)
cookie+session仍旧有风险,因为cookie文件保存在用户主机,也会被盗取,可以和用户访问相同的网站
防护措施:异地登录认证(IP识别),重新登陆(重新生成新的session_id);强制下线(服务端直接清掉session文件)
结论:cookie+session可以提高用户访问网站或平台的体验,使无状态的http协议的上下文记录下用户的状态

最终源代码

#include "socket.hpp"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fstream>
#define PATH "./wwwroot/" //设置的web根目录,此目录下的文件都叫做资源
#define FILE_NAME "index.html"  //首页,默认进入
using namespace ns_sock;
void *Routine(void *args)
{
    int sock = *(int *)args;
    delete (int *)args;
    pthread_detach(pthread_self());

#define SIZE 1024 * 10
    char buf[SIZE];
    memset(buf, 0, sizeof(buf));
    ssize_t s = recv(sock, buf, sizeof(buf), 0);
    if (s > 0)
    {
        buf[s] = 0;
        std::cout << buf;

        // // 重定向
        // std::string http_response = "HTTP/1.1 301 Permanently moved\n";
        // http_response += "Location: https://www.qq.com/\n";
        // http_response += "\n";
        // send(sock, http_response.c_str(), http_response.size(), 0);


        // std::string http_response = "HTTP1.0 200 OK\n";
        // http_response+="Content-Type:text/plain\n";
        // http_response+="\n";
        // http_response+="hello\n";
        // send(sock,http_response.c_str(),http_response.size(),0);

        // 文件版
        std::string http_file = PATH;
        http_file += FILE_NAME;

        std::ifstream in(http_file);
        if (!in.is_open())
        {
             std::string http_response = "http/1.0 404 NOT FOUND\n";
            // 正文部分的数据类型
            http_response += "Content-Type: text/html; charset=utf8\n";
            http_response += "\n";
            http_response += "<html><p>你访问的资源不存在</p></html>";
            send(sock, http_response.c_str(), http_response.size(), 0);
        }
        else
        {

            //std::cout << "open success" << std::endl;
            std::string http_response = "HTTP/1.0 200 OK\n";
            struct stat st;
            stat(http_file.c_str(), &st);
            http_response += "content-type: text/html; charset=utf8\n";
            http_response += "content_length:";
            http_response += std::to_string(st.st_size);
            http_response += "\n";

            // cookie
            // set-cookie:服务器向浏览器设置一个cookie
            http_response+="set-cookie:name=111\n";
            http_response+="set-cookie:password=123\n";

            http_response += "\n";
            std::string content;
            std::string line;
            while (getline(in, line))
            {
                content += line;
            }
            http_response += content;
            // std::cout << http_response << std::endl;
            in.close();

            send(sock, http_response.c_str(), http_response.size(), 0);
        }
    }
    close(sock);
}
void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " port" << std::endl;
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = atoi(argv[1]);
    int sock = Sock::Socket();
    Sock::Bind(sock, port);

    Sock::Listen(sock);

    for (;;)
    {
        int new_sock = Sock::Accept(sock);
        pthread_t pid;
        int *parm = new int(new_sock);
        pthread_create(&pid, nullptr, Routine, parm);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值