Linux--网络2(应用层)

Posted 水澹澹兮生烟.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux--网络2(应用层)相关的知识,希望对你有一定的参考价值。

目录

1.HTTP概述

2.HTTP协议的URL解释

3.HTTP协议的数据流

4.HTTP协议的格式

4.1HTTP请求格式

4.2HTTP响应格式

5.HTTP协议的版本

6.HTTP协议的请求方法

6.1GET方法与POST方法

6.2其他的请求方法

7.HTTP协议的响应状态码

7.1状态码类别 

8.请求/相应的常见字段

9.代码模拟实现HTTP协议与浏览器的交互

10.子定制协议

10.1TCP粘包的现象

10.2解决TCP粘包的现象

10.3序列化和反序列化


在学习HTTP协议时,我们需要掌握的内容有九个点。

1.HTTP概述

  1. HTTP协议,HyperText Transfer Protocol,超文本传输协议。
  2. HTTP协议是无连接,无状态工作在应用层的协议。

在这里解释一下HTTP协议的两个特性,无连接,无状态。

  • 无连接指的是HTTP协议本身在发送HTTP数据的时候并不需要与服务端建立连接,这是从HTTP协议本身所说的。但是HTTP协议作为应用层协议,它在传输层使用的是TCP协议,TCP在传输协议的过程中是要建立连接的。
  • 无状态是指HTTP协议本身是对请求和响应之间的通信状态不进行保存。现在双方的状态是服务端在实现的机制,这个机制我们称之为会话机制。也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。

2.HTTP协议的URL解释

  • a. 协议方案名:总共分为两个http与https。两个都是超文本传输协议,只不过https在http上增加了ssl加密过程,ssl是一个非对称加密,会对http双方发送的数据进行加密。
  • b.登录信息:早期时显示的我们的身份与认证,现在并没有,因为是不安全的行为。
  • c.域名:他最终会被DNS协议解析成为IP地址
  • d.服务端的端口号:指定服务器连接的网络端口号。若用户省略则自动使用默认端口号。
  • e.带层次的文件路径:这是向服务端后台请求的资源,而他之前的'/'指的是服务器当中的逻辑根目录,而不是Linux服务器的根目录。服务端可以指定一个路径为http服务端的根目录的其实路径。
  • f.查询字符串:他是提交给服务端的数据。在这里要注意,1.他的格式为key=value,如果有多个,则格式为key=value&key1=value1。2.再提交上去的的内容有通俗意义的字符串要进行转码,将字符采用16进制进行表示。使用%这个字符+urlencode之后的字符来表示,其中%是告诉我们服务端后面的内容是经过urlencode的字符,需要服务端进行解码。
  • g.片段标识符:现在已经不太常用,使用它通常可以标记出已经湖区资源的子资源(文档内的某个位置)。

拓展:

非对称加密分为了公钥与私钥,服务端持有私钥,http客户端持有公钥。在HTTP客户端使用公钥进行加密,加密完后传输到服务端,服务端用私钥进行解密就可以得到原生的内容,而在网路传输过程当中,如果有人进行网络数据的抓取由于他没有私钥,他拿到的数据是解析不了的,也就是说即使拿到了数据包也是一堆乱码,这就完成了对传输数据的保密过程。


3.HTTP协议的数据流

 左边我们可以理解为是浏览器,右边可以理解为HTTP的服务端。浏览器在这里会先产生一个HTTP数据,HTTP数据就按照HTTP协议格式将它进行封装并且交给传输层;传输层得到后在这里打上TCP首部然后递交给网络层;网络成在这里打上IP协议的包头后递交给数据链路层;数据链路层打上以太网头部和以太网尾部传递给物理层;物理层将这个二进制处理成过电信号在网络当中进行传输,传输到对端,对端拿到数据之后再将其转化成二进制和格式,然后层层去掉原生数据的封装,最后拿到的数据还是按照HTTP协议组织得到的数据。在这里数据流还是牵扯到了两点,封装与分用。


4.HTTP协议的格式

HTTP协议规定,请求从客户端发出,最后服务端响应该请求并返回。话句话说肯定是先从客户端开始建立通信的,服务器端在没有接受到请求之前是不会发送相应。

