| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> UDPTCP和HTTP协议学习总结 -> 正文阅读 |
|
[网络协议]UDPTCP和HTTP协议学习总结 |
UDP协议TCP面向连接,UDP无连接,在两端互通之前,面向连接的协议会先建立连接。 建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。 TCP提供可靠交付,通过TCP连接传输的数据,无差错、不丢失、不重复、并且按序到达。而UDP继承IP包的特性,不保证不丢失,不保证能够按顺序到达。 TCP是面向字节流的,发送的时候发的是一个流,没头没尾。UDP继承了IP的特性,基于数据报的,一个一个地发,一个一个地收。TCP具有拥塞控制,UDP则是不考虑网络拥塞情况,一直在发。同时TCP具有一个状态服务。 UDP包头UDP包头结构如下图所示: 无论是TCP传输还是UDP传输,都需要监听一个端口,通过这个端口来区分不同的应用程序。 UDP的特点和使用场景UDP具有以下三个特点:
因此,基于上述几个UDP的特点,UDP适合在以下场景中使用:
因此,基于上述几个UDP的主要应用场景,UDP最常用的几个例子如下所示:
TCP协议TCP包头格式TCP包头格式如下图: 主要的几个如下所示: 开头是源端口和目标端口 之后是包的序号,通过序号解决发送数据包的乱序问题 之后是确认序号,发出的包在对方接收到之后,会发送确认序号 之后是状态位,SYN是发起一个连接,ACK是回复,RST是重新连接,FIN是结束连接 然后是窗口大小,TCP要做流量控制,通信双方各声明一个窗口,标识自己当前的数据接收和处理能力 TCP三次握手TCP的三次握手过程如下图: TCP在建立连接前,会经历三次握手,即请求-应答-应答的应答三次过程。具体的过程是,
TCP四次挥手TCP四次挥手过程图: TCP在断开连接时,会经历四次挥手阶段,以客户端主动断开连接为例,四次挥手过程如下所示:
TCP状态机TCP状态机就是将连接建立和连接断开这两个时序状态图综合起来,可以参考上面两个三次握手和四次挥手的图 SocketSocket可以理解为插口或者插槽,客户端和服务端在进行通信之前,双方需要建立一个SOcket,Socket编程进行的是端到端的通信,一般不知道中间经过多少局域网,多少路由器,因此能够设置的参数,都是端到端协议之上网络层和传输层的。 Socket函数指定是IPv4还是IPv6,分别对应设置为AF_INET和AF_INET6。指定是TCP还是UDP,TCP协议是基于数据流的,设置为SOCK_STREAM,而UDP是基于数据报的,设置为SOCK_DGRAM。 基于TCP协议的Socket程序函数调用过程
具体过程如下图所示: TCP的Socket就是一个文件流,因为Socket在Linux中就是以文件的形式存在的。除此之外,其还存在文件描述符,写入和读出,也是通过文件描述符。Socket是一个文件,对应有文件描述符。每一个进程都有一个数据结构task_struct,里面指向一个文件描述符数组,来列出这个进程打开的所有文件的文件描述符。文件描述符是一个整数,是这个数组的下标。数组中的内容是一个指针,指向内核中所有打开的文件列表。文件还都有inode,但Socket对应的inode不像真正的文件系统一样保存在硬盘上,而是保存在内存中。在这个inode中,指向了Socket在内核中的Socket结构。在这个结构中,主要有两个队列,一个是发送队列,一个是接收队列,在这两个队列里保存的是一个缓存sk_buff。数据结构图如下图所示: 基于UDP协议的Socket程序函数调用过程UDP是无连接的,因此UDP不需要三次握手,即不需要调用listen和connect,但UDP的的交互仍然需要IP和端口号,因而也需要bind。UDP没有维护连接状态,不需要每对连接建立一组Socket,而是只要有一个Socket,就能够和多个客户端通信。也正是因为没有连接状态,每次通信的时候,都调用sendto和recvfrom,都可以传入IP地址和端口。 UDP函数调用过程如下图所示: 服务器如何连接更多的项目系统会用一个四元组来标识一个TCP连接,即 {本机IP, 本机端口, 对端IP, 对端端口} 服务端TCP连接四元组中只有对端IP, 即客户端的IP和对端的端口,也即客户端的端口是可变的,因此最大TCP连接数=客户端IP数×客户端端口数。对IPv4,客户端的IP数最多为2的32次方,客户端的端口数最多为2的16次方,也即服务端单机最大TCP连接数,约为2的48次方。 但服务端最大并发TCP连接数远不能达到理论上限。首先主要是文件描述符限制,Socket都是文件,首先要通过ulimit配置文件描述符的数目;另一个限制是内存,按socket的数据结构,每个TCP连接都要占用一定内存,但操作系统是有限的。因此,在资源有限的情况下,想要接入更多的项目,即需要降低每个项目消耗的资源数目,可以通过以下几种方式: 多进程方式监听进程相当于一个代理,在那里监听来的请求。一旦建立了一个连接,就会有一个已连接Socket,此时创建一个子进程,然后将基于已连接Socket的交互交给这个新的子进程来做。 此时进程移交的过程即进程复制,在Linux下,创建子进程使用fork函数。其在父进程的基础上完全拷贝一个子进程。在Linux内核中,会复制文件描述符的列表,也会复制内存空间,还会复制一条记录当前执行到了哪一行程序的进程。复制的时候在调用fork,在复制完毕之后,父进程和子进程都会记录当前刚刚执行完fork。在两个进程刚复制完时,两者几乎一模一样,只是根据fork的返回值来区分到底是父进程,还是子进程。如果返回值是0,则是子进程;如果返回值是其他的整数,就是父进程。 进程复制过程如下图所示: 子进程复制了文件描述符列表,而文件描述符都是指向整个内核统一的打开文件列表,因而父进程刚才因为accept创建的已连接Socket也是一个文件描述符,同样也会被子进程获得。子进程就可以通过这个已连接Socket和客户端进行互通了,在通信完成之后退出后,父进程可以通过子进程ID来查看是否完成,是否退出。 多线程方式多进程方式太消耗资源,在Linux下,通过pthread_create创建一个线程,调用do_fork。新的线程在task列表会新创建一项,但文件描述符列表、进程空间,还是共享的,只不过多了一个引用。新的线程也可通过已连接Socket处理请求,从而达到并发处理的目的。多线程方式如下图所示: IO多路复用无论进程还是线程,太多了以后都很难维护,可以采用IO多路复用,观测所有Socket,将其都放在一个文件描述符集合fd_set中即项目进度墙,然后调用select函数来监听文件描述符集合是否有变化。一旦有变化,依次查看每个文件描述符。发生变化的文件描述符在fd_set对应位都设为1,表示Socket可读或者可写,从而进行读写操作。 IO多路复用epoll模式上面那个方式需要主动去循环检测,进行轮询,一样消耗资源。可以使用epoll,当项目进度发生变化的时候,主动通知项目组,然后项目组再根据项目进展情况做相应的操作。其在内核中的实现不是通过轮询的方式,而是通过注册callback函数的方式,当某个文件描述符发送变化的时候,就会主动通知。 HTTP协议一般网址域名,称之为URL,即统一资源定位符。当将网址输入到浏览器后,浏览器会将域名发送给DNS服务器,让其解析为IP地址。建立了TCP连接之后,就可使用HTTP协议,因为HTTP协议是基于TCP协议的。目前使用的HTTP协议大部分是1.1,默认开启Keep-Alive,此时建立的TCP连接即可在多次请求中复用。 HTTP请求的构建HTTP请求格式: HTTP的报文分为三大部分即请求行、首部和正文实体。 请求行访问类型主要分为GET,POST,PUT,DELETE GET就是去服务器获取一些资源。对于访问网页来讲,要获取的资源往往是一个页面。比如返回一个JSON字符串,到底要返回什么,是由服务器端的实现决定的。 POST需要主动告诉服务端一些信息,而非获取。一般会将告知内容放在正文里面,正文可以有各种各样的格式,常见的格式也是JSON。 PUT就是向指定资源位置上传最新内容。但HTTP的服务器往往是不允许上传文件的,PUT和POST主要是用于要传给服务器东西的方法。 POST往往是用来创建一个资源的,而PUT往往是用来修改一个资源的。 DELETE就是用来删除资源的。 首部字段首部是key value,通过冒号分隔,首部保存的字段都较为重要,比如Accept-Charset,表示客户端可以接受的字符集,Content-Type表示正文的格式,需要正文传输JSON格式时即需要将这个值设置为JSON。 对于高并发场景下的系统,在真正的业务逻辑之前,需要有一个接入层,将这些静态资源的请求拦在最外面,架构图如下图所示: 对于静态资源,有Vanish缓存层。当缓存过期的时候,才会访问真正的Tomcat应用集群。对于动态资源有Redis。 HTTP头里的Cache-control是用来控制缓存。当客户端发送的请求中包含max-age指令时,如果判定缓存层中资源的缓存时间数值比指定时间的数值小,则客户端可以接受缓存的资源;当指定max-age值为0,则缓存层通常需要将请求转发给应用集群。If-Modified-Since也关于缓存,如果服务器的资源在某个时间之后更新了,则客户端应该下载最新资源;如果没有更新,服务端会返回“304 Not Modified”的响应,客户端就不用下载了。 HTTP请求的发送HTTP协议基于TCP协议,使用面向连接的方式发送请求,通过stream二进制流的方式传给对方。到TCP层之后,会将二进制流变成一个报文段发送给服务器。 TCP经过三次握手建立连接之后,TCP层没次发送一个报文后,加上自己的源地址和目的地址交付给IP层进行传输。IP层查验地址后,经过ARP协议解析源和目的的MAC地址,经过网关路由器的交付到达目的地。目的端再经过IP和TCP的解析,HTTP服务器监听TCP头中的端口号,之后处理网页或其他请求。 HTTP返回的构建HTTP的返回报文格式如下图所示: 状态码能反映HTTP请求结果,200表示成功,404表示服务端无法请求这个请求。之后返回首部的key-value,Retry-After表示,客户端应该在多长时间以后再次尝试。Content-Type,表示返回的是HTML,还是JSON。 HTTP返回报文构造完成之后,会交给Socket和TCP层去发送,TCP层将返回的HTML,分程很多小段,确保每个段都能可靠到达。再经过IP和MAC等处理,浏览器拿到HTTP报文发现返回200后,一个正常的HTML网页即能显示。 HTTP 2.0HTTP 1.1在应用层以纯文本的形式进行通信。每次通信都要带完整的HTTP的头,而且不考虑pipeline模式时,每次都需要上述过程提到的那样一去一回。实时性、并发性都存在问题。 HTTP 2.0会对HTTP头进行一定压缩,将原来每次都要携带的大量key value在两端建立一个索引表,对相同的头只发送索引表中的索引。HTTP 2.0协议将一个TCP连接,切分成多个流,每个流都有自己的ID,流可以是客户端发往服务端,也可以是服务端发往客户端,其实是一个虚拟通道。流是有优先级的。HTTP 2.0还将所有的传输信息分割为更小的消息和帧,并采用二进制格式编码。常见的帧有Header帧,用来传输Header内容,并且会开启一个新的流。Data帧,用来传输正文实体。多个Data帧属于同一个流。 通过上述机制,HTTP 2.0的客户端可以将多个请求分到不同的流中,然后将请求内容拆成帧,进行二进制传输。帧可以打散乱序发送, 根据每个帧首部的流标识符重新组装,并且可以根据优先级,决定优先处理哪个流的数据。HTTP 2.0解决了HTTP 1.1的队首阻塞问题,不需要通过HTTP 1.x的pipeline机制用多条TCP连接来实现并行请求与响应;减少了TCP连接数对服务器性能的影响,同时将页面的多个数据css、js、 jpg等通过一个数据链接进行传输,能够加快页面组件的传输速度。 QUIC协议HTTP 2.0虽然提升了并发性,但其仍然基于TCP协议,TCP协议,处理包时有严格顺序,Google提出的QUIC协议相对来说效果更好。 自定义连接机制 TCP协议断开重连时,需要进行三次握手等,导致一定时延。基于UDP,即可在QUIC的逻辑里维护连接机制,不再以四元组标识,而是以一个64位的随机数作为ID来标识,而且UDP是无连接的,当IP或者端口变化的时候,只要ID不变,就不需要重新建立连接。 自定义重传机制 QUIC有个序列号,是递增的,同时还定义了一个offset。QUIC也是一个数据流,发送的数据在这个数据流里面有个偏移量offset,可以通过offset查看数据发送到了哪里,只要这个offset的包没有来,即重发;如果来了,按照offset拼接拼成一个流。 无阻塞的多路复用 同一条QUIC连接上可以创建多个stream,来发送多个 HTTP 请求。但QUIC基于UDP,一个连接上的多个stream之间没有依赖。 自定义流量控制 QUIC的流量控制也是通过window_update,来告诉对端其可以接受的字节数。QUIC的窗口是适应其多路复用机制的,不但在一个连接上控制窗口,还在一个连接中的每个stream控制窗口。 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 23:24:00- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |