Linux网络原理与编程(4)——第十四节 传输层协议

简介: 客户端认为连接已经建立成功了,所以就正常发数据。但是这个时候服务器并未建立连接,在收到数据之后,会向客户端发送一个含有RST的报文(reset),即希望客户端重新建立连接。

传输层是在应用层的下面一层,我们在讲解传输层协议之前,先来说一说一些前置知识即命令函数等;然后,我们本节主要来介绍UDP、TCP的报文。


前置知识

再谈端口号

端口号(Port)标识了一个主机上进行通信的不同的应用程序;


在TCP/IP协议中, 用 "源IP", "源端口号", "目的IP", "目的端口号", "协议号" 这样一个五元组来标识一个通信(可以通过


netstat -n查看);(协议号一般是指用的是哪种协议 )


通过端口号,加上我们的ip,就是先了从一个主机到另外一个主机上的通信

微信图片_20221211142426.png


端口号范围划分:


0-1023 属于知名端口;比如,


ssh服务器, 使用22端口


ftp服务器, 使用21端口


telnet服务器, 使用23端口


http服务器, 使用80端口


https服务器, 使用443


1024-65535:属于OS动态分配的端口号;可供用户使用的端口。


我们自己写一个程序使用端口号时, 要避开这些知名端口号


几个函数

netstat

netstat是一个用来查看网络状态的重要工具.


语法: netstat [选项]


功能:查看网络状态


常用选项:


-n 拒绝显示别名,能显示数字的全部转化成数字


-l 仅列出有在 Listen (监听) 的服務状态


-p 显示建立相关链接的程序名


-t (tcp)仅显示tcp相关选项


-u (udp)仅显示udp相关选项


-a (all)显示所有选项,默认不显示LISTEN相关


比如:

image.png

可以查看一下网络状态信息。


telnet

telnet [-d] [-a] [-n tracefile] [-e escapechar] [[-l user] host [port]]


用于远程登录。相关参数的意义可参考:


Telnet的命令 - Lunaa - 博客园


UDP报文

UDP协议端格式

UDP不保证可靠性。实际上,它啥也不保证。它里面只有一个校验和的东西,用于检验报文是否被破坏,当发现被破坏后,它啥也不管,直接丢弃。当然,这也保证了其高效快速。(DNS协议就是基于udp的)


UDP首部:

image.png

对应的源码:


image.png

UDP的脑袋上面还有协议,那么其就必须要解决:数据和有效载荷分离的问题。


怎么做呢?


我们知道,UDP是属于定长报头。就是说,其报头是长度是一定的。前面的8个字节就是报文,后面的就是数据。


udp拿到有效载荷后,要交付给自己上层的协议没错,但是上层的用户协议本质上是一个进程绑定在一起的。


那我怎么知道我要交给脑袋顶上的哪个进程?


在udp上有16为目的端口号。用端口号去查找进程是采用哈希的算法来去查找的。


在前面的16位源端口号就是客户端的端口号。就相当于recvfrom()函数里面的sin_port


而所要读的有效载荷就是通过udp16位长度来确定。通过这个16位udp长度来去确定判断我的这个报文有没有读完,从而确保交付给上层的是一个完整的udp报文


16位UDP长度, 表示整个数据报(UDP首部+UDP数据)的最大长度;


16位UDP校验和,用来检验报文是否完整。如果校验和出错, 就会直接丢弃;


UDP的特点

UDP传输的过程类似于寄信.


三个特点:


无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;


不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层


不返回任何错误信息;


面向数据报: 不能够灵活的 控制读写数据的次数和数量


我们来解释一下面向数据报:


应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并;(核心)


用UDP传输100个字节的数据,如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom, 接收100个字节; 而不能循环调用10次recvfrom, 每次接收10个字节;


UDP的缓冲区

UDP没有真正意义上的 发送缓冲区. 调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作;(之所以有缓冲区,是为了提高IO的效率)


