IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: 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包头结构如下图所示:

img

无论是TCP传输还是UDP传输,都需要监听一个端口,通过这个端口来区分不同的应用程序。

UDP的特点和使用场景

UDP具有以下三个特点:

  • 沟通简单,即相信网络通络默认就是很容易送达,不容易被丢弃的。

  • 不会建立连接,虽然有端口号,但只要监听,谁都可以向其传输或其向别人传输

  • 不会根据网络的状态进行发包的拥塞控制,不考虑网络丢包的情况

因此,基于上述几个UDP的特点,UDP适合在以下场景中使用:

  • 需要资源少,在网络情况比较好的内网,或者对于丢包不敏感的应用。在这种情况场景下,出现一些问题也可以忍受

  • 不需要一对一建立连接,可以广播的应用。UDP不面向连接的功能,可以使得其能承载广播或者多播写。DHCP和VXLAN协议就是就是基于UDP协议。

  • 需要处理速度快,时延低,可以容忍少数丢包,即使出现网络拥塞也不至于影响传输的应用。UDP简单,处理速度快,时延较低,且TCP在网络拥塞时会启动拥塞控制,降低发送速度,使得传输变得更卡。当前很多应用都是要求低时延的,不需要采用TCP这种复杂的机制,而是根据自己的场景,实现自己的可靠和连接保证。

因此,基于上述几个UDP的主要应用场景,UDP最常用的几个例子如下所示:

  • 网页或者APP的访问

    传统的访问网页和手机APP都是基于HTTP协议,HTTP协议基于TCP协议,建立连接需要多次交互,时延较大,较为耗时。Google提出的 QUIC(Quick UDP Internet Connections,快速UDP互联网连接)是基于UDP改进的通信协议,其目的是降低网络通信的延迟,提供更好的用户互动体验。QUIC在应用层上,会自己实现快速连接建立、减少重传时延,自适应拥塞控制。

  • 流媒体协议

    对于视频播放来讲,有的包可以丢,有的包不能丢,但如果必须丢包,隔几个帧丢一个对于是哦i你来说影响不大,且当网络不好时,TCP协议会主动降低发送速度,因而很多直播应用都基于UDP实现视频传输。

  • 实时游戏

    游戏对实时性要求较高,而TCP的重传和拥塞控制等严重影响实时性,因此对实时要求较为严格的情况下,采用自定义的可靠UDP协议,自定义重传策略,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成的影响。

  • IOT物联网

    物联网终端资源少,维护TCP协议代价大,且物联网对实时性要求较高,Google推出的物联网通信协议Thread,就是基于UDP协议的。

  • 移动通信领域

    4G网络里,移动流量上网的数据面对的协议GTP-U是基于UDP的。

TCP协议

TCP包头格式

TCP包头格式如下图:

img

主要的几个如下所示:

开头是源端口和目标端口

之后是包的序号,通过序号解决发送数据包的乱序问题

之后是确认序号,发出的包在对方接收到之后,会发送确认序号

之后是状态位SYN是发起一个连接,ACK是回复,RST是重新连接,FIN是结束连接

然后是窗口大小,TCP要做流量控制,通信双方各声明一个窗口,标识自己当前的数据接收和处理能力

TCP三次握手

TCP的三次握手过程如下图:

img

TCP在建立连接前,会经历三次握手,即请求-应答-应答的应答三次过程。具体的过程是,

  • 在刚开始的时候,客户端和服务端都处于CLOSED状态

  • 先是服务端主动监听某个端口,处于LISTEN状态

  • 然后客户端主动发起连接SYN,之后客户端处于SYN-SENT状态

  • 服务端收到发起的连接,返回SYN,并且发送对客户端的SYN的ACK,之后服务端处于SYN-RCVD状态

  • 客户端收到服务端发送的SYN和ACK之后,发送服务端返回过来的ACK的ACK,之后客户端处于ESTABLISHED状态,至此客户端一发一收成功了

  • 服务端收到ACK的ACK之后,处于ESTABLISHED状态,至此服务端也一发一收成功了

TCP四次挥手

TCP四次挥手过程图:

img

