目录

  • 概念
  • 序列化和反序列化
  • 协议
    • 如何制定自定制协议
    • 知名协议----HTTP协议
      • URL的组成
      • HTTP协议请求格式
        • 首行
        • 头部
        • 空行
        • 正文
      • HTTP协议响应格式
        • 首行
        • 头部
        • 空行
        • 正文
    • HTTPS
      • 简单模拟实现HTTP服务器

概念

应用层:是TCP/IP的顶层,通过使用传输层提供的服务,直接向用户提供服务,是TCP/IP网络与用户之间的界面或接口。应用层是直面程序员的一层,因为应用层是程序员自己写的,因此应用层的协议都是程序员自己定的

应用层上的典型应用包括web浏览器、电子邮件、文件传输访问和远程登录等。

序列化和反序列化

序列化:将各个数据对象按照指定的协议组织成为持久化存储/数据传输的二进制数据串
反序列化:将二进制数据串按照指定协议解析得到各种数据对象
常用的序列化方式:json序列化/protobuf/二进制序列化
序列化方式的评价标准:解析数据的性能、传输数据的性能、和可读性

协议

应用层有两个重要的协议:一个是自定制协议,一个是超文本传送协议HTTP
自定义协议:程序员自己根据自己的应用场景的特点,定义协议(数据的格式/数据的描述信息)

如何制定自定制协议

我们以一个简单的网络版计算器来举例,计算机功能为:客户端发送两个数字以及一个运算符给服务端,服务端获取到数据后然后进行运算,将运算结果返回给客户端。
有两种约定方案可以实现:
方案一:1、客户端发送一个型如"1+1"的字符串;2、这个字符串的两个操作数都是整形;3、两个数字之间会有一个字符是运算符,运算符只能是+;4、数字和运算之间没有空格
方案二:采用结构体构造二进制数据串,将三个数据都封装到一个结构体中

struct cal_t
{int num1;int num2;char op;
};

这种方案是非常常用的,将多个对象封装成一个对象,当客户端收到数据时就不用再多此一举得去解析,而是按指定格式去取数据;前4个字节数数据1,前8个字节的后4字节是数据2,最后一个字节就是运算符。用起来非常方便

socket封装的对象中添加结构体信息

typedef struct
{int num1;int num2;char op;
}cal_t;

客户端:

cal_t cal;
cal.num1 = 12;
cal.num2 = 34;
cal.op = '+';
send(fd, (char*)&cal, sizeof(cal_t), 0);

服务端:

cal_t cal;
recv(fd, (char*)&cal, sizeof(cal_t), 0);
printf("%d % c %d\n", cal.num1, cal.op, cal.num2);

这样子就可以实现自定制协议

知名协议----HTTP协议

HTTP是当今互联网应用中使用最广泛的应用层协议,也是应用程序之间远程通信所采用比较多的协议,用来在浏览器和WWW服务器之间传送超文本的协议。基于浏览器的HTMP、XML、JSON、等格式的文本都是通过HTTP进行传输的。它非常便捷,客户向服务端发送请求服务时,只需要发送路径、参数以及请求方法即可。请求方法常用的右GET、POST、UDPATE、DELETE等,它们组成RESTful架构风格的不可缺一的部分

网址:例如我们平时打开的网页都有相对应的网址https://www.baidu.com/。网址是统一资源定位器,简称URL,定位网络中某台主机上的某个资源

URL的组成

协议方案名称://认证用户名:认证密码@服务器IP地址:服务器处理进程端口/请求的资源路径?查询字符串#片段标识符

http://username:password@www.baidu.com:80/index.html?name=WhiteShirtI&age=21#id

协议方案名称(常用):通信协议,通常使用http

认证用户名:认证密码(少用):用户的账号密码

服务器IP地址(常用):我们看到的不一定是IP地址,也可能是一个域名,也就是服务器的别名,通过域名解析服务器就能得到服务器的IP地址

服务器处理进程端口(常用):web服务器默认http服务器端口是80端口,默认不显示

/请求的资源路径(常用):资源在服务器上的路径,这里的/是http的根目录,但是是一个服务器的相对根目录,只是一个子目录。原因是省去前面重要的目录地址信息,防止用户访问

查询字符串:客户端提交给服务端的一些数据,由key=val&key=val形式的键值对组成的;查询的字符串不能出现特殊字符:因为url中特殊字符都是有特殊含义的,一旦提交的数据中有特殊字符,就会造成数据二义,因此若要提交的数据中有特殊字符,则需要进行数据转义;urlencode:url解码,提交的数据中不能出现特殊字符,一旦出现就要进行转义。将特殊字符每一个字节转换为16进制的数字字符,并且使用%前缀作为转义;+ 转义成 %2B ;解释:在ASSIC中+是代表数字43,转换成16进制就是2B

