Linux网络——传输层协议

news/2024/5/17 17:28:14 标签: Linux网络, 传输层协议, UDP, TCP

目录

    • UDP协议
        • 协议格式
        • 协议特性
        • 基于UDP的应用层协议
        • 注意事项
    • TCP协议
        • 协议格式
        • 协议特性
            • 建立 / 断开连接
            • 面向连接
            • 可靠传输
            • 面向字节流
        • 基于TCP应用层协议

UDP_1">UDP协议

协议格式

图片

  • 16 位源端和对端端口:用于描述识别通信两端进程;
  • 16 位数据报长度:能够存储的最大数据长度 65535 字节,所以 udp 报文大小最大不能超过 64k 字节,这其中是包含头部的 8 字节大小的;
  • 16 为校验和:采用二进制反码求和算法,校验接收方接受到的数据与发送方发送的数据是否一致;
  • udp 协议的头部长度固定位 8 字节;

协议特性

  • 无连接:通信时不需要建立连接,只要知道对方地址就可以直接发送数据;
  • 不可靠:不保证数据安全并且有序的到达对端;
  • 面向数据报:无连接、不可靠、无序、有最大长度限制的传输方式;
  1. udp 传输时,sendto发送的数据会被放到发送缓冲区,但是 udp 并不会等待(也就是说,只要有数据放到发送缓冲区,就直接进行后续操作,不等待是否还有数据进来),而是直接对数据封装头部并发送;
  2. udp 传输时,recvfrom收到的数据被放到会被放到接收缓冲区,而 udp 保证数据是整条交付的(就连头部信息也不剥离),并不会出现半条或者多条交付;

UDP_14">基于UDP的应用层协议

  • NFS:网络文件系统
  • TFTP:简单文件传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议

注意事项

  1. 不保证安全到达:会在应用层的时候使用 tcp 所使用的一些机制实现;
  2. 不保证有序到达:需要在应用层进行包序管理;
  3. udp 报文有最大限制:报文最大长度小于 64k 字节,因此发送大块数据的时候,需要在应用层对数据分包发送;
  4. udp 实现整条交付:因此接收方定义的缓冲区要足够大,能够一次性取出一整条数据;

TCP_25">TCP协议

协议格式

在这里插入图片描述

  • 16 位源端和对端端口:用于描述识别通信两端进程;
  • 32 位序号和确认序号:实现 tcp 包序管理;
  • 4 位头部长度:表示该 tcp 头部有多少个字节,以 4 字节为单位,因为 4 字节所能表示的最大数字为 15,所以 tcp 头部最大长度是15 * 4 = 60,并且规定最小为 20 字节;
  • 6位标志位:
    • URG:紧急指针是否有效;
    • ACK:确认号是否有效;
    • PSH:提示接收端应用程序立刻从 TCP 缓冲区把数据读走;
    • RST:对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段;
    • SYN:请求建立连接; 我们把携带 SYN 标识的称为同步报文段;
    • FIN:通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段;
  • 16 位窗口大小:实现滑动窗口机制,是 tcp 的一种流量控制方法,保证数据不会因空间不足而丢失;
  • 16 为校验和:采用二进制反码求和算法,校验接收方接受到的数据与发送方发送的数据是否一致;

协议特性

建立 / 断开连接
  • 三次握手、四次挥手过程图:这其中四次挥手并不总是由客户端先发送 fin 请求,只不过在实际中服务端通常不会主动断开连接,通常是由客户端主动断开连接,所以图片中就以客户端断开为例;
    在这里插入图片描述

服务端状态转化

  • [CLOSED -> LISTEN]:服务器端调用 listen 后进入 LISTEN 状态,等待客户端连接;
  • [LISTEN -> SYN_RCVD]:一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列中,并向客户端发送 SYN 确认报文;
  • [SYN_RCVD -> ESTABLISHED]:服务端一旦收到客户端的确认报文,就进 ESTABLISHED 状态,可以进行读写数据了;
  • [ESTABLISHED -> CLOSE_WAIT]:当客户端主动关闭连接,服务器会收到结束报文段,服务器返回确认报文段并进入 CLOSE_WAIT 状态;
  • [CLOSE_WAIT -> LAST_ACK]:进入 CLOSE_WAIT 后说明服务器准备关闭连接(需要处理完之前的数据),当服务器真正调用 close 关闭连接时,会向客户端发送 FIN,此时服务器进入 LAST_ACK 状态,等待最后一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN);
  • [LAST_ACK -> CLOSED]:服务器收到了对 FIN 的 ACK,彻底关闭连接;