UDP具有接收缓冲区. 但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致; (但是TCP不会存在这个问题)


如果缓冲区满了(实际上就是一块内存), 再到达的UDP数据就会被丢弃;(但是TCP不会存在这个问题)


UDP的socket既能读, 也能写, 这叫做 全双工


基于UDP的应用层协议:


NFS: 网络文件系统


TFTP: 简单文件传输协议


DHCP: 动态主机配置协议


BOOTP: 启动协议(用于无盘设备启动)


DNS: 域名解析协议


思考,为啥会有可靠性问题?

因为网络实际上是将我们的线变长,由于路线更长,就会有可能存在着各种问题。

不可靠有哪些情况?


发生丢包、乱序、错误、缓冲区溢出等情况。


那我们能不能设计一种协议方案,使得其能够保证可靠性呢?


当然,它就是TCP(当然tcp解决的不止这些问题)


TCP报文详解

我们本节,主要来讲TCP的报头(报文格式)


Tcp报头详解

图示:


image.png

源码:

image.png


可以看到,它们刚刚好是一一对应的。源码时图示在代码上的体现。(注意,这里的tcp协议可能比较新,这里有八个标志位)

我们接下来,来详细地讲解下TCP报文里面的每一个内容(参数)

首先对于tcp协议而言,作为传输层协议,其还是需要解决两个问题:数据包和有效载荷分离 以及我要交付给上层哪一个协议的问题。


【四位首部长度、有效载荷分离及向上交付】


1、4为首部长度即可以让我们让我们知道什么时候能将报头读完。


它表示该TCP头部有多少个32位bit(有多少个4字节) 即每个值按照四个字节来计算;


2、因此选项的大小最多为60-20 = 40个字节,首部长度最少为5。选项也是报头。


3、所以其要实现报头和有效载荷分离:先无脑式地把20个字节拿下来,然后再读四位首部长度,根据四位首部长度的值来去判别是否需要读取选项。


【接下来:】


4、根据目的端口号,经过哈希算法,找到对应的进程。


5、注意到,这里的tcp并没有读取数据的大小的参数。即这里只有数据首部长度,没有数据总长度。原因很简单,是因为其不需要。因为tcp并不需要按照数据块交付。它收到了数据只要放置在自己的缓冲区里就可以了。其是面向字节流的。上层怎么读由上层决定。


6、那我怎么检验数据的完整性呢?答案就是用16位校验和。如果你少了些许报文或者是多了报文,那么校验和一定会有问题(即校验失败)发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也包含TCP数据部分.


7、关于32位序号和确认序号:


a.关于可靠性:有绝对可靠性和相对可靠性。


(1)加入客户端给服务器发了一个消息,客户端怎么知道服务器收到了呢?原因是:服务器在收到之后,会向客户端发送一个ACK(应答)。对于客户端而言,其意义就是:我之前发送的消息服务器都收到了。


(2)但是,我们会发现,在通信过程当中,永远会有最新的一条消息没有ACK。(注意:不需要对ACK再次ACK了)


(3)所以,在互联网通信过程当中,是没有绝对可靠性的。但是有局部相对可靠性(是不是有马克思主义原理的味道了hhhh)。


(4)故:只要收到了对应的应答,认为之前的数据对方已经收到。这种机制,称为确认应答机制。(我们后面还会说)


(5)对于client而言,不论是在其将数据发送给服务器的时候数据丢失,还是服务器返回的ACK丢失,其都认为自己的数据对方没有收到,这个时候,就会有超时重传机制。 而重传到服务器之后,服务器如果在一段时间内收到了相同的报文,其也就知道自己的ACK丢了。(ACK一般不携带数据,单次简单的应答。当然当代的数据通信中也可能会携带数据)


b.那么这两个序号是干什么的呢?


(1)我们知道,即便同一时间段发送的信息,其发送的消息是串行的,但是其有可能在接收的时候乱序。(这个与路径选择有关)


