文章目录
- 一、传输层的意义
- 二、端口号
- 2.1 五元组标识一个通信
- 2.2 端口号范围划分
- 2.3 知名端口号
- 2.4 绑定端口号数目问题
- 2.5 pidof & netstat命令
- 三、UDP协议
- 3.1 UDP协议格式
- 3.2 如何理解报头?
- 3.3 UDP协议的特点
- 3.4 UDP缓冲区
- 3.5 UDP传输最大长度
一、传输层的意义
数据从应用层下来并不是直接发送给网络,而是从网络协议栈自顶向下传输,经过传输层、网络层,数据链路层,最后通过硬件发送到网络。
前两章讲了应用层的两个协议:HTTP和HTTPS,应用层的主要目的是为了保证数据的安全,而传输层的目的则是为了保证数据能够可靠地传送到目标地址。
二、端口号
2.1 五元组标识一个通信
端口号是用来标识一个主机上进行网络通信的不同的应用程序。
因为主机上存在不同的服务,从网络中获取的数据在进行向上交付时,在传输层就会提取出该数据对应的目的端口号,进而确定该数据应该交付给当前主机上的哪一个服务进程(应用层)。即一台主机上可以同时部署端口号不同的服务。
在TCP/IP协议中,用“源IP地址”,“源端口号”,“目的IP地址”,“目的端口号”,“协议号”这样一个五元组来标识一个通信。
举个例子,我们打开浏览器用不同的页面访问CSDN,虽然源IP地址是一样的,但是源端口号不同,就表示两个不同的通信。通过这个五元组,服务器就能准确的区分请求从哪里来的。
- 通信流程
1️⃣ 先提取出数据当中的目的IP地址和目的端口号,确定该数据是发送给当前服务进程的。
2️⃣ 然后提取出数据当中的协议号,为该数据提供对应类型的服务。
3️⃣ 最后提取出数据当中的源IP地址和源端口号,将其作为响应数据的目的IP地址和目的端口号,将响应结果发送给对应的客户端进程。
2.2 端口号范围划分
端口号的长度是16位,因此端口号的范围是0 ~ 65535:
0 ~ 1023:知名端口号。比如HTTP,FTP,SSH等这些广为使用的应用层协议,它们的端口号都是固定的。(类比120或110)
1024 ~ 65535:操作系统动态分配的端口号。客户端程序的端口号就是由操作系统从这个范围分配的。
2.3 知名端口号
有些服务器是非常常用的,这些服务器的端口号一般都是固定的:
ssh服务器——22端口。
ftp服务器——21端口。
telnet服务器——23端口。
http服务器——80端口。
https服务器——443端口。
- 查看端口号
可以vim /etc/services
文件,该文件是记录网络服务名和它们对应使用的端口号及协议。
2.4 绑定端口号数目问题
- 一个端口号是否可以被多个进程绑定?
不行! 因为端口号的作用就是标识唯一的一个进程。如果绑定了多个进程怎么找到对应的进程呢?所以如果绑定一个已经被绑定的端口号,就会出现绑定失败的问题。
- 一个进程能不能绑定多个端口号?
可以! 比方说绑定了两个端口号A和B,这两个端口号标识的是同一个进程 ,这与端口号用来标识进程的唯一性不冲突。
2.5 pidof & netstat命令
- pidof命令
查看进程的pid
配合kill杀死一个进程:
这里的xargs
是用来把从管道读取的数据拼接到kill -9的后边。
- netstat命令
用来查看网络状态
选项:
n:拒绝显示别名,能显示数字的全部转换成数字。
l:仅列出处于LISTEN(监听)状态的服务。
p:显示建立相关链接的程序名。
t(tcp):仅显示tcp相关的选项。
u(udp):仅显示udp相关的选项。
a(all):显示所有的选项,默认不显示LISTEN相关。
查看TCP相关的网络信息时,一般选择使用nltp
组合选项。
查看UDP相关的网络信息时,一般选择使用nlup
组合选项。
三、UDP协议
3.1 UDP协议格式
16位源端口号:表示数据从哪里来。
16位目的端口号:表示数据要到哪里去。
16位UDP长度:表示整个数据报(UDP首部+UDP数据)的长度。
16位UDP检验和:如果UDP报文的检验和出错,就会直接将报文丢弃。
我们在用户层使用端口一直用的是uint16_t
,其根本原因就是因为传输层协议当中的端口号就是16位的。我们send数据并不是直接发送到网络里,而是发给了传输层。
- 如何将报头和有效载荷分离?
UDP采用的是固定报头,UDP的报头当中只包含四个字段,每个字段的长度都是16位,总共8字节。所以直接提取前八个字节就是报头,其他的就是有效载荷。
- UDP如何分用?(有效载荷交给上层的哪一个协议?)
应用层每个进程都绑定有端口号,UDP就是通过报头当中的目的端口号来找到对应的应用层进程的,把有效载荷交出去。
3.2 如何理解报头?
其实这里的报头就是一种结构化数据对象:
struct udp_hdr
{
uint16_t src_port;// 源端口
uint16_t dsc_port;// 目的端口
uint16_t length;// UDP长度
uint16_t check;// 校验和
};
- UDP数据封装过程:
首先要知道应用层sendto数据是发给传输层的。
创建一块内存,计算出有效载荷的起始地址,拷贝有效载荷,强转填写报头部分。最后形成UDP报文。
- UDP数据分用过程:
因为是定长报头,直接取出目的端口号,把有效载荷向上交付给指定协议(进程)。
3.3 UDP协议的特点
无连接:知道对端的IP和端口号就直接进行数据传输,不需要建立连接。
不可靠:没有确认机制,没有重传机制;如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息。
面向数据报:保证能读到完整的报文。
- 面向数据报
这里就像快递一样,别人发了三个快递,那么我们一定要收到三个,不会收到一个,一个半。如果只有一个包裹,我们也不能只拿走一半。
发送了一个报文,要么不读,要么recvfrom等到读取完一整个报文返回。
如果发送端调用一次sendto,发送100字节,那么接收端也必须调用对应的一次recvfrom,接收100个字节;而不能循环调用10次recvfrom,每次接收10个字节。
3.4 UDP缓冲区
1️⃣ UDP没有真正意义的发送缓冲区,因为它没有可靠机制,不需要把数据暂存起来。它直接把数据拷贝到内核,由内核将数据传给网络层协议进行后续的传输动作。
2️⃣ UDP是有接收缓冲区的,但是不能保证收到的顺序就是发送的顺序。而且如果缓冲区满了,再来的UDP数据就会被丢弃。
而UDP在读的过程中也能写,所以是全双工的。
- 为什么UDP要有缓冲区?
如果UDP没有接收缓冲区,那么就要求上层及时将UDP获取到的报文读取上去,如果一个报文在UDP没有被读取,那么此时UDP从底层获取上来的报文数据就会被迫丢弃。
3.5 UDP传输最大长度
UDP协议报头当中的UDP最大长度是16位的,因此一个UDP报文的最大长度是64K(包含UDP报头的大小)。
如果要传输大于64k的数据,就需要在应用层进行手动分包,多次发送,并在接收端进行手动拼装。