客户端状态转化:

  • [CLOSED -> SYN_SENT]:客户端调用 connect,发送同步报文段;
  • [SYN_SENT -> ESTABLISHED]:connect 调用成功,则进入 ESTABLISHED 状态,开始读写数据;
  • [ESTABLISHED -> FIN_WAIT_1]:客户端主动调用 close 时,向服务器发送结束报文段,同时进入 FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2]:客户端收到服务器对结束报文段的确认,则进入 FIN_WAIT_2,开始等待服务器的结束报文段;
  • [FIN_WAIT_2 -> TIME_WAIT]:客户端收到服务器发来的结束报文段,进入 TIME_WAIT,并发出 LAST_ACK;
  • [TIME_WAIT -> CLOSED]:客户端要等待一个 2MSL(Max Segment Life, 报文最大生存时间)的时间,才会进入 CLOSED 状态;
面向连接

为什么握手是三次,而挥手是四次?

  • 握手:两次不安全,tcp 是一个全双工通信,两端都必须确认对方是否具有数据收发的能力,服务端在收到客户端 syn 请求后,需要确认客户端还在,所以需要第三次的 ack;四次没必要,服务端收到客户端 syn 请求后,可以在进行 ack 应答的同时并向客户端发送 syn 请求,所以没必要吧 ack 与 syn 分开来发送;
  • 挥手:fin 包只能表示对方不再发送数据了,不代表对方不再接收数据,被动关闭方有可能还会继续发送数据,因此这种情况下就不能在收到对方 fin 包后,在发送 ack 应答的同时发送 fin 包,而是等待上层用户不在发送数据了,调用 close 或者 shutdown 才会发送 fin 包,因此被动关闭方的 ack 和 fin 并不能一起发送;

tcp 三次握手失败了,两端是如何处理的?

  • 客户端 syn 丢失:会重新向服务端多次发送 syn 连接请求;
  • 服务端 ack + syn 丢失:不会重发 ack + syn,而是向客户端发送 rst 重置连接报文,然后释放新建套接字;
  • 客户端 ack 丢失/恶意不回:服务端会默认为是恶意攻击,所以向客户端发送 rst 重置连接报文,然后释放新建套接字;

主动关闭方在发送最后一次 ack 之后为什么会进入 TIME_WAIT 状态,而不是直接关闭套接字?

  • TIME_WAIT 是主动关闭方在断开连接过程中进行最后一次 ack 回复后进入的状态,如果没有 TIME_WAIT:主动关闭方 A 会在最后一次 ack 之后直接释放资源,如果此时被动关闭方没有收到最后一次 ack 回复,则会重传 fin,然后等待主动关闭方的 ack 应答,恰巧此时主动关闭方又启动了一个新的套接字使用的地址信息和之前的 A 一样,那么这个新套接字就会收到 fin 包,或者被动关闭方在等待 ack 应答时会收到 syn 请求,从而造成影响;
  • 这个对于服务端其实算是一个阻碍,首先我们要知道服务端地址信息不轻易改变,因此如果服务端挂了,那么我需要立马启动服务端,但是此时这个地址信息正处于 TIME_WAIT 状态,服务端不能立马使用,所以 TIME_WAIT 更多的是为了保护客户端启动时不会受到上个套接字通信遗留问题;
  • TIME_WAIT 状态会持续两个 MSL(一个报文最大生存时间,默认 60s),一是为了保证对重传的 fin 进行处理,二是保证之前通信过程中的所有数据都消失在网络中,从而不影响到后续新的通信连接;

一台主机上出现了大量的 TIME_WAIT 状态的原因?如何解决?

  • 原因:TIME_WAIT 是主动关闭方在断开连接过程中进行最后一次 ack 回复后进入的状态,因此存在大量的 TIME_WAIT 状态,则说明存在大量的主动关闭套接字;
  • 解决
    • 减少 TIME_WAIT 状态时间,也就是设置减少 MSL(一个报文最大生存时间,默认 60s)的时间;
    • 使用套接字选项:地址复用,客户端一般不使用,服务端常用,这是为了防止服务器断开连接后不能立即重启,下面是为套接字设置地址复用的接口;
      int setsockopt(int fd, int level, int optname, void* optval, int optlen);:fd——需要设置的监听套接字描述符,level——选项定义的层次,一般设置为 SOL_SOCKET,optname——需设置的选项,我们只需要对 SO_REUSEADDR(地址重用)进行设置,optval——指向一个缓冲区的指针,用来给 optname 中的选项设置值,选项 SO_REUSEADDR 设置为 1,optlen——optval 设置的缓冲区长度;

一台主机上出现了大量的 CLOSE_WAIT 是什么原因?如何解决?

  • CLOSE_WAIT 是被动关闭方在收到 fin 包后进行 ack 应答后进入的状态,这个状态的后续操作是等待上层用户调用 close/shutdown(wr),所以出现这种状态后很有可能是代码中没有对套接字调用close

