Linux网络:应用层协议http/https

认识URL

URL是我们平时说的网址

eg:http常见的URL

http://user:pass@www.example.jp:80/dir/index.htm?uid=1#ch1![](https://i-blog.csdnimg.cn/direct/5bedfa1927534b098ef1a7a79e547a06.png)

注意:

  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的形式

1.http协议

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

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

http协议 请求格式

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

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

#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方法:

通过正文提交数据给服务器,不通过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响应状态码

常见的状态码为:

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 分钟前
计算机专业知识【深入理解子网中的特殊地址:为何 192.168.0.1 和 192.168.0.255 不能随意分配】
网络·智能路由器
s_fox_12 分钟前
Nginx Embedded Variables 嵌入式变量解析(4)
java·网络·nginx
ChinaRainbowSea42 分钟前
1. Linux下 MySQL 的详细安装与使用
linux·数据库·sql·mysql·adb
etcix1 小时前
实现一个简单的拉取网络todo app
网络
网络安全(华哥)1 小时前
网络安全服务实施流程管理 网络安全服务体系
运维·服务器·网络
致奋斗的我们1 小时前
Nginx反向代理及负载均衡
linux·运维·mysql·nginx·负载均衡·shell·openeluer
百锦再1 小时前
在Linux上创建一个Docker容器并在其中执行Python脚本
linux·python·docker
忧虑的乌龟蛋2 小时前
嵌入式 Linux:使用设备树驱动GPIO全流程
linux·服务器·嵌入式·imx6ull·gpio·点灯·pinctrl
查理养殖场2 小时前
计算机网络之TCP的可靠传输
网络·tcp/ip·计算机网络
朝九晚五ฺ2 小时前
【Linux探索学习】第三十弹——线程互斥与同步(上):深入理解线程保证安全的机制
linux·运维·学习