目录
知识引入:
端口号:
当应用层获得一个传输过来的报文时,这时数据包需要知道,自己应该送往哪一个应用层的服务,这时就引入了“端口号”,通过区分同一台主机不同应用程序的端口号,来保证数据传输的可靠性!
而我们在之前的学习知道,ip地址是唯一的地址标识,那么我们借助ip地址和端口号是不是就能找到网络中唯一的一台主机?答案是肯定的,这也就是传输层协议存在的意义之一!
在TCP/IP协议中, 用 "源IP", "源端口号", "目的IP", "目的端口号", "协议号" 这样一个五元组来标识一个通信
如图我们通过源ip和源端口号,就知道信息是从哪来的,知道了目的ip和目的端口号就知道信息是去往哪里的。那么就能够实现网络中唯二的两个进程通过网络进行进程间通信了!!!
端口号划分:
- 0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是固定的.
- 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的.
查看网络连接状态命令:
// -ntpl n-带数字 t-TCP协议 p-服务名称 l-只查看listen服务
sudo netstat -ntpl
// ss命令也可以查网络服务
ss -nltp
常用选项:
- n 拒绝显示别名,能显示数字的全部转化成数字l 仅列出有在 Listen (监听) 的服務状态
- p 显示建立相关链接的程序名
- t (tcp)仅显示tcp相关选项
- u (udp)仅显示udp相关选项
- a (all)显示所有选项默认不显示LISTEN相关
1.UDP协议
1.1.UDP协议端格式
如图:UDP协议报文前8字节为UDP协议的报头,后面的即为有效载荷。
我们知道网络传输需要解决的四个问题:
- 报文如何将报头和有效载荷分离
- 有效载荷如何向上交付给对应应用层程序
- 报文内容是否完整
- 报文内容是否有误
联系UDP协议格式,我们发现以上四个问题对应:
- 解析固定报头长度来分开报头和有效载荷
- 再通过目的端口号将有效载荷交付给应用层服务
- 16位UDP长度对应着报文的长度(当长度不符时,直接丢包)
- 而16位UDP检验和检测是否在传输过程中出现0变成1、1变成0
通过UDP协议报头的设计,那么我们就解决了网络传输的4个问题,而在这里我们也能理解报头(协议)是一个结构化字段。
struct UdpHeader
{
uint32_t src_port:16;
uint32_t dest_port:16;
uint32_t length:16;
uint32_t check_sum:16;
}
又因为传输层是实现在操作系统中,也就是操作系统需要维护获得的UDP报文,需要对UDP报文实现“先描述再组织”
如图为:发送端如何形成UDP报文结构示意
- 首先应用层需要存在报头的结构化对象和管理报文信息的sk_buff结构化对象
- 当用户准备通过sendto进行发送时,通过bind函数将对应端口号写入进报头信息中,另外有效载荷写入sk_buff指向的缓冲区中,这时有tail执行有效载荷的尾,_data指向有效载荷的头部(_data-_tail即为有效载荷的长度)
- 传输层首先将_data向左移动8个字节,给UDP的报头放入,接着完善报头中的报文长度信息和check_num(通过二进制位运算)
- 最终就形成了一段UDP报文
因为系统中可能存在多份待发送的UDP报文,所以我们需要通过数据结构来管理这些报文。最终UDP协议就实现了!!!
当接收端接收到UDP报文时:
- 先分开报头和有效载荷(通过分离前8个字节数据),然后读取报头中的报文长度,就能找到有效载荷
- 通过对有效载荷进行二进制位运算,判断前后的check_num和为0,不为0就丢弃报文。
- 获取到报文后就可以通过对应端口,找到接受端的应用层服务
最终我们就完成了UDP通信!!!
1.2.UDP的特点
UDP传输的过程类似于寄信,为什么这么说呢,这和UDP的特点有关
- 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;
- 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层 返回任何错误信息;
面向数据报: 不能够灵活的控制读写数据的次数和数量;(应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并; )
我们在传输报文时,只要知道对端的地址就可以进行传输,不需要事先通知对方才能够寄信。另外,当我们写信出去后我们就无法获得这封信的状态,除非他被对方收到,并且返回收到信息给你。最终,信的寄和读都是一次的行为,跟你信里面写了多少内容无关,是一个整体。
值得注意的是:UDP协议允许报文最长为16位,也就是64k的大小,当我们传输的内容大于64k时,我们就需要多次将数据分为64kb的报文,接着不断传输。
2.TCP协议
TCP协议的学习任务十分繁重,建议慢慢品。
2.1.TCP协议格式
如图TCP协议格式明显复杂于UDP协议,接下来我们学习一下TCP协议中的重要字段。
ps:如果发现这些重要字段的学习过于抽象,可以大概记忆一下概念,结合下面的TCP机制学习!
选项
表示TCP协议标准报头携带的额外信息,用于增强TCP协议的功能和灵活性,大小为0-40字节(与4位首部长度有关)。
4位首部长度(4位TCP报头长度)
4位首部长度对应着0000-1111,即【0,15】,并且1单位对应着4个字节,所以最终4为首部长度对应着【0,60】字节。
在实际应用中4位首部长度是用来分离协议报头和有效载荷的!
- 首先当应用层获取到报文时,截取前20字节的标准报头,访问到4位首部地长度
- 获取到4位首部长度,如果4位首部长度为20(表示选项为空),那么后续数据就是有效载荷。如果大于20字节,说明需要截取大于部分之后为有效载荷
6位标志位
- URG: 紧急指针是否有效(紧急任务报文)
ACK: 确认号是否有效(确认报文)
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走(询问报文段)
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段
SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段
FIN: 通知对方, 本端要关闭了我们称携带FIN标识的为结束报文段
一个标志位对应着一个比特位!而6位标志位是为了定义报文的类型,因为服务器一般只有一个,而获取服务的客户端有无数个,那么服务器在通信时就需要标识不同的报文类型
16位窗口大小
窗口大小字段用于告诉接收端,发送端目前还有多少数据没有收到确认,还可以发送多少数据。用于实现流量控制!!!
32位序号和32位确认序号
32位序号用来保证数据的按序到达,32位确认序号用来保证发送端发送的哪些数据已经被接受到了(该序号之前的数据,全部收到)。
16位紧急指针
表示紧急数据在有效载荷中的偏移量。但是大小只有一字节
需要结合6位标志位中的URG标志
2.2.不同类型报文和TCP通信
我们知道在TCP协议字段中存在6位的标志位,而这6位的标志位对应着6种类型的报文,分别在TCP通信的不同场景中发挥着各自的作用。
因为一个服务器会处理大量客户端的报文请求,所以我们也需要学习不同类型的报文请求!!!在这部分内容中我们主要讲解URG、RSH、RST标志位对应字段的报文,其他标志位都是比较常见的我们会在TCP整个模块或多或少会有提及……
处理紧急任务报文---URG
在接收端,报文的维护是通过链表式的队列,也就是处理任务时需要遵守先进先出原则,当出现一些紧急任务时(比如:客户端发现传输的大文件数据传错了,这时取消传输),就需要将这个任务及时的关闭,那么就需要将该报文插入