如何保证在没有通信时,也确定和对方持续保持连接?

  • tcp 保活机制:通信两端在长时间没有数据通信的情况下,服务端每隔一段时间会向客户端发送一个保活探测数据包,要求客户端进行回复,如果服务端连续多次没有收到回复信息,那么则认为连接断开,默认 7200s 没有通信,则每隔 75s 发送探测包,如果 9 次无回复则认为连接断开,这些数值是可以通过套接字选项进行设置的;
  • 连接断开在程序中的体现:recv返回 0,或者send触发 SIGPIPE 异常,所以我们通常在编写 tcp 通信程序时,首先是自定义 SIGPIPE 信号的处理方式,以防止程序因为连接断开就直接退出(有时候连接断开不想要直接退出,而是想要重新连接);
可靠传输

如何保证 tcp 通信中包序的正确性?

  • 数据序号:在传输过程中,发送发会告诉对方数据起始位置以及数据大小(来确定每个数据的顺序位置),然后接收方会根据数据的序号存放在接收缓冲区中对应的位置,没有接收到的数据位置则空着,当要取出数据时,即使某个位置为空也要算作一份子按序取出;
  • 确认序号(确认应答机制):确认序号 = 起始序号 + 数据长度,即接收方针对接收到的每一条数据进行确认回复,回复的序号意味着在此序号之前的数据我都接收到了;
    如果发送发没有接收到某一个确认序号,但是接收到了后续的确认序号,则不会重传该数据;
    如果接收方没有接收到某个序号的数据,但是接收到了后续序号的数据,那么则不会发送后面的确认序号,只有接收到了缺失的数据,才会按序发送确认序号;
  • 超时重传机制:发送数据后,若等待确认回复超时,则会认为数据丢失,进行重传;
    • Linux 中(BSD Unix 和 Windows 也是如此)超时以 500ms 为一个单位进行控制,每次判定超时重发的超时时间都是 500ms 的整数倍;
    • 如果重发一次之后,仍然得不到应答,等待 2 * 500ms 后再进行重传;
    • 如果仍然得不到应答,等待 4 * 500ms 进行重传,依次类推,以指数形式递增;
    • 累计到一定的重传次数,TCP 认为网络或者对端主机出现异常,强制关闭连接;
  • 校验和字段:检验数据一致性,不一致则丢弃,并发送重传请求;
  • 滑动窗口机制:通信双方都会有接收窗口和发送窗口,发送窗口(后沿:发送起始序号,前沿:结束发送位置,前沿减去后沿不能大于对方的窗口大小),接收窗口(后沿:起始接收序号,前沿:结束接收位置,前沿减去后沿不能大于接收缓冲区空间大小);
    一开始,双方协商每次发送的最大数据大小(mss),然后发送方会根据接收方接收窗口大小,确定发送窗口大小,接着以不大于 mss 的大小在发送窗口中拿取数据发送,一次数据通信后,双方会调整窗口大小(后沿移动,前沿不变),如果当接收方缓冲区大小出现改变,则双方窗口需要进行相应调整(后沿不变,前沿移动);
    窗口大小字段越大,说明网络的吞吐量越高,接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端,发送端接受到这个窗口之后,就会减慢自己的发送速度;
    因为接收方窗口大小改变只有在通信回复时才能被发送方知道,所以如果接收窗口大小为 0 后,发送方并不是就不进行数据通信了,而是会每隔一段时间向接收方发送窗口探测包,以此来确认什么时候继续发送数据;
    一篇相关文章:TCP的滑动窗口机制
  • 一些相关协议:
    停等协议:收到确认回复后才会发送下一条;
    回退 n 步协议:从丢失的数据开始进行重新传输;
    选择重传协议:哪条数据丢了就重传哪条;

在通信过程中如果出现网络突然变差,该怎么应对?

  • 拥塞机制:以慢启动快增长的形式进行传输,发送方维护一个拥塞窗口,用于限制当前所能发送的数据大小,发送开始的时候,定义拥塞窗口大小为 1,每次收到一个 ACK 应答,拥塞窗口翻倍,每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口,当增长到一定程度后不再按照指数方式增长,而是按照线性方式增长,以此种方式来实现网络探测,少量的丢包,仅仅是触发超时重传,大量的丢包,就会认为网络拥堵,当 tcp 通信开始后,网络吞吐量会逐渐上升,随着网络发生拥堵,吞吐量会立刻下降,拥塞控制,归根结底是 tcp 协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案;

