文章目录
在TCP/IP协议中,传输层有两个重要的协议:TCP(传输控制协议)和UDP(用户数据报协议)。TCP用于提供可靠的数据传输,而UDP则适合用于广播或对细节控制要求不高的应用传输。
为了确保传输层协议能够正确地将接收到的数据交给相应的应用程序,TCP和UDP都引入了端口号的概念,用来识别目标应用。
一、引入端口号
可以用寄送包裹来类比这个过程。邮递员(对应网络层的IP协议)根据收件地址(目标IP地址)将包裹(数据包)送到目标计算机。包裹抵达后,传输层协议会根据附带的端口号决定最终交给哪个应用程序。
我们举一个更具体的例子来说明:假设快递单上只写了家庭住址和一个姓氏,那么就无法准确判断包裹应该交给家庭中的哪位成员。同样,如果寄送到学校或公司,只写了一个姓氏而没有明确部门或接收人的全名,快递员也会遇到困难。在实际生活中,为了避免这些问题,邮政系统也通常要求详细的地址和全名,甚至在某些情况下还需要附上联系电话,以便区分重名的收件人。
类似地,在网络传输中,端口号相当于应用程序的"全名",确保数据能够准确地交付给正确的应用。因此我们就可以根据端口号识别在传输层上一层的应用层中所需要处理的具体程序(一个程序可以使用多个端口)。
数据链路和IP中的地址,分别指的是MAC地址和IP地址。前者用来识别同一链路中不同的计算机,后者用来识别TCP/IP网络中互连的主机和路由器。在传输层中也有这种类似于地址的概念,那就是端口号。端口号用来识别同一台计算机中进行通信的不同应用程序。因此,它也被称为程序地址。
二、端口号的作用
TCP/IP的众多应用协议大多以客户端/服务端的形式运行。客户端(客户端(Client)具有客户的意思。在计算机网络中是提供服务和使用服务的一方。) 类似于客户的意思,是请求的发起端。而服务端(服务端(Server)在计算机网络中则意味着提供服务的程序或计算机。) 则表示提供服务的意思,是请求的处理端。另外,作为服务端的程序有必要提前启动,准备接收客户端的请求。否则即使有客户端的请求发过来,也无法做到相应的处理。
确认一个请求究竟发给的是哪个服务端,可以通过所收到数据包的目标端口号轻松识别。当收到TCP的建立连接请求时,如果目标端口为22,则转给sshd,如果是80则转给httpd。然后,这些守护进程会继续对该连接上的通信传输进行处理。上图是把传输协议的数据将被传递给HTTP应用层协议。
传输层协议通过端口号来识别这些正在通信的应用程序,并确保数据准确地传递给相应的程序。
每个运行的程序都会被分配一个唯一的端口号,TCP和UDP协议通过这些端口号来区分不同的应用。例如,Web浏览器使用HTTP服务时通常使用端口80 ,而SSH客户端通常使用端口22。传输层协议根据目标端口号,确保数据包能准确地到达运行该端口的应用程序,使得同一台计算机能够同时进行多种网络通信而不会发生混淆。
但是仅凭借端口号识别某一个通信是不够的。
上图中的通信是在①和②的通信是在两台计算机上进行的。它们的目标端口号相同,都是80。
例如打开两个Web浏览器,同时访问两个服务器上不同的页面,就会在这个浏览器跟服务器之间产生类似前面的两个通信。在这种情况下也必须严格区分这两个通信。因此可以根据源端口号加以区分。
而中③跟①的目标端口号和源端口号完全相同,但是它们各自的源IP地址不同。
此外,还有一种情况上图中并未列出,那就是IP地址和端口全都一样,只是协议号(表示上层是TCP或UDP的一种编号)不同。这种情况下,也会认为是两个不同的通信。
因此TCP/IP或UDP/IP通信中可以采用一个五元组来识别一个通信。它通常包括以下信息:
- 源IP地址: 数据报的发送者的IP地址。
- 源端口号: 发送者的端口号,用于标识源主机上的具体应用。
- 目的IP地址: 数据报的接收者的IP地址。
- 目的端口号: 接收者的端口号,用于标识目标主机上的具体应用。
- 协议号: 使用的传输协议(如TCP、UDP等)的标识符。
只要其中某一项不同,就被认为是其他通信。即这些信息共同定义了网络中的一个会话或连接。通过 netstat -n
命令,可以查看当前系统上的网络连接信息,包括IP地址和端口号等。
例如,运行 netstat -n
可能会显示如下内容:
shell
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 192.168.1.10:54321 192.168.1.20:80 ESTABLISHED
udp 0 0 192.168.1.10:12345 192.168.1.20:53 ESTABLISHED
在这个例子中:
- 源IP地址是
192.168.1.10
- 源端口号是
54321
或12345
- 目的IP地址是
192.168.1.20
- 目的端口号是
80
(HTTP)或53
(DNS)
Linux下cat /etc/services
命令可以用于查看知名端口号。
三、端口号的确定
在实际进行网络通信时,要事先确定端口号。确定端口号的方法分为两种:
- 已知的标准端口号(Well-known Ports)
这些端口号通常是由特定的网络服务或协议所使用的,并且已被标准化。它们的范围为0到1023,例如:
- HTTP 使用端口 80
- HTTPS 使用端口 443
- FTP 使用端口 21
- SSH 使用端口 22
这些端口号是预先定义好的,客户端在与服务器通信时,通常不需要明确指定端口号,因为大家对这些标准端口已广泛了解。
- 动态或私有端口号(Dynamic/Private Ports)
这些端口号由应用程序或操作系统动态分配,通常用于客户端与服务器之间的临时通信。它们的范围为1024到65535**。服务端有必要确定监听端口号,但是接受服务的客户端没必要确定端口号。**例如,当一个客户端启动连接时,操作系统可能会随机为它分配一个未使用的端口号,这样可以避免与其他应用程序产生冲突。这些端口号通常用于短期通信,在通信完成后可以重新分配。
在这种方法下,客户端应用程序可以完全不用自己设置端口号,而全权交给操作系统进行分配。操作系统可以为每个应用程序分配互不冲突的端口号。例如,每需要一个新的端口号时,就在之前分配号码的基础上加1。这样,操作系统就可以动态地管理端口号了。
根据这种动态分配端口号的机制,即使是同一个客户端程序发起的多个TCP连接,识别这些通信连接的五元组也不会全部相同。
端口号由其使用的传输层协议决定。因此,不同的传输协议可以使用相同的端口号。例如,TCP与UDP使用同一个端口号,但使用目的各不相同。这是因为端口号上的处理是根据每个传输协议的不同而进行的。
当数据从传输层进入IP层时,首先会检查IP首部中的协议号 ,再根据该协议号将数据传递给相应的协议模块。例如,如果协议号指示为TCP,数据将被传递给TCP模块 进行处理;如果协议号指示为UDP,则数据会交给UDP模块进行处理。因此,即使相同的端口号被TCP和UDP同时使用,数据处理仍然是各自独立的,不会产生冲突或干扰。
那么操作系统是如何根据端口号,把数据发送给对应的客户端进程呢?
操作系统将数据发送给客户端进程的过程涉及以下几个步骤:
-
数据到达网络接口
当数据报到达服务器的网络接口时,网络接口卡(NIC)会通过硬件中断通知CPU。
-
数据报被内核处理
- 接收数据报:操作系统内核的网络栈会接收数据报,并从链路层开始逐层处理,直到传输层。
- 解析数据报:在传输层,内核会解析数据报的头部信息,包括源端口号、目的端口号、协议类型等。
-
根据端口号找到对应的进程:以下是操作系统如何根据端口号将数据发送给正确的客户端进程:
- 查找端口号 :内核会根据数据报的目的端口号在内部维护的一个查找表(哈希表)中查找。这个查找表通常称为
socket table
或port table
,它记录了当前系统中所有正在监听的端口号以及它们对应的套接字描述符。 - 套接字描述符:每个套接字都有一个唯一的描述符,它是由内核在创建套接字时分配的。这个描述符用于内核与进程之间的交互。
- 绑定关系 :当一个进程通过
bind
系统调用绑定一个端口号时,内核会在这个查找表中为该端口号创建一个条目,并将该端口号与进程的套接字描述符关联起来。 - 数据传递:当内核找到了对应端口号的套接字描述符后,它会将数据报的内容复制到该套接字的接收缓冲区中。
- 查找端口号 :内核会根据数据报的目的端口号在内部维护的一个查找表(哈希表)中查找。这个查找表通常称为
-
通知客户端进程
- 唤醒进程 :如果客户端进程正在等待接收数据(例如,调用了
recv
、recvfrom
或类似的系统调用),内核会将数据放入进程的缓冲区,并唤醒该进程。 - 设置文件描述符为可读 :如果客户端进程没有阻塞在接收调用上,内核会将对应的文件描述符标记为"可读",这样当进程下次进行轮询(例如使用
select
、poll
或epoll
)或阻塞在读取操作上时,可以读取到数据。
- 唤醒进程 :如果客户端进程正在等待接收数据(例如,调用了
-
客户端进程读取数据
客户端进程通过系统调用(如
read
、recv
、recvfrom
等)从其套接字的接收缓冲区中读取数据。
这个过程确保了数据能够根据端口号准确地发送到正确的进程。值得注意的是,这一机制适用于TCP和UDP协议,尽管UDP是无连接的,但数据报的发送和接收依然依赖于端口号来正确地路由到相应的进程。