TCP在断开连接时,会经历四次挥手阶段,以客户端主动断开连接为例,四次挥手过程如下所示:

  • 在客户端刚开始断开时,发送FIN,客户端就进入FIN_WAIT_1状态

  • 服务端收到客户端发送的FIN后,会发送一个对这个FIN的ACK,服务端进入CLOSE_WAIT状态

  • 客户端收到服务端对其FIN的ACK之后,就进入FIN_WAIT_2状态,如果此时服务端直接跑路,则客户端将永远在这个状态。TCP协议里面并没有对这个状态的处理,但是Linux有,可以调整tcp_fin_timeout参数,设置一个超时时间。

  • 之后服务端会再次发送一个FIN和ACK,进入到LAST-ACK阶段

  • 客户端在收到之后,会回复一个ACK,并进入TIME-WAIT状态,等待的时间设为2MSL,MSL是Maximum Segment Lifetime,报文最大生存时间,是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。以此来确保所有在挥手过程中的报文都已经接收或者失效,协议规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等

  • 之后两者都会进入CLOSED状态

TCP状态机

TCP状态机就是将连接建立和连接断开这两个时序状态图综合起来,可以参考上面两个三次握手和四次挥手的图

img

Socket

Socket可以理解为插口或者插槽,客户端和服务端在进行通信之前,双方需要建立一个SOcket,Socket编程进行的是端到端的通信,一般不知道中间经过多少局域网,多少路由器,因此能够设置的参数,都是端到端协议之上网络层和传输层的。

Socket函数指定是IPv4还是IPv6,分别对应设置为AF_INET和AF_INET6。指定是TCP还是UDP,TCP协议是基于数据流的,设置为SOCK_STREAM,而UDP是基于数据报的,设置为SOCK_DGRAM。

基于TCP协议的Socket程序函数调用过程

  • TCP的服务端要先监听一个端口,先调用bind函数,给这个Socket赋予一个IP地址和端口。对于一个应用程序,当一个网络包来的时候,内核要通过TCP头里的这个端口,来找到这个应用程序,把包交付,同时一个机器会有多个网卡对应多个IP地址,只有发送给监听IP地址网卡的包,才会交付。

  • 服务端有了IP和端口号,即调用listen函数进行监听。TCP的状态图有一个listen状态,当调用这个函数之后,服务端就进入了这个状态,此时客户端就可以发起连接了。

    在内核中,为每个Socket维护两个队列。

    一个是已经完全建立连接的队列,此时连接三次握手已经完毕,处于established状态;

    一个是还没有完全建立连接的队列,此时三次握手还没完成,处于syn_rcvd的状态。

  • 之后,服务端调用accept函数,拿出一个已经完成的连接进行处理。如果此时还没有已完成的,就需要等待。

  • 服务端等待的时候,客户端可以通过connect函数发起连接。先在参数中指明要连接的IP地址和端口号,然后开始发起三次握手。内核会给客户端分配一个临时的端口。握手成功后服务端的accept就会返回另一个Socket。监听的Socket和用来传数据的Socket是两个,一个是监听Socket,一个是已连接Socket

  • 连接建立成功之后,双方即可以通过read和write函数来读写数据

具体过程如下图所示:

img

TCP的Socket就是一个文件流,因为Socket在Linux中就是以文件的形式存在的。除此之外,其还存在文件描述符,写入和读出,也是通过文件描述符。Socket是一个文件,对应有文件描述符。每一个进程都有一个数据结构task_struct,里面指向一个文件描述符数组,来列出这个进程打开的所有文件的文件描述符。文件描述符是一个整数,是这个数组的下标。数组中的内容是一个指针,指向内核中所有打开的文件列表。文件还都有inode,但Socket对应的inode不像真正的文件系统一样保存在硬盘上,而是保存在内存中。在这个inode中,指向了Socket在内核中的Socket结构。在这个结构中,主要有两个队列,一个是发送队列,一个是接收队列,在这两个队列里保存的是一个缓存sk_buff。数据结构图如下图所示:

img

基于UDP协议的Socket程序函数调用过程

UDP是无连接的,因此UDP不需要三次握手,即不需要调用listen和connect,但UDP的的交互仍然需要IP和端口号,因而也需要bind。UDP没有维护连接状态,不需要每对连接建立一组Socket,而是只要有一个Socket,就能够和多个客户端通信。也正是因为没有连接状态,每次通信的时候,都调用sendto和recvfrom,都可以传入IP地址和端口。