(2)但是,如果我们将我们发送的每一条信息编号,那么就不用担心乱序的情况了。


(3)所以,序号是为了保证客户端->服务端的按序到达。当一条信息收到之后,会发送ACK。而客户端收到ACK之后,意味着在这个序列之前的所有信息服务器都收到了。


(4)在ACK进行确认时,其返回的确认序号应当是发送过来的原始序号+1.


(比如,我发送出去了一个序号位7的数据,那么其返回的确认序号位8.对于客户端而言,这个8的意思:8之前的数据,我服务器全部都收到了,接下来服务器想让我从8开始发。注意,即使这个时候含有确认序号6、7的ACK丢了,但是也不需要重传了,因为我收到了8,就代表着服务器端在7之前的数据都收到了。这种机制的存在,就允许了ACK有部分的丢包情况)


注意:由于TCP是全双工的,双方的通信地位对等,即一方在接收数据的同时,也可以发送数据。我接收的时候,重点关注的是32位序号,而其作为收到应答的时候,关注的是确认序号。


所以,在一个报头当中,32位序号和32位确认序号同时存在。


所以,序号主要解决的是按序到达的问题(当然,其也让确认应答更加准确和高效)。为什么要用两套,是因为tcp是全双工的。


所以,ACK和序号解决了丢包问题(引发其超时重传机制),而序号解决了乱序的问题。


8、我们之前在看sock源码的时候,发现其有一个receive_queue和write_queue,其含义就是发送缓冲区和接收缓冲区。(我们后面会继续说)


9、如果用户区的数据计算比较复杂,而传输又比较快,就有可能会出现接收缓冲区满了的问题。这个时候,如果继续传送,就有可能会出现报文丢失的问题。


10、16位窗口大小为:接收缓冲区(发送方的)的剩余空间的大小。从这里的窗口大小,就可以实现流量控制。


11、六个标志位:SYN表示该报文是一个链接请求的报文。如果没有SYN/FIN,就说明其是一个正常的数据。(FIN表示断开连接的报文)ACK表示应答确认。即该报文具有确认机制作用。


PSH即push:表示催促,希望对方将报文尽快向上交付、发送方快速清空。RST见下。UGR:打破数据的按序到达。表示当前携带的报文中需要优先被处理。(类似插队)


关于RST:


它和TCP的三次握手有关。虽然具体细节我们还没有说,但是我们已经有了三次握手建立连接的这样一个概念。试想,是不是三次握手一定能建立成功?答案当然是否定的。当第一次或者第二次的报文丢了的话,我们实际上并不担心,因为这个时候,我们的客户端并未和服务器处于连接的状态。


但是如果第三次丢了(但实际上,这种概率很小),这个时候,我们的客户端并不知道,而它自己已经处于established状态了。 (因为其已经收到了服务器的ACK)但是我们的服务器并未处于连接状态。


这个时候,客户端认为连接已经建立成功了,所以就正常发数据。但是这个时候服务器并未建立连接,在收到数据之后,会向客户端发送一个含有RST的报文(reset),即希望客户端重新建立连接。


12、16位指针就是URG的偏移量。紧急指针又叫做带外数据。(这个我们可以在recv函数的最后一个参数中手动设置。比如设置位MSG_OOB,就表示要读取这个紧急指针标志位。注意,这里的紧急指针只能插一个数据,因为其没有结束的范围标识)


(注:紧急指针不是指针,就是一个整数,表示一个偏移量)

