如何在虚拟机中建设网站,wordpress windows 伪静态,统计助手小程序怎么制作,北京培训机构文章目录 1、再谈端口号2、UDP协议3、TCP协议3.1 TCP协议段格式3.2 TCP的三次握手和四次挥手#xff08;连接管理机制#xff09;3.3 TCP的滑动窗口3.4 TCP的流量控制3.5 拥塞控制3.6 延迟应答和捎带应答3.7 面向字节流和粘包问题3.8 TCP总结 1、再谈端口号
端口号port标识一… 文章目录 1、再谈端口号2、UDP协议3、TCP协议3.1 TCP协议段格式3.2 TCP的三次握手和四次挥手连接管理机制3.3 TCP的滑动窗口3.4 TCP的流量控制3.5 拥塞控制3.6 延迟应答和捎带应答3.7 面向字节流和粘包问题3.8 TCP总结 1、再谈端口号
端口号port标识一个主机上的不同应用程序。
比如常见的服务器端口 HTTP服务器端口号是80HTTPS服务器端口号是443FTP服务器端口号是21SSH服务器端口是22 端口号范围划分 0 - 1023是一些知名端口号HTTP,FTP,SSH等这些应用层协议他们的端口号是固定的。 1024-65532操作系统动态分配的端口号。客户端程序的端口号就是这个范围里分配的。 通过下面的命令可以看到所有知名端口号
cat /etc/services值得注意的是
一个端口只能绑定一个进程而一个进程可以绑定多个端口。
netstat
netstat是一个用来查看网络状态的重要工具
常用选项 n 拒绝显示别名能显示数字的全部转换成数字l 仅列出在Listen监听状态的服务p 显示建立相关链接的程序名t 仅显示tcp相关选项u 仅显示udp相关选项a 显示所有选项默认不显示LISTEN相关 pidof
在查看服务器进程id时非常方便。
通过进程名查看进程id
pidof [进程名]2、UDP协议
UDP协议端格式 UDP相关字段 16位的源端口号和目的端口号保证了数据包的分发。源端口号表明了数据从哪个应用层进程来到哪个应用层进程去。 16位UDP长度表示整个数据报报头有效载荷的最大长度。UDP报文不是流式的是有边界的因此可能出现两个报文互相干扰通过限定数据报大小就能很好解决这个问题 16位UDP检验和如果校验和出错就会直接丢弃。 //报头结构可以理解成一堆字段
struct udp_hdr
{size_t src_port:16size_t dst_port:16size_t udp_len:16size_t udp_check:16
}
//添加报头本质就是在数据前面拷贝一个结构体对象UDP的封装、解包和分用
UDP报文是定长的传输层封装就直接在原来的应用层数据上通过指针添加一段结构体对象另一端在解包时就直接通过定长的8字节找到报文大小在通过报文减去8字节确定有效载荷数据完成解包。由于报头中有确定的目的端口因此也能确定特定的应用层协议进程。
UDP的特点 无连接: 知道对方的IP和端口号就直接传输不要建立连接。不可靠: 没有确认机制没有重传机制如果无法发给对方也不会有任何错误信息。面向数据报不能够灵活的控制读写数据的次数和数量。 无连接和不可靠不能看成是UDP的缺点而是特点建立连接和保持可靠是需要代价的在某些场景下恰恰无连接和不可靠才是好的。
其中面向数据报应用层交给UDP多次的报文UDP原样发送既不拆分也不合并。
比如发送端一次sendto发100个字节接收端也一定是recvfrom接收100个字节
udp缓冲区 udp没有真正的发送缓冲区因为数据简单并且不用维持连接和可靠性不用暂存起来调用sendto会交给内核由内核将数据传给网络层协议进行后续的传输。udp具有接收缓冲区因为udp不保证可靠性所以这个接收缓冲区不能保证收到udp报顺序和发送udp顺序报顺序一样并且如果缓冲区满了再次到达的udp数据会被丢弃。 实际上常用的write这类IO接口实际上不是将数据写入文件而是将数据拷贝至系统缓冲区因为只有系统才了解硬件的情况因此拷贝到系统缓冲区的数据什么时候发、怎么发都由OS决定。网络中的sendto也是如此。
这类udp的socket既能读也能写这个概念叫全双工。 可以注意到16位udp长最大也就64K很小如果传输的数据超过64K就需要应用层手动的分包多次发送并在接收端手动拼装。
udp因为其不需要维护其连接和可靠性在一些链接压力很大并且只需要进行传输数据的场景就非常合适。比如直播 3、TCP协议
tcp传输控制协议的特点是有连接和可靠性因此谈论tcp协议往往需要讨论其可靠性和效率问题。
3.1 TCP协议段格式 16位源端口号和16位目的端口号和UDP一样源端口号表明了数据从哪个应用层软件来到哪个应用层软件去。4为首部长度表示TCP报头有多少个4字节。因此如果显示是0101那么报头大小为5*4 20字节。因此报头的范围为20-60. TCP的封装、解包和分用 封装TCP的数据报大小是动态的其报头也是通过字段组成。因此在封装的时候也是在应用层数据的基础上添加一个结构体对象。 解包在解包的时候通过4位首部长度*4减去20字节标准报头就可以确定还有多少剩余报头提取完报头剩下的就是有效载荷。对于有效载荷的边界问题后面再详细讨论。 分用分用一样是通过目的端口号确定特定的应用层协议进程。 TCP可靠性问题
什么是不可靠 丢包、乱序、数据包检验失败怎么确认一个报文是丢了还是没有丢 如果收到应答就确认没丢没有就不确定。 TCP不提供有效载荷大小的字段而是采用一种确认应对机制确保数据传输可靠。 那么如果面对多种请求如何确定哪些是确认收到的呢 对于发送的多个信息只有收到的信息是和发送有对应关系的才能确定发出去的数据是可靠的。 因此TCP报头中有两个重要的字段32位序号和32位确认序号。 其中序号标识传输的当前报文确认序号代表确认接收到了当前所有之前序号的报文。因此序号和确认序号保证了两端通信数据的可靠性。 那为什么一个报文中要同时存在序号和确认序号两个字段呢 因为tcp是全双工的当server在确认回应的同时也可能向Client发送数据因此就需要一个报文设置两份序号。 为了保证序号安全序号生成不能有规律即序号生成是随机生成的并且与报文有关。溢出也会有方法进行回绕。
TCP发送缓冲区和接收缓冲区的关系
tcp协议传输需要保证其可靠性因此在发送的时候需要有发送缓冲区比如为了超时重传进行备份数据另一端也需要有接收缓冲区暂存还未被应用层提取的数据。 实际上用户层上会有自己定义的缓冲区并且IO类函数本质都是拷贝函数将用户数据拷贝到内核再由内核拷贝给用户因为OS比用户更清楚底层的情况。 因此数据怎么发出错了怎么办要不要添加提高效率的策略这些都是由OS中TCP自主决定的所以TCP对数据是具有传输和控制能力的也就被称为传输控制协议。 其实在文件操作中虽然用户拷贝到内核缓冲区的数据是由OS决定何时何样写到文件中但也提供一些接口如fsync刷新缓冲区接口给用户带来确定性。网络更需要这样不然在用户发送后OS经过一些决定后才算发送成功那么效率就太慢了。 TCP协议中有自己的发送缓冲区和接收缓冲区因此一端在接收数据的时候也能向对方发数据。全双工的通信特点也因此。 16位窗口大小的应用 如果当client向server发消息速度过快导致server缓冲区满了那么后续的数据接收不了该怎么办呢 让client重传这个做法显然是不太行的因为client传递的数据是需要成本的如果在到达后才知道server接收不了数据这很影响效率。 有没有一种能提前知道对方接受能力的策略报头中的窗口大小字段很好的解决。 client给server发消息后server的应答报文中是会有窗口大小字段的。这个窗口大小就是接收缓冲区的剩余接收容量。 双方都可以通过传输报文的同时携带自身的窗口大小让对方知道自己接收缓冲区的剩余接收容量这一双向的行为也称流量控制。 6位标志位
两端进行TCP协议的整个通信过程中有相互建立链接的过程有通信的过程有断开链接的过程。在这些过程中发送的报文也有很多的类别需要用不同逻辑区分这些报文。 SYN请求建立连接把携带SYN标识的称为同步报文段。只要报文是建立链接请求标识为1证明这一次是建立连接的请求。FIN通知对方本端要关闭了。携带这种标识的称为结束报文段。ACK确认标记位标识该报文是对历史报文的确认。发送的确认报文不仅仅可以是确认也可以边确认边发消息PSH提示接收端应用立刻从TCP接收缓冲区内把数据读走。可以理解为催促报文一种就绪数据通知策略URG紧急指针标记位。TCP为了保证其数据可靠性通过在缓冲区将序号进行排序让发报文和收报文的顺序是一样的。但如果有一些数据优先级更高但序号较晚因此有优先被要求的需求。通过URG标记让报文是优先被读的类型。之后通过16位紧急指针在数据中获得特定的偏移量位置的数据并且该数据只有1个字节。在一些极端情况下常用于查看机器的状态RST对方要求重新建立连接; 我们把携带RST标识的称为复位报文段。如果Client回应ACK后Server没有收到此时Client以为建立成功就直接开始通信而Server看到没有建立链接就发信息于是发一个RST的报文要求让对方重新建立链接。 3.2 TCP的三次握手和四次挥手连接管理机制 TCP的三次握手
tcp是面向连接的如果多个客户端与TCP服务器建立链接OS就需要管理这些链接就需要管理维护这些链接的结构体。花时间、花空间
为什么是三次握手 一次行不行SYN一次不一定成功并且很容易收到攻击构造假的SYN请求引发SYN洪水使得服务端一直建立维护链接的结构体不断消耗其资源两次行不行SYNSYNACKserver还是认为一次SYN就成功了其实和一次是一样的。Client只要忽略你发的请求就还是可以和一次的SYN攻击一样的。三次三次让客户端先建立维护链接的结构体再回复给server。这样客户端就要和服务端受到同等代价而服务器资源肯定是要比单主机资源多的。同时三次的ACK失败不影响server而是影响client。奇数次链接成本能够嫁接到客户端 三次握手也用最小成本验证了全双工。
TCP的四次挥手 TCP是全双工的通信双方地位是共有的你关闭对应链接我也要关闭对应链接。
客户端主动关闭连接向服务端发送FIN结束报文服务端返回确认报文段进入CLOSE_WAIT处理完之前数据就close关闭连接向客户端发送FIN结束报文等待最后一个ACK到来后就彻底关闭连接客户端等待后进入CLOSED。 进入CLOSE_WAIT状态的服务器此时因为没有close对应socket而占用资源。因此可能会有内存泄漏危险。 因为TCP是全双工的在特殊情况下Server方的ACK和FIN可能会以一个报文的形式发送。 一个现象为什么服务器关闭客户端再关闭客户端还要进入TIME_WAIT状态
因为最后的ACK回应报文可能是丢失的如果Client完成四次挥手直接进入CLOSED状态可能Server还没有完成四次挥手最后以异常情况关闭链接这有问题。因此Client收到FIN后向Server发送ACK如果之后没有发生Server因为超时重传FIN的情况Client就正常退出。 那么这个TIME_WAIT等待的时长是多少呢 Client-ServerServer-Client一来一回时长是要浮动的其中最长的被称为TCP最大生存时间MSL而TIME_WAIT等待时间如果设定为2*MSL就能保证完成一次一来一回。 不过一般MSL都是被系统设置好了这是为了保证两个传输方向上不收到尚未被接收或迟到的报文段。 [yzhVM-4-8-centos ~]$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60在极端情况下 TIME_WAIT意义从宏观上来看Client可能在传Data同时传了FIN当FIN先到达时TIME_WAIT就能很好保证剩余数据也能被处理。 不过在一些场景下需要服务器及时启动让其它不同IP或端口的客户端能够bind成功随后链接。
//通过setsockopt设置的socketlevel一般设置为SOL_SOCKET代表socket层选项optname有SO_REUSEADDR和SO_REUSEPORT分别代表能以不同的IP和端口进行绑定链接。opt代表设置新值的缓冲区。
#include sys/socket.h
int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);int opt 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt));3.3 TCP的滑动窗口
TCP的Listen和Accept
#include sys/socket.h
//socket是套接字。
//如果backlog上层不进行accept底层建立好的链接数就是有上限的上限是backlog1。
int listen(int socket, int backlog);
int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);在TCP三次握手之前listen是一个等待链接的接口在调用accept之前建立链接后会在底层建立一个链接好的队列。里面都是全链接ESTABLISHED状态的结构体。此时已经建立好链接。在链接数超过backlog1后再次建立的链接就会处于SYN_RCVD半链接状态 accept不参与三次握手但底层会维护一个链接队列accept将底层链接拿到上层给用户看到。 重点是为什么要有这个队列呢 1、为什么要排队 可以让我们Server在有闲置的情况下从底层拿去链接进行链接处理。 2、为什么不能太长 太长影响客户体验太长过于占用资源反而可能导致服务器效率低下。与其增加更多的排队资源不如腾出更多的资源给客户使用 TCP的确认应答机制 之前的确认应答机制主机间的通信发一次给一次应答整个过程是串型的。这种做法效率很低。TCP采用它的思想但不按照这样做。 通过并行的确认应答机制接收一堆响应一堆。TCP发送真正采用的是这种策略。 滑动窗口和缓冲区 发送出去的数据在没有得到回应的情况下必须被保留在发送缓冲区以便支持超时重传。 在发送缓冲区中已经发送但没有得到响应的区域就是可能会出现超时重传的数据的区域。 它的整个区域大小也就决定了当前最多能发多少的数据给接收端能发多少也就取决于接收端有多少的吞吐量而衡量这一标准采用的就是接收端的16位窗口大小字段。在发送数据的过程中这个区域的大小随着接收端的窗口大小而变化因此形象称之为滑动窗口。 上图中假设开始滑动窗口位4KB同时也对应接收端接收缓冲区为4KB当其中4KB数据全部传输过去但接收端的用户进程一点都不取。这时接收缓冲区的剩余容量就是0因此滑动窗口大小也就为0。同时滑动窗口的移动不可能向左并且不用担心越界问题因为在实现角度上可以通过一个缓冲区数组的下标进行取模调整因为滑动窗口之前的数据都是无用数据了。 滑动窗口与超时重传策略 假设接收端接收缓冲区接收能力一直不变当传输序号为1001~2000的报文当收到2001的确认序号滑动窗口起始就移到2001代表之前数据发送成功。 那么在传多个报文的时候中间报文丢失了怎么办
情况1数据包完整ACK丢了。 如上图假设同时发送4种报文其中只收到了确认报文4001其它的确认报文都丢失怎么办呢 只要确认序号收到4001那么就代表4001前的都收到前面丢的都可以忽略start_index就可以直接到4001。 情况2数据包丢了 数据一直从1 ~ 1000发到6001 ~ 7000接收端的接收缓冲区里除了1001 ~ 2000的数据包其它的都收到了。因此返回确认报文时确认序号总是1001当发送端收到3个同样的确认应答时就会知道对应数据包丢失了进行重发。之后如果接收端收到了1001 ~ 2000的数据包就会返回确认序号为7001的报文代表之前序号的报文都收到了。对应滑动窗口start_index就到了7001 这种机制被称为 “高速重发控制”(也叫 “快重传”) 综上滑动窗口能在一定上提高传输的效率同时也能很好的解决TCP的丢包问题。 3.4 TCP的流量控制
在前面介绍窗口大小字段的时候为了让发送端知道接收端的剩余接收容量在接收端发送报文给发送端的时候会附带一个窗口大小字段代表当前还能接受多少的数据量。因为TCP是全双工的双方都可以这么做。
因此TCP支持根据接收端的处理能力来决定发送端的发送速度这个机制就叫做流量控制。 如果接收端缓冲区满了就会将窗口置为0这时发送方不再发送数据但是发送方会定期发送一个窗口探测数据段如果过了重发超时的时间还没收到窗口更新的通知就会发一个窗口探测的包再由接收端把窗口大小告诉发送端。但这个返回的窗口通知是可能会丢失的因此发送端主机会时不时发送窗口探测包。 不过窗口大小是16位的最大也就64K那么数据超过这个怎么办在TCP首部中选项中有对应的扩大因子会将实际窗口大小字段左移。 3.5 拥塞控制
在之前我们考虑了主机之间的数据可靠问题、效率问题、流量控制问题但是这些都是主机和主机之间的。网络通信还必须考虑主机和网络之间的问题。因为网络上有很多的计算机可能当前网络状态已经很拥堵如果在不清楚网络的状态下贸然发送大量数据是很有可能引起雪上加霜的。 当发送方发送1K个报文在接收端接收时发现少了2、3个报文。此时可能是发送端或接收端问题这没事大不了就超时重传一下。 如果发送方发送1K个报文在接收端接收时发现少了大量的报文此时就不应该是发送端接收端的问题因为它们之间有策略保证了数据的可靠性问题。此时大概率就是网络的问题了。 因为网络拥塞问题出现大量的丢包那能重传吗 接入网络的主机是很多的如果网络出问题这么多的主机出现丢包如果超时重传的话那么一定会有一定量的主机在同一时间段向网络发送数据造成了大量的数据向网络里塞网络压力本来就很大因此这种方式不行。 那解决方案拥塞控制 TCP引入慢启动机制识别到网络拥塞先发少量的数据探探路摸清当前的网络拥堵状态再按照多大的速度传输数据。 拥塞窗口发送的数据在这个窗口数据量内不会发生阻塞超过这个量可能会导致网络拥塞问题。 在之前一次向目标主机发送数据的量是对方窗口大小现在考虑网络一次向目标主机发送数据最大的量就应该是对方窗口大小和网络拥塞窗口的较小值。 在发生开始的时候定义拥塞窗口大小为1每次收到一个ACK应答阻塞窗口以2倍增长。这种”慢启动“在初始时慢但是增长速度很快这也是为了想尽快把数据传给对方。当拥塞窗口超过某个阈值的时候不再按照指数级方式增长而是按照线性增长。如果再次遇到网络拥塞就会再次降低拥塞窗口进行慢启动。 综上拥塞控制是为了TCP协议尽快把数据传输给对方但又要避免给网络造成拥塞的折中方案。 3.6 延迟应答和捎带应答
延迟应答
如果接收数据的主机立刻返回ACK应答这时候返回的窗口可能比较小因为接收发上层用户还没从接收缓冲区里取走数据窗口大小就被返回了。 假设接收缓冲区的大小是1M一次收到了500K的数据如果立刻应答返回的窗口就是500K。如果等待一段时间让上层用户将缓冲区中的500K数据取走再返回的窗口就又是1M。 值得注意的是窗口越大网络的吞吐量就越大传输效率就越高我们目标是保证在网络不拥塞的前提下提高传输效率。 那么这个等待时间如何把握呢毕竟等待是为了更好的提高传输效率如果等待过长就得不偿失了。 数据限制每隔N个包就应答一次。一般N2(更多)时间限制超过最大延迟时间就应答一次。一般200ms 捎带应答
稍等应答很简单在之前认识TCP两端进行通信的时候大多数是”一发一收“的在ACK的时候可以不仅是发送确认同时也可以发送我想给你发的有效信息。 3.7 面向字节流和粘包问题
创建一个TCP的socket, 会同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区; 建立连接的双端有两套缓冲区彼此可以互相读写因此构成了全双工。 在写入和读取缓冲区字节的时候可以任意控制其数量以及次数。 TCP是面向字节流的接收和发送不关系任何数据格式但是应用层要正确使用这里的数据是需要有特定数据格式的在应用层就需要自己定制协议。如果数据处理直接从流氏空间中以特定字节读取的话就很可能读到多个数据包的内容这就是TCP粘包问题。就是蒸包子时还没分开直接拿的时候可能会拿到其它包子的部分 如果明确报文和报文的边界 1、通过特定的标识符将其分开。比如http中的空行、\r\n 2、可以在报头位置约定一个包总长度的字段。比如http属性中的content-length UDP协议没有”粘包问题“因为其报头中有明确的报文长度字段这保证了其报文的边界。
3.8 TCP总结
TCP的复杂就是为了保证其可靠性以及尽可能提高性能。
可靠性 校验和序列号确保发送和接收的顺序性确认应答通过序号和确认序号超时重发连接管理三次握手四次挥手流量控制通过窗口大小决定数据能被接收的量同时也决定了发送方的速度拥塞控制在保证网络不拥塞的情况下维持TCP最大的传输速度 提高性能: 滑动窗口 让数据并行可靠的向对方发送快速重传发送丢包时发送方通过边传数据边识别多次收到相同确定序号报文的快重传策略延迟应答捎带应答