UDP函数调用过程如下图所示:

img

服务器如何连接更多的项目

系统会用一个四元组来标识一个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,则是子进程;如果返回值是其他的整数,就是父进程。

进程复制过程如下图所示:

img

子进程复制了文件描述符列表,而文件描述符都是指向整个内核统一的打开文件列表,因而父进程刚才因为accept创建的已连接Socket也是一个文件描述符,同样也会被子进程获得。子进程就可以通过这个已连接Socket和客户端进行互通了,在通信完成之后退出后,父进程可以通过子进程ID来查看是否完成,是否退出。

多线程方式

多进程方式太消耗资源,在Linux下,通过pthread_create创建一个线程,调用do_fork。新的线程在task列表会新创建一项,但文件描述符列表、进程空间,还是共享的,只不过多了一个引用。新的线程也可通过已连接Socket处理请求,从而达到并发处理的目的。多线程方式如下图所示:

img

IO多路复用

无论进程还是线程,太多了以后都很难维护,可以采用IO多路复用,观测所有Socket,将其都放在一个文件描述符集合fd_set中即项目进度墙,然后调用select函数来监听文件描述符集合是否有变化。一旦有变化,依次查看每个文件描述符。发生变化的文件描述符在fd_set对应位都设为1,表示Socket可读或者可写,从而进行读写操作。

IO多路复用epoll模式

上面那个方式需要主动去循环检测,进行轮询,一样消耗资源。可以使用epoll,当项目进度发生变化的时候,主动通知项目组,然后项目组再根据项目进展情况做相应的操作。其在内核中的实现不是通过轮询的方式,而是通过注册callback函数的方式,当某个文件描述符发送变化的时候,就会主动通知。

img

HTTP协议

一般网址域名,称之为URL,即统一资源定位符。当将网址输入到浏览器后,浏览器会将域名发送给DNS服务器,让其解析为IP地址。建立了TCP连接之后,就可使用HTTP协议,因为HTTP协议是基于TCP协议的。目前使用的HTTP协议大部分是1.1,默认开启Keep-Alive,此时建立的TCP连接即可在多次请求中复用。

HTTP请求的构建

HTTP请求格式:

img

HTTP的报文分为三大部分即请求行、首部和正文实体

请求行

访问类型主要分为GETPOSTPUTDELETE

GET就是去服务器获取一些资源。对于访问网页来讲,要获取的资源往往是一个页面。比如返回一个JSON字符串,到底要返回什么,是由服务器端的实现决定的。

POST需要主动告诉服务端一些信息,而非获取。一般会将告知内容放在正文里面,正文可以有各种各样的格式,常见的格式也是JSON。

PUT就是向指定资源位置上传最新内容。但HTTP的服务器往往是不允许上传文件的,PUT和POST主要是用于要传给服务器东西的方法。

POST往往是用来创建一个资源的,而PUT往往是用来修改一个资源的。

DELETE就是用来删除资源的。

首部字段

首部是key value,通过冒号分隔,首部保存的字段都较为重要,比如Accept-Charset,表示客户端可以接受的字符集,Content-Type表示正文的格式,需要正文传输JSON格式时即需要将这个值设置为JSON。

对于高并发场景下的系统,在真正的业务逻辑之前,需要有一个接入层,将这些静态资源的请求拦在最外面,架构图如下图所示:

img

对于静态资源,有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的返回报文格式如下图所示:

img

状态码能反映HTTP请求结果,200表示成功,404表示服务端无法请求这个请求。之后返回首部的key-value,Retry-After表示,客户端应该在多长时间以后再次尝试。Content-Type,表示返回的是HTML,还是JSON。

HTTP返回报文构造完成之后,会交给Socket和TCP层去发送,TCP层将返回的HTML,分程很多小段,确保每个段都能可靠到达。再经过IP和MAC等处理,浏览器拿到HTTP报文发现返回200后,一个正常的HTML网页即能显示。

HTTP 2.0

HTTP 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地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-06 11:28:49  更:2021-09-06 11:30:01 
 
开发: 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年6日历 -2024/6/27 1:59:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码