好啦,本节内容就到这里啦~~~


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
打赏
0
0
0
0
2
分享
相关文章
Linux网络应用层协议展示:HTTP与HTTPS
此外,必须注意,从HTTP迁移到HTTPS是一项重要且必要的任务,因为这不仅关乎用户信息的安全,也有利于你的网站评级和粉丝的信心。在网络世界中,信息的安全就是一切,选择HTTPS,让您的网站更加安全,使您的用户满意,也使您感到满意。
82 18
SecureCRT & SecureFX 9.6.3 for macOS, Linux, Windows - 跨平台的多协议终端仿真和文件传输
SecureCRT & SecureFX 9.6.3 for macOS, Linux, Windows - 跨平台的多协议终端仿真和文件传输
674 4
SecureCRT & SecureFX 9.6.3 for macOS, Linux, Windows - 跨平台的多协议终端仿真和文件传输
Linux(openssl)环境:编程控制让证书自签的技巧。
总结:在Linux环境中,OpenSSL是一个非常实用的工具,可以帮助我们轻松地生成自签名证书。通过上述三个简单步骤,即可为内部网络、测试环境或开发环境创建自签名证书。但在公共访问场景下,建议购买经过权威认证机构签发的证书,以避免安全警告。
91 13
网络通讯技术:HTTP POST协议用于发送本地压缩数据到服务器的方案。
总的来说,无论你是一名网络开发者,还是普通的IT工作人员,理解并掌握POST方法的运用是非常有价值的。它就像一艘快速,稳定,安全的大船,始终为我们在网络海洋中的冒险提供了可靠的支持。
107 22
掌握网络通信协议和技术:开发者指南
本文探讨了常见的网络通信协议和技术,如HTTP、SSE、GraphQL、TCP、WebSocket和Socket.IO,分析了它们的功能、优劣势及适用场景。开发者需根据应用需求选择合适的协议,以构建高效、可扩展的应用程序。同时,测试与调试工具(如Apipost)能助力开发者在不同网络环境下优化性能,提升用户体验。掌握这些协议是现代软件开发者的必备技能,对项目成功至关重要。
如何在阿里云的linux上搭建Node.js编程环境?
本指南介绍如何在阿里云Linux服务器(Ubuntu/CentOS)上搭建Node.js环境,包含两种安装方式:包管理器快速安装和NVM多版本管理。同时覆盖全局npm工具配置、应用部署示例(如Express服务)、PM2持久化运行、阿里云安全组设置及外部访问验证等步骤,助你完成开发与生产环境的搭建。
智能体竟能自行组建通信网络,还能自创协议提升通信效率
《一种适用于大型语言模型网络的可扩展通信协议》提出创新协议Agora,解决多智能体系统中的“通信三难困境”,即异构性、通用性和成本问题。Agora通过标准协议、结构化数据和自然语言三种通信格式,实现高效协作,支持复杂任务自动化。演示场景显示其在预订服务和天气预报等应用中的优越性能。论文地址:https://arxiv.org/pdf/2410.11905。
126 6
linux命令—tree
tree是一款强大的Linux命令行工具,用于以树状结构递归展示目录和文件,直观呈现层级关系。支持多种功能,如过滤、排序、权限显示及格式化输出等。安装方法因系统而异常用场景包括:基础用法(显示当前或指定目录结构)、核心参数应用(如层级控制-L、隐藏文件显示-a、完整路径输出-f)以及进阶操作(如磁盘空间分析--du、结合grep过滤内容、生成JSON格式列表-J等)。此外,还可生成网站目录结构图并导出为HTML文件。注意事项:使用Tab键补全路径避免错误;超大目录建议限制遍历层数;脚本中推荐禁用统计信息以优化性能。更多详情可查阅手册mantree。
linux命令—tree
linux命令—cd
`cd` 命令是 Linux/Unix 系统中用于切换工作目录的基础命令。支持相对路径与绝对路径,常用选项如 `-L` 和 `-P` 分别处理符号链接的逻辑与物理路径。实际操作中,可通过 `cd ..` 返回上级目录、`cd ~` 回到家目录,或利用 `cd -` 在最近两个目录间快速切换。结合 Tab 补全和 `pwd` 查看当前路径,能显著提升效率。此外,需注意特殊字符路径的正确引用及脚本中绝对路径的优先使用。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等