Linux_网络_应用层协议 http/https(协议格式,协议方法,状态码,常见Header)

14 篇文章 3 订阅

认识URL

URL是我们平时说的网址

eg:http常见的URL
http://user:pass@www.example.jp:80/dir/index.htm?uid=1#ch1

在这里插入图片描述
注意:

  1. 服务器地址就是域名,相当于服务器ip地址

  2. 像http服务绑定80端口号,https服务绑定443端口。ssh服务端口绑定22号端口。所以只要知道使用的是http协议就知道使用的是80端口。所以这个也可以省略。

  3. 服务文件地址:就是想要获得的资源(视频,图片,网页等)在服务器的路径

  4. ?后查询字符串,是这次http请求的参数。是客户端与服务器之间传递数据的一种方式,多个参数之间用&连接

  5. 片段标识符:当浏览网页时,点击下一张图片,网页不刷新。此时片段标识符一直在更新。

urlencode与urldecode

像 / 与 ?这些特殊字符在URL中的特殊符号时,URL会将这些关键字特殊处理

URL会将这些关键字进行转义,将需要转码的字符转化为16进制,然后从右到左取4位,不足4位直接处理,再每2位做一位前加上%,编码成%XY的形式

urldecode:
在这里插入图片描述
urlencode:
在这里插入图片描述
在这里插入图片描述

1.http协议

http协议是基于请求与响应的应用层协议(cs / bs 模式)

一次http请求包括客户端向服务器request请求,服务器向客户端response响应

http协议 请求格式

常规情况下,http(s)下层传输层协议使用的是tcp协议。

下面用C++ 实现服务器,启动浏览器访问这个服务。将浏览器发送给服务器的request请求打印出来分析http客户端请求的格式

TCP相关套接字方法见:
Linux_套接字(C++_TCP回显服务器——多进程/线程池(生产者消费者模型)处理多链接请求)

#include<stdlib.h>
#include<iostream>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<cstring>
#include<sys/wait.h>

int main(){
  int listen_sock=socket(AF_INET,SOCK_STREAM,0);
  if(listen_sock<0){
    std::cerr<<"socket error"<<std::endl;
    return 1;
  }

  struct sockaddr_in local;
  memset(&local,0,sizeof(local));

  local.sin_family=AF_INET;
  local.sin_port=htons(8081);
  local.sin_addr.s_addr=INADDR_ANY;

  if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){
    std::cerr<<"bind error"<<std::endl;
    return 2;
  }

  if(listen(listen_sock,5)<0){
    std::cerr<<"listen error"<<std::endl;
    return 3;
  }

  sockaddr_in client;
  while(true){
    socklen_t len=sizeof(client);
    int sock=accept(listen_sock,(struct sockaddr*)&client,&len);
    if(sock<0){
      std::cout<<"accept error"<<std::endl;
      continue;
    }

    if(fork()==0){
      if(fork()>0){
        exit(0);
      }
      close(listen_sock);
      //读取客户端请求
      char buff[1024];
      size_t size=recv(sock,buff,sizeof(buff)-1,0);
      buff[size]='\0';
      std::cout<<"################http begin#####################"<<std::endl;
      std::cout<<buff<<std::endl;

      exit(0);
    }
    close(sock);
    waitpid(-1,nullptr,0);
  }
  return 0;
}

在这里插入图片描述
客户端向服务器发送请求

服务器打印http请求
在这里插入图片描述
分析上面的打印结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这一行称为请求行。


此外,像这些key:value代表了这次请求的若干属性
在这里插入图片描述
eg:
User-Agent:发起这次请求的浏览器的信息

这部分称为请求报头

综上http协议格式为:
在这里插入图片描述

http协议 响应格式

在这里插入图片描述
当客户端读取到空行时,代表客户端已经读取完http响应报头了。

注意:

  • 客户端向服务器发送请求http时首行带的http版本是客户端的http版本。服务器接受到请求报头时,识别http版本,用对应的http版本进行处理业务。提高了兼容性

  • 响应报头中的状态码:表示服务器处理请求的情况,常见的状态码有200(OK)、404(Not Found)等

http协议方法(GET 、POST)

http GET方法:
在这里插入图片描述
http POST方法:
在这里插入图片描述
对比两种请求的请求报头可以发现POST方法比GET方法多了
Content-Length项

GET方法:

  1. 直接获取资源信息
  2. GET方法可以带参数,参数在URL?后面都是GET的参数,通过URL传递给服务器
    在这里插入图片描述

POST方法:

  1. 通过正文提交数据给服务器,不通过URL
    在这里插入图片描述

http在读取正文时如果此时是POST方法

空行的下一行就是正文,根据Content-Length项可以知道应该在正文上读取几个字节。通过这种方法(POST+Content-Length)就可以有效的读取http正文(请求或响应)

C++实现服务器响应 观察http响应,以及POST 、GET传参

简单的html网页index.html