4.1HTTP请求格式

HTTP的请求格式分为了四个部分:请求首行(方法URI协议版本),请求体(key:value的属性行),空行,请求正文 。

我们先给出框架,如下图:

4.2HTTP响应格式

HTTP响应格式有四部分,分别是响应首行(协议首行,状态码,状态码解释),响应体,空行和响应内容。


5.HTTP协议的版本

  1. HTTP/0.9:HTTP 于 1990 年问世。那时的 HTTP 并没有作为正式的标准被建⽴。 现在的 HTTP其实含有 HTTP1.0 之前版本的意思,因此被称为 HTTP/0.9。
  2. HTTP/1.0:HTTP 正式作为标准被公布是在1996 年的 5 ⽉,版本被命名为 HTTP/1.0,并记载于 RFC1945。虽说是初期标准,但该协议标准⾄今仍被⼴泛使⽤在服务器端。
  3. HTTP/1.1:这是目前主流的HTTP协议版本。
  4. HTTP/2.0:0 新 ⼀代HTTP/2.0 正在制订中,但要达到较⾼的使⽤覆盖率,仍需假以时⽇。

6.HTTP协议的请求方法

请求方法当中比较常见的有Get与Post。

6.1GET方法与POST方法

  • Get:向服务端索要某些资源,也可以给服务端提供少量的数据在URL当中(少量的原因是URL的长度是有限制的,所以不能无限制给服务端提交数据在"查询字符串当中",且URL在不同浏览器当中是不同的)。
  • Post:给服务器传输资源的方法,提交的数据实在请求正文当中传输给服务端。
  • POST与GET对比:POST方法比GET方法更加私密。不能说POST方法比GET方法更加安全,因为无论GET方法是在URL当中提交数据,还是POST方法在请求正文当中提交数据,都是明文传输。

6.2其他的请求方法

  • PUT:它用来传输文件。HTTP没有校验,一般情况下,后台的服务端是不支持PUT方法的。
  • HEAD:获取响应头部,只获取响应首行和请求体,为了测试请求资源是否有效。
  • DELETE:删除文件。HTTP没有校验,一般情况下,后台的服务端是不支持DELETE方法的。
  • OPTIONS:询问服务端支持的方法。

常见的请求方法的说明,如下表:

方法说明支持HTTP协议版本

GET

获取资源1.0,1.1
POST传输实体主体1.0,1.1
PUT传输文件1.0,1.1
HEAD获得报文首部1.0,1.1
OPTIONS询问支持的方法1.1
TRACE追踪路径1.1
DELETE删除文件1.0,1.1
CONNECT要求用隧道协议连接代理1.1
LINK建立和资源之间的联系1.0
UNLINE断开连接关系1.0

7.HTTP协议的响应状态码

7.1状态码类别 

类别原因短语
1XXInformational(信息性状态码)接受的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误代码)服务器无法处理请求,访问资源不正确或者访问页面不存在
5XXSever Error(服务器错误状态码)服务器处理请求出错

 7.2具体的响应状态码

  • 200:OK,表示从客户端发来的请求在服务端被正常处理了。
  • 302:Found,临时重定向行为,在服务器当中,资源的URI已经临时重定向d奥其他位置。
  • 404:Not Found,服务器桑没有请求资源,访问的页面不存在。
  • 502:Bad Getway,坏的网关

8.请求/相应的常见字段

  • Content-Type:正文的类型(text/html:返回原生的html页面; application/json:json数据类型)
  • Content-Length:正文的长度
  • Host:保存服务端的IP和端口信息
  • User-Agent:保存的是操作系统和浏览器版本的信息
  • Location:保存重定向的网页地址
  • Connection:keep-alive,保持长连接(HTTP底层使用到的TCP保持长连接)
  • Cookie:他是服务端返回给浏览器的,由浏览器进行保存Cookie;在访问服务器其他界面的时候,由浏览器自动在请求体当中加上Cookie。(它的作用:服务端通过Cookie当中的value值,可以得到服务端生成的sessionid,通过会话id,可以在服务端查询出来是哪一个用户的session;浏览器通过请求当中的Cookie信息提交到服务端,服务端就可以通过Cookie保存的会话信息,进行会话校验)。