tcp 通信中存在许多机制来保证它的安全可靠,但是性能较低,如果来提高 tcp 通信的性能?

  • 确认序号:是告诉发送方确认序号之前的所有数据都已经接收成功,避免因为中间的某个确认回复丢失而导致的重传,这样会极大影响效率;
  • 快速重传机制:目的是为了减少超时等待的时间,接收方在接收数据时,先接收到了后发的数据,则认为前边的数据有可能丢失,则在一定间隔下连续发送三条前边数据的重传请求(确认序号为丢失数据的起始序号,即 ack = 丢失数据起始序号),发送方接收到连续三条重传请求,则对该序号的数据进行重新传输,三次重传请求是为了防止前边数据因为网络状况后到达的情况;
  • 延迟应答机制:接收方接收到数据后,延迟确认回复,这是因为接收方接收数据后如果立即进行回复,大概率窗口大小会减小,延迟应答是为了尽量保证窗口大小,在延迟期间,上层有可能将数据取出,此时窗口将不会减小,保证传输吞吐量;
  • 捎带应答机制:将确认回复信息,放到即将要发送的数据包头,捎带一块传输给对方,尽可能减少了纯报头的确认回复;
面向字节流
  • 概念:基于连接、可靠的、有序的、双向的一种字节流(以字节为单位)传输方式,tcp 要发送的数据都会被放到发送缓冲区中,通信时 tcp 会从缓冲区中取出合适大小的数据(不大于 mss 大小),封装头部进行发送;
  • 优点:不限制上层发送、接收时对数据大小的要求,数据会在缓冲区中堆积,使得传输比较灵活;
  • 缺点:会产生粘包问题——将多余的数据当做一条进行处理,无法分辨数据的边界,这是因为 tcp 并不维护数据边界导致的;
  • 粘包解决方案:需要程序员在应用层进行数据边界管理,以此区分数据边界;
    1. 特殊字符:需要转义,并且有可能和数据中的内容冲突;
    2. 数据定长:限制了数据的大小,使得其不够灵活;
    3. 应用层头部:在应用层头部中加上数据长度字段,根据该信息即可区分出数据边界;

TCP_119">基于TCP应用层协议

  • HTTP,HTTPS,SSH,Telnet,FTP,SMTP;

http://www.niftyadmin.cn/n/1578858.html

相关文章

Linux网络——网络层协议

目录IP协议协议格式数据分片地址管理IP地址私网路由选择概念过程IP协议 协议格式 4 位版本号(version):指定 IP 协议的版本,对于 IPv4 来说就是 4;4 位头部长度(header length):以 4 字节为单位,所以 IP 头部的长度是…

网络***的一般原理和方法

TCP SYN拒绝服务*** 一般情况下,一个TCP连接的建立需要经过三次握手的过程,即:1、建立发起者向目标计算机发送一个TCP SYN报文; 2、目标计算机收到这个SYN报文后,在内存中创建TCP连接控制块(TCB&#xff09…

Linux网络——链路层协议

目录以太网协议协议格式MAC地址详谈MTUARP协议协议格式概念DNS协议NAT/NAPTNATNAPTNAT缺陷NAT和代理服务以太网协议 协议格式 功能:负责相邻两个设备之间的数据传输; 48 位源端 / 对端 Mac 地址:网卡的物理硬件地址,在网卡出厂时…

java 获取请求的完整url地址

2019独角兽企业重金招聘Python工程师标准>>> 1 String urlrequest.getRequestURL()"?"request.getQueryString(); 获取域名:如:http://www.test.com/ StringBuffer url request.getRequestURL(); String tempContextUrl url.…

linux上安装memcached

我的版本为Centos Release 5.3 (Final)使用这个命令可以知道你的Linux版本1、cat /etc/redhat-release首先要安装libevent库。cd /usr/local/srccurl -O http://monkey.org/~provos/libevent-1.4.10-stable.tar.gztar xzvf libevent-1.4.10-stable.tar.gzcd libevent-1.4.10-st…

高级I/O

目录五种I/O模型阻塞I/O非阻塞I/O信号驱动I/OI/O多路转接异步I/O简单概念非阻塞I/Ofctnl函数实现SetNoBlock函数轮询方式读取标准输入select模型接口流程特性fd_set结构特点优点缺点代码封装selectpoll模型接口流程特性epoll模型概念接口流程epoll事件触发方式socket就绪条件水…

MyISAM表锁

MyISAM存储引擎只支持表锁,这也是MySQL开始几个版本中唯一支持的锁类型。随着应用对事务完整性和并发性 要求的不断提高,MySQL才开始开发基于事务的存储引擎,后来慢慢出现了支持页锁的BDB存储引擎和支持行锁的InnoDB存储引擎(实际…

linux系统部署ffmpeg视频转码环境及使用方法

环境&#xff1a;CentOS 6.2 64位 CentOS 5.8 64位 部署过程 建立yum源文件 cat << EOF > /etc/yum.repos.d/ffmpeg.repo [dag] nameDag RPM Repository for Red Hat Enterprise Linux baseurlhttp://apt.sw.be/redhat/el\$releasever/en/\$basearch/dag gpgcheck0 en…