urldecode:url解码,在url中遇到%,则认为其后两个字符需要转义,将第一个字符转换成数字乘以16,加上第二个字符转换的数字。%2B 转义成 + ;解释:2*16+11=43, 将43转换为ASSIC码对应的符号

片段标识符:html中的一个标签id,直接跳转到页面的某个位置

HTTP协议请求格式

HTTP协议请求包含四个内容:首行、请求头部、空行、正文

首行

GET https://blog.csdn.net/qq_44443986?spm=1011.2124.3001.5113 HTTP/1.1 以空格进行间隔包含三个要素,并且最终以\r\n作为结尾
第一要素:请求方式:GET/POST/HEAD/PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH

  • GET-请求指定的页面信息,并返回实体主体,没有请求正文。也可以通过url中查询字符串向服务器提交数据,但是数据不安全 且 url长度有限制(各个服务器应用商的限制)
  • POST-向指定资源提交数据进行处理请求(例如提交表单或者上传文件),且提交的数据在请求正文中,相对GET比较安全 且无长度限制。
  • HEAD-类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头

第二要素:URL:网址信息
第三要素:协议版本:HTTP/1.1/0.9/1.0/2.0

  • HTTP/0.9-这时候的http仅用于传输html数据,并且只有GET请求方法,并且没有协议标准格式
  • HTTP/1.0-正式规定了http协议格式,并且增加了多种请求方法,并且支持了不同文件格式的数据流
  • HTTP/1.1-在1.0的基础上增加了更多请求方法和头部描述信息,并且支持了长连接管线化传输。(http基于在传输层tcp实现通信,短连接指的是建立连接后发送一个请求,得到响应之后就关闭连接;长连接指的是发送请求得到响应后并不会关不连接,当下次再来一次请求是还会使用当前这个连接,但这个连接不是永久存在的,当两端长时间没有交往时会自动断开;管线化传输指的是将多个HTTP请求整批提交的技术,而在传送过程中不需先等待服务端的回应 <响应的顺序必须与请求的顺序保证一致:1请求到2请求,必须等到1响应了2才能响应,存在线头阻塞问题>
  • HTTP/2.0-采用二进制流传输,并且支持多路复用,并且允许服务端主动推送数据 。(服务端主动推送数据是指请求一次,服务端会一次性推送所有数据,而不是一个请求,对应一个响应的数据;<利用多路复用,头部中标识了自己属于哪个流,解决了线头阻塞的问题,同时也提高了网络速度的利用率>)

头部

请求头部用来描述本次请求的关键字段信息,由key:val形式的键值对组成,并且每个键值对以\r\n作为结尾

  • Connection-控制长/短连接
  • Cache-Control-缓存控制
  • User-Agent-客户端的属性
  • Accept-描述自己所能接收的数据属性
  • Content-Length-描述正文长度
  • Content-type-描述正文的数据类型
  • Get请求方式专属信息:Cookie-带有客户端的身份、状态等信息,客户端每次通信从cookie文件读取数据,通过cookie向服务端传递信息,(用于维护客户端状态信息)但是不够安全。Post则是将这些信息保存在正文中(安全)

空行

目的是间隔头部与正文,\r\n。接收http数据的时候,当连续接收两个\r\n的时候,则就认为头部到此结束。

正文

先获取完整头部,通过头部中的Content-Lenght获取正文长度,然后获取指定长度的正文,通过这种方式每次获取完整一条http请求数据
正文就是提交给服务端的数据

HTTP协议响应格式

HTTP协议响应包含四个内容:首行、请求头部、空行、正文

首行

HTTP/1.1 200 OK 以空格进行间隔包含三个要素,并且最终以\r\n作为结尾
第一要素:版本协议
第二要素:响应状态码
响应状态码是一个数字,这个数字表示本次的请求后服务端所做出响应的结果,这个结果分为五大类型:

  • 1xx:描述信息-服务器收到请求,需要请求者继续执行操作
  • 2xx:请求成功-操作被成功接收并处理;典型的有200-请求成功。一般用于GET与POST请求
  • 3xx:重定向-要求客户端重新请求新的位置;典型的有301-永久移动、302-临时移动
  • 4xx:客户端错误-请求包含语法错误或无法完成请求;典型的有400-请求错误;404-请求的资源不存在
  • 5xx:服务端错误-服务器在处理请求的过程中发生了错误;典型的有500-服务器内部错误,无法完成请求;502-服务器作为网关或代理尝试执行请求时,从远程服务器接收到了一个无效的响应;504-服务器作为网关或代理,但是没有及时从远程服务器收到请求,响应超时

第三要素:描述状态码
对状态码的描述信息,可以是官方文档对应的描述信息,也可以自定义描述信息

HTTP状态码大全

头部

响应头部用来描述本次响应的关键字段信息,由key:val形式的键值对组成,并且每个键值对以\r\n作为结尾

  • Connection-控制长/短连接
  • Content-type-描述正文的数据类型
  • Server-包含有关用作原始服务器处理请求的软件信息
  • Transfer-Encoding-指定实体正文传输给客户端的方式,例如chunked-分块传输,将一个正文分为多块进行传输
  • Expires-缓存过期时间
  • Cache-Control-缓存控制
  • Set-Cookie-服务端通过set-cookie向客户端传递信息,会被保存在客户端浏览器的cookie文件中

由于cookie的使用不够安全,从而引入了Session,搭配cookie使用
Session-会话:服务端会为每个登录的客户端创建会话session,会话session保存了一些会话信息(客户端身份、状态信息等),并且session保存在服务端。可以通过cookie将session id返回给客户端,客户端每次通信都会通过cookie带有自己的session id,服务端就通过session id知道这是哪一个客户端了
图解:

cookie和session的区别:cookie是保存在客户端上的数据(用户信息),用于持续与服务端进行信息传递的一种手段;session是一种会话的控制,服务端保存的会话信息包含客户端的身份状态信息,通过cookie/set-cookie传递session_id进行客户端的身份状态识别

空行

目的是间隔头部与正文,\r\n。接收http数据的时候,当连续接收两个\r\n的时候,则就认为头部到此结束。

正文

正文就是提交给服务端的数据

HTTPS

HTTPS协议并不是一个新的协议,而是在HTTP协议基础上进行了一层加密。https协议是基于ssl进行加密实现的加密传输协议

安全传输需要考虑的问题:
1、身份验证问题:防止伪装
2、数据加密问题:防止监听

CA证书:通信双方在通信前先到权威机构请求给自己颁发一个CA证书

通信两方建立连接后,在通信之前先将证书发送给对方,收到对方的证书后,查看证书的权威机构是否是自己所信任的权威机构,如果是则到权威机构进行身份验证,通过后才进行通信

对称加密:服务器和浏览器使用的密钥都是同一个密钥
非对称加密:一个为公钥,一个为私钥,公钥和私钥之间不能相互推导,公钥加密需要私钥解密,私钥加密需要公钥解密
混合加密:通信时先使用非对称加密保护对称密钥协商的过程,直到对称密钥协商完后再使用对称加密进行传输

简单模拟实现HTTP服务器

实现流程

  1. 从键盘接收IP地址和PORT
  2. 创建套接字,为套接字绑定地址信息,服务端开始监听请求
  3. 开始接收客户端请求
  4. 用一个字符串req接收浏览器的请求信息
  5. 按照http响应信息格式定义首行first、头部header、空白行blank、正文body
  6. 将响应信息发送给用户
  7. 关闭套接字
//http_srv.cpp
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
using namespace std;int main(int argc, char* argv[])
{if (argc != 3){cout << "请按格式输出 ./http_srv ip port" << endl;return -1;}//ip地址string ip = argv[1];//端口号uint16_t port = stoi(argv[2]);//创建套接字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(ip.c_str());addr.sin_port = htons(port);socklen_t srv_len = sizeof(addr);int ret = bind(fd, (struct sockaddr*)&addr, srv_len);if (ret < 0){perror("bind");return -1;}//服务端开始监听ret = listen(fd, 5);if (ret < 0){perror("listen");return -1;}while (1){//接收客户端请求struct sockaddr_in cli_addr;socklen_t cli_len;int cli_fd = accept(fd, (struct sockaddr*)&cli_addr, &cli_len);if (cli_fd < 0){perror("accept");continue;}//用于接收http响应信息string req;char tmp[4096] = {0};ret = recv(cli_fd, tmp, 4096, 0);if (ret <= 0){perror("recv");continue;}req.assign(tmp, ret);cout << "req[" << req << "]" << endl;//定义http响应信息,反馈给用户//首行string first = "HTTP/1.1 200 ok\r\n";//空白行string blank = "\r\n";//正文string body = "<html><body><h1>Hello WhiteShirtI<h1></body></html>";//头部信息stringstream header;header << "Content-Length:" << body.size() << "\r\n";header << "Connection:close\r\n";//响应信息发送给用户send(cli_fd, first.c_str(), first.size(), 0);send(cli_fd, header.str().c_str(), header.str().size(), 0);send(cli_fd, blank.c_str(), blank.size(), 0);send(cli_fd, body.c_str(), body.size(), 0);close(cli_fd);}close(fd);
}

运行结果:
先开启服务端,等待请求

打开网页,输入http://192.168.73.130:8888 (如果是虚拟机必须关闭虚拟机的防火墙systemctl disable firewalld)

服务端收到请求信息

网络 应用层 | HTTP的认识及实现(模拟实现一个简单的服务器)相关推荐

  1. JAVA同时输入用户名和密码_用java模拟设计一个简单的“用户注册”程序。当用户输入用户名和密码时,单击“注...

    用java模拟设计一个简单的"用户注册"程序.当用户输入用户名和密码时,单击"注 2020 - 9 - 26 TAG : 所有功能均已实现,如有不满意的地方我再修改imp ...

  2. 编程题目:使用C++语言模拟完成一个简单的计算机系统

    编程题目:使用C++语言模拟完成一个简单的计算机系统(举一个管理人员的例子,其他的例子与下述方法一致即可) #include<iostream.h> #include<math.h& ...

  3. c语言网络定向拉取数据,用C模拟了一个http请求,但是recv函数接收的数据不完整且欠安顺序获取信息...

    用C模拟了一个http请求,但是recv函数接收的数据不完整且不安顺序获取信息 用C模拟了一个http请求,但是recv函数接收的数据不完整且不安顺序获取信息 我把代码贴上 #include #inc ...

  4. node --- 模拟express实现一个简单的服务器

    目标 使用express实现一个监听3000端口的http服务如下 const express = require('express'); const app = express();app.get( ...

  5. 【网络编程知识】使用Socket通信,做一个简单的多人聊天室

  6. java模拟而一个电话本操作

    哈哈,大家平时都在使用电话本,下面使用java来模拟而一个简单的电话本吧... 首先给出联系人的抽象类 package net.itaem.po;/*** * 电话人的信息* */ public cl ...

  7. java制作电话本,java模拟而一个电话本操作

    哈哈.大家平时都在使用电话本.以下使用java来模拟而一个简单的电话本吧... 首先给出联系人的抽象类 package net.itaem.po; /** * * 电话人的信息 * */ public ...

  8. omnet++,veins,sumo使用多应用层实现车辆和行人的模拟

    1.完成网络的搭建: 搭建一个简单的十字路口场景: 1)定义结点:新建intersection.node.xml,内容如下: NOTE1:结点属性type="traffic_light&qu ...

  9. 大连理工18秋计算机应用基础,大连理工大学网络教育本科计算机应用基础入学考试模拟题...

    大连理工大学网络教育本科计算机应用基础入学考试模拟题 一.单选题 1. 世界上第一台电子数字计算机采用的电子器件是______. A.大规模集成电路 B.集成电路 C.晶体管 D.电子管 2. 将计算 ...

最新文章

  1. React应用里Invalid hook call错误消息的处理
  2. 正则表达式强化,爬虫练习
  3. 数据探查_数据科学家,开始使用探查器
  4. Shell脚本基础语法
  5. MP3 Encoder for mac(MP3编码器)修复版
  6. 腾讯区块链+医疗,一场值得期待的卫生行业创新探索
  7. typedef用法和结构体指针用法
  8. win10计算器rsh_Win10计算器快捷键
  9. 物联网、大数据、云计算、人工智能之间的关系
  10. Linux下的SD卡分区--解决sd卡分区损坏
  11. 四、快速搭建一套现代化的个人独立博客系统,给爱写博客的你(part2 正文)
  12. 制作的动图太大怎么办?如何快速将gif图片缩小?
  13. JAVA计算:用 100 元钱买 100 支笔,其中钢笔 3 元 / 支,圆珠笔 2 元 / 支,铅笔 0.5 元 / 支,问钢笔、圆珠笔和铅笔可以各买多少支 ?
  14. 电信宽带100M,平时只有30一40M而且常常掉线这是怎么回事?
  15. MT40A1G16KH-062E AIT内存MT40A1G16KH-062E AUT
  16. 创新商用沟通协作方式,科天云发布协作云开放平台
  17. ios怎么引入masonry_iOS Masonry详解
  18. 如何保持规律的生活习惯?
  19. 如何debug Vue源码
  20. 装箱问题(Packing Problem)

热门文章

  1. openstack mysql默认密码_OpenStack 安装数据库和rabbitmq消息队列 (三)
  2. java io流屏幕输出_java IO流 之 输出流 OutputString()的使用
  3. 实现粗糙表面_你了解什么是表面粗糙度吗?
  4. 怎么把页面内容填满一页_【2020手帐体系】超详细的设置思路和内容介绍~
  5. java io .log_namenode无法启动:java.io.FileNotFoundException: .log (Permission denied)
  6. Volley源码学习1--volley结构图
  7. androidStudio快捷键概览
  8. Spring Boot+Mysql实现的电影在线资讯系统
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的在线论坛管理系统
  10. jsp点击文字改变颜色_这样给图片添加上文字、诗词、歌词,超吸睛