9.代码模拟实现HTTP协议与浏览器的交互

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

using namespace std;

int main()
    int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(listen_sock < 0)
        perror("socket");
        return 0;
    

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(28989);
    //0.0.0.0 : 本地所有的网卡地址
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");

    int ret = bind(listen_sock, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0)
        perror("bind");
        return 0;
    

    ret = listen(listen_sock, 1);
    if(ret < 0)
        perror("listen");
        return 0;
    
    struct sockaddr_in cli_addr;
    socklen_t cli_addrlen = sizeof(cli_addr);
    int newsockfd = accept(listen_sock, (struct sockaddr*)&cli_addr, &cli_addrlen);
    if(newsockfd < 0)
        perror("accept");
        return 0;
    
    printf("accept new connect from client %s:%d\\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));

    while(1)
        //接收
        char buf[1024] = 0;
        ssize_t recv_size = recv(newsockfd, buf, sizeof(buf) - 1, 0);
        if(recv_size < 0)
            perror("recv");
            continue;
        
        else if(recv_size == 0)
            printf("peer close connect\\n");
            close(newsockfd);
            return 0;
        

        printf("%s\\n", buf);
        memset(buf, '\\0', sizeof(buf));

        string body = "<html><h1>hello</h1></html>";
        stringstream ss;
        ss << "HTTP/1.1 302 Found\\r\\n";
        //ss << "Content-Type: text/html\\r\\n";//相应首行
        //ss << "Content-Length: " << body.size() << "\\r\\n";//响应体
        ss << "Location: https://www.baidu.com/\\r\\n";
        ss << "\\r\\n";
        send(newsockfd, ss.str().c_str(), ss.str().size(), 0);
        send(newsockfd, body.c_str(), body.size(), 0);
    

    close(listen_sock);
    return 0;

10.自定制协议

10.1TCP粘包的现象

我们在了解自定制协议之前先举个例子:

 现在客户端使用send接口给服务端发送了一串数据给服务端12+12,此时客户端有发送一条数据24+24,两条数据依次被丢入网络当中,因为TCP是面向字节流的,此时两条数据到达服务端的传输层的TCP协议,而此时两条数据之间没有任何的分隔符。当应用层调用recv接口将数据拿到,但是服务端没有办法分析是12+12,24+24还是12+1224+24,此时服务端没有办法进行拆分,我们将这种现象称之为TCP粘包问题。

即就是TCP服务端没有办法针对TCP数据进行拆分,拆分成为不同的请求。因为TCP是面向字节流的,数据之间并没有明显的间隔,就导致服务端无法拆分数据。

10.2解决TCP粘包的现象

那么就在应用层自定制我们的协议,用来解决TCP粘包问题。

解决方案:

  1. 定义应用层自己的协议数据结构,来描述发送到数据
  2. 每一条数据都会友谊和分隔符(\\r\\n),来间隔前后两条数据。

10.3序列化和反序列化

序列化:将对象转换成二进制数据

反序列化:将二进制数据转化成对象

举个栗子:假设在这里有一个结构体

struct a
    string name;
    string passwd;
;

我们知道这个结构体当中的两个string对象有可能在我们进程虚拟地址空间中并非连续存储,而如果不转化则会发送一些无效的数据,因此将当前的结构体中的对象转化成连续的二进制数据,这样就不会传输无效的数据,这种方式称之为序列化。而反序列化就与其相反。

josn也是一个好的使用方式。json是一种key/value的数据结构,可以支持嵌套定义,也可以支持多种基础类型(int,string,char)。同时也支持将josn对象序列化成二进制序列,也可以将二进制反序列化成josn对象。

以上是关于Linux--网络2(应用层)的主要内容,如果未能解决你的问题,请参考以下文章

[linux] Linux网络编程之HTTP协议详解

Java-----网络编程

Java-----网络编程

谢烟客---------Linux之网络基础知识

计网网络层首部

计网网络层首部