<html>
  <header><h5>log in<h5><header>
  <body>
    <form method="GET" action="/s">
      user:<br>
      <input type="text" name="user">
      <br>
      password:<br>
      <input type="text" name="passowrd">
      <br>
      <input type="submit" value="register">
  <body>
</html>
#include<string>
#include<stdlib.h>
#include<iostream>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<cstring>
#include<sys/wait.h>

#include<fstream>

int main(){
  int listen_sock=socket(AF_INET,SOCK_STREAM,0);
  if(listen_sock<0){
    std::cerr<<"socket error"<<std::endl;
    return 1;
  }

  struct sockaddr_in local;
  memset(&local,0,sizeof(local));

  local.sin_family=AF_INET;
  local.sin_port=htons(8081);
  local.sin_addr.s_addr=INADDR_ANY;

  if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){
    std::cerr<<"bind error"<<std::endl;
    return 2;
  }

  if(listen(listen_sock,5)<0){
    std::cerr<<"listen error"<<std::endl;
    return 3;
  }

  sockaddr_in client;
  while(true){
    socklen_t len=sizeof(client);
    int sock=accept(listen_sock,(struct sockaddr*)&client,&len);
    if(sock<0){
      std::cout<<"accept error"<<std::endl;
      continue;
    }

    if(fork()==0){
      if(fork()>0){
        exit(0);
      }
      close(listen_sock);
      //读取客户端请求
      char buff[1024];
      size_t size=recv(sock,buff,sizeof(buff)-1,0);
      buff[size]='\0';
      std::cout<<"################http begin#####################"<<std::endl;
      std::cout<<buff<<std::endl;
#define PAGE "index.html"
      std::ifstream in(PAGE);
      if(in.is_open()){
        in.seekg(0,std::ios::end);//获取文件末尾指针
        size_t size=in.tellg();
        in.seekg(0,std::ios::beg);//定位到文件开头
        char*file=new char[size];
        in.read(file,size);
        in.close();
  //      std::cout<<file<<std::endl;
        std::string statusLine="http/1.1 200 OK\n";
        //响应报头
        std::string respon="Content-Length: "+std::to_string(size);
        respon+="\n";
        std::string blank="\n";//空行
        send(sock,statusLine.c_str(),statusLine.size(),0);
        send(sock,respon.c_str(),respon.size(),0);
        send(sock,blank.c_str(),blank.size(),0);


        //发送正文
        send(sock,file,size,0);
        delete[]file;
      }
      exit(0);
    }
    close(sock);
    waitpid(-1,nullptr,0);
  }
  return 0;
}

首先是GET方法
在这里插入图片描述
由上图可知GET方法通过URL项服务器传参。密码和账号都暴露出来了不太好
在这里插入图片描述

其次是POST方法
在这里插入图片描述

在这里插入图片描述
由上图可知POST通过正文传参,没有直接暴露到URL上,相对比较隐秘一些(并不安全)。

当在http请求时,每次请求之间没有任何关系(无状态)

http响应状态码

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

常见的状态码为:
200(OK) ,404(Not Found) ,403(Forbidden) ,302(重定向) ,504(Bad Gateway)等等

其中重定向分为临时重定向(307/http1.1 - 302/http1.0)和永久重定向(301)
本质区别:
影响客户端标签,决定客户端是否需要更新目标地址。

http 常用 Header

location:搭配3XX状态码实现重定向
重定向的实现还需要搭配响应报头location:字段

std::string statusLine="http/1.1 307 Temporary Redirect\n";
//响应报头
std::string respon="Content-Length: "+std::to_string(size);
respon+="\n";
respon+="location: https://www.baidu.com/\n";
std::string blank="\n";//空行
send(sock,statusLine.c_str(),statusLine.size(),0);
send(sock,respon.c_str(),respon.size(),0);
send(sock,blank.c_str(),blank.size(),0);

在这里插入图片描述

  • Content-Type: 资源类型(html、text等)
  • Content-Length:正文长度
  • Host:所请求的资源在那个主机那个端口上(代理服务器常用)
  • User-Agent:用户的操作系统以及浏览器版本信息
  • referer:当前页面是从那个页面跳转的,方便回退

Cookie:用于在客户端储存少量信息,实现会话(session)的功能
在这里插入图片描述
在登录网站时,如果曾经使用过账号密码,第二次登录网站时不需要再次输入账号密码进行身份认证了。

在这里插入图片描述
注意:Cookie文件分为内存级和文件级

如果重启客户端还需要输入用户信息的属于内存级,反之就为文件级

  • Connection:长链接keep-alive
    在这里插入图片描述
    在这里插入图片描述

2.https协议

在这里插入图片描述
同理对端再收到报文时要先经过SSL或TLS进行解密,再传到应用层

其中加密分为对称加密(异或加密)(密钥负责加密解密)与非对称加密(RSA)(公钥加密,私钥解密)

其中非对称加密 私钥是不对外公开的,公钥可以公开。
在这里插入图片描述

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NUC_Dodamce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值