网络层为我们提供了从主机到主机的传输能力,这种传输我们称为 点到点 传输。借助网络层,网络中的一台主机,可以向其他任一主机发送数据。
图中有两台主机,左边是一台普通的 PC ,右边是一台服务器,这是一种可以提供网络服务的主机。为访问服务器提供的网络服务,PC 必须与服务器进行通信。
通过网络层协议,例如 IP 协议,PC 与服务器都可以向对方发送数据。如果 PC 和服务器都只运行一个应用程序,那么网络层可以工作得很好。但这是不可能的!
进程间通信
无论是普通主机还是服务器,一般都不止运行一个应用进程。我们举个例子:
- 服务器上可能运行着多个服务进程,包括:授时服务、直播服务等等;
- PC 上也可能运行着多个应用进程,包括:校时工具、视频播放器等等;
为了观看直播,PC 上的播放器进程必须和服务器上的直播服务进程进行通信;为了校正时间,PC 上的时间同步进程必须和服务器上的时间服务进程进行通信。
换言之,我们需要一种 从进程到进程 的传输能力。
端口
那么,如何实现从进程到进程的传输能力呢?其实很简单,我们可以在网络层的基础之上,引入新的传输层,专注于进程间通信。
传输层的通信单元一般叫做 段 ( segment ),也分为头部和数据两个部分。其中,头部会保存发送进程和接收进程等相关信息。那么,保存进程的什么信息好呢?
你可能会想到进程号,但进程号其实不是一个好选择:一方面,进程号类型和数值范围都没有标准,可能因操作系统而有所差异;另一方面,进程号可能会变。
如果服务端进程发生重启,它的进程号就会发生改变。这时所有客户端都要进行调整,以便向新的进程号发送数据,显然是不合理的。
实际上,传输层引入了 端口 ( port )的概念,用来区分不同的通信端点。如果将主机想象成一栋建筑物,那端口就是它上面的房间门:
一台主机上可以有很多个通信端口,应用进程可以关联到一个或多个端口。当进程需要发送数据时,它必须申请一个端口,数据从该端口发送出去;当某个端口有数据到达时,操作系统负责将数据提交给对应的应用进程。
这种从进程到进程的传输能力,可以叫做 端到端 传输。
我们可以通过主机地址,比如 IP 地址,来确定一个 点 ,主机地址加上端口,则可以确定一个 端 。
点到点 | 端到端 |
---|---|
从主机到主机 | 从进程到进程 |
地址 <==> 地址 | 地址:端口 <==> 地址:端口 |
至于端口号,一般可以根据自己需要,灵活选用。但为了方便沟通协作,也形成了一些约定俗成的惯例,比如 Web 服务一般用 80 或 443 端口,邮件传输服务一般用 25 端口。这就是所谓的 知名端口 。
服务 | 端口 |
---|---|
FTP文件传输 | 20 、 21 |
SSH安全远程登录 | 22 |
SMTP邮件传输 | 25 |
DNS域名系统 | 53 |
Web | 80 、 443 |
通信过程
传输层的通信单元是 段 ( segment ),它负责封装数据和通信双方的端口号。
段需要借助网络层提供的点对点通信能力,由网络层包(比如 IP 包)携带,传输到目标主机。当段到到目标主机后,操作系统可以根据端口号,将数据提交给对应的进程。
以时间同步进程请求时间服务为例,通信过程大致如下:
- 时间同步进程需要向服务进程发请求数据,它先申请了一个端口,并通过该端口将数据提交给操作系统。
- 操作系统将数据封装成一个段,段的头部会包含双方的端口号。这个段需要先发给服务器,服务器收到后根据端口号即可将数据提交给对应的进程。
- 由于 IP 等网络层协议已经具备了主机间通信能力,因此可以将这个段搭载在网络层包中,发给服务器。网络层包需要经过若干条路由的转发,才能最终到到服务器。此外,网络层包每次转发时,都需要搭载在数据链路层帧中,发给下一节点。
- 网络层包来到服务器,服务器根据包头部中的协议字段,将承载在包数据中的段取出,提交给传输层来处理。
- 传输层收到这个段后,根据端口号,找到目标进程。
- 操作系统将段中的数据,提交给对应的时间服务进程。
在现行的 TCP/IP 协议栈中,有两个常用的传输层协议:
- UDP ,无连接的数据报式协议;
- TCP ,面向连接的流式协议;
下一小节,我们开始学习 UDP 协议。
【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注: