UNIX/Linux网络编程基础:图解TCP/IP协议栈

时间:2021-09-23 01:30:06

目录

1、主机到网络层协议:以太网协议

2、IP协议

3、网际控制报文协议(ICMP)

4、传输控制协议(TCP)

5、用户数据报文协议(UDP)

6、流控制传输协议(SCTP)

7、地址解析协议(ARP)

 

联网的各个终端之间能否进行交互的软件基础是网络协议栈,目前主流的网络协议栈是TCP/IP协议栈

UNIX/Linux网络编程基础:图解TCP/IP协议栈

UNIX/Linux网络编程基础:图解TCP/IP协议栈

UNIX/Linux网络编程基础:图解TCP/IP协议栈

UNIX/Linux网络编程基础:图解TCP/IP协议栈

1、主机到网络层协议:以太网协议

主机到网络层主要为IP协议和ARP协议提供服务、发送和接收网络数据报。本层中由于要实现跨网和跨设备的互通,有很多的实现方式,这里我们只关注以太网的实现方式。

以太网是由数字设备公司(Digital Equipment Corp,DEC)、英特尔公司和Xerox公司在1982年公布的一个标准。目前TCP/IP技术主要基于以太网标准。以太网标准采用一种带冲突检测的载波监听多路接入(CSMA/CD,Carrier Sense,Multiple Access with Collision Detection)的方法进行传输。以太网的封包格式如下图所示,它在IP数据的基础上增加了共14个字节。

UNIX/Linux网络编程基础:图解TCP/IP协议栈

源地址和目的地址:以太网用48bits(6字节)来表示源地址和目的地址。这里的源地址和目的地址指的是硬件地址,例如网卡的MAC地址。

在地址后面是两个字节的表示类型的字段,例如0800表示此帧数据为IP数据,0806表示此帧数据为ARP请求。

类型字段之后是数据,对于以太网,规定数据段的大小范围是46-1500个字节,如果数据不足46个字节,则要用空字符填满。

注意:数据段的长度有一个最大值,以太网为1500,这个特性称为MTU,即最大传输单元。如果IP层有一个要求传送的数据长度比MTU大,那么在IP层要对数据进行分片,使得每个片都小于MTU。

CRC字段用于对帧内数据进行校验,以保证数据的正确性,通常由硬件实现(例如在网卡设备中实现)。

注意:以太网的头部长度为14的特点在某些平台的实现上会造成效率上的问题,例如4字节对齐的平台,在取得IP数据时通常会重新复制一次。

2、IP协议

IP协议是TCP/IP协议中最重要的协议,它为TCP、UDP、ICMP等协议提供传输的通路。IP层的主要目的是提供子网的互联,形成较大的网络,使不同的子网间能够传输数据。IP层主要有如下作用:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

IP数据的格式如下图所示,不包含选项字段,其头部长度为20字节。

UNIX/Linux网络编程基础:图解TCP/IP协议栈

源IP地址和目的IP地址:源地址表示发送数据的主机或设备的IP地址,目的地址表示接收数据的主机IP地址。这两个字段均为32位。本字段的目的在于识别Internet上的主机。

3、网际控制报文协议(ICMP)

ICMP协议用于传递差错信息、时间、回显、网络信息等报文控制数据。

ICMP协议的数据位于IP字段的数据部分,它是在IP报文的内部被传送的。

UNIX/Linux网络编程基础:图解TCP/IP协议栈

ICMP报文的数据格式如下图所示:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

ICMP的报文类型由类型和代码两个字段共同决定。

4、传输控制协议(TCP)

传输控制协议(Transmission Control Protocol),简称TCP协议,它在原有IP协议的基础上,增加了确认重发、滑动窗口和复用/解复用等机制,提供一种可靠的、面向连接的、字节流服务

首先,TCP提供客户和服务器的连接。

其次,TCP提供可靠性。(数据的可靠投递或故障的可靠通知)并不能保证数据一定会被对方端点接收。

第三,TCP通过给所发送数据的每一个字节关联一个序列号进行排序(sequencing)。

第四,TCP提供流量控制(flow control)。TCP总是告诉对端它能够接收多少字节的数据,这称为通告窗口(advertised window)。该窗口在任何时刻都指出接收缓冲区中的可用空间,从而确保发送端发送的数据不会溢出接收缓冲区。该窗口时时刻刻动态地变化着:当接收来自发送端的数据时,窗口大小减小;而当接收端应用进程从缓冲区中读取数据时,窗口大小增大。

最后,TCP的连接是全双工的(full duplex)。

TCP的特点:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

TCP的数据格式:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

UNIX/Linux网络编程基础:图解TCP/IP协议栈

源端口号和目的端口号:这两个字段均为16位的长度,表示发送端和接收端的端口,用于确认发送端和接收端的应用程序发送端的IP地址和端口号以及接收端的IP地址和端口号可以确认一个在Internet上的TCP连接。

UNIX/Linux网络编程基础:图解TCP/IP协议栈

TCP的封装解封过程:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

建立TCP连接的三次握手:

(1)服务器必须准备好接受外来的连接。这通过调用socket、bind和listen函数来完成,称为被动打开(passive open)。

(2)客户通过调用connect进行主动打开(active open)。这引起客户TCP发送一个SYN(表示 同步)分节(segment),它告诉服务器客户将在(待建立的)连接中发送数据的初始序列号。一般情况下SYN分节不携带数据,它只含一个IP头部、一个TCP头部及可能有的TCP选项。

(3)服务器必须确认客户的SYN,同时自己也得发送一个SYN分节,它含有服务器将在同一连接中发送的数据的初始序列号。服务器以单个分节向客户发送SYN和对客户SYN的ACK(表示确认)。

(4)客户必须确认服务器的SYN。

连接建立的过程至少需要交换三个分组,因此称之为TCP的三路握手(three-way handshake)。如下图所示:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

上图中给出的客户的初始序列号为J,而服务器的初始序列号为K。在ACK里的确认号为发送这个ACK的一端所期待的对端的下一个序列号。

建立TCP连接的日常系统可类比电话系统,客户(呼叫者)、服务器(被呼叫者):

soket函数等同于有电话可用。呼叫者和被呼叫者都要有一个电话。

bind函数用于告诉其他人你的电话号码,让他们可以向你打电话。

listen函数用于打开电话振铃,它使得你可以听到一个外来的电话。

accept函数等同于被呼叫者接电话,而且accept函数有来电显示功能,可以显示呼叫者的电话号码。

释放TCP连接的四次握手:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

TCP状态转换图:

TCP连接的建立和终止可以用状态转换图(state transition diagram)来说明。

TCP为一个连接定义了11种状态(nestat命令的输出包括这些状态,它是调试客户/服务器应用程序有用的工具),并且TCP规则规定如何基于当前状态及在该状态下接收的分节从一个状态转换到另一个状态。

我们用实线表示客户的状态转换,虚线表示服务器的状态转换。

UNIX/Linux网络编程基础:图解TCP/IP协议栈

注意,执行主动关闭的那一端(客户端)进入TIME_WAIT状态。该端点停留在这种状态的持续时间是最长分节生命期(maximum segment lifetime,简称MSL)的两倍,有时候称之为2MSL。

5、用户数据报文协议(UDP)

UDP是一种基于IP协议的无连接、不可靠网络传输协议。

UNIX/Linux网络编程基础:图解TCP/IP协议栈

UDP协议把应用程序需要传递的数据发送出去,不提供发送数据包的顺序;接收方不向发送方发送接收的确认信息,如果 出现丢包或者重包的现象,也不会向发送方发送反馈,因此不能保证使用UDP协议的程序发送的数据一定到达了接收方或者到达接收方的数据顺序和发送方的一致性。

使用UDP协议传输数据的应用程序,必须自己构建发送数据的顺序机制和发送接收的确认机制,以此来保证发送数据的正确到达,保证接收数据的顺序与发送数据的一致性,也就是说应用程序必须根据UDP的缺点提供解决方案。

UDP协议相对于TCP协议执行时的速度要比TCP快得多,因为UDP协议简单的多,对系统造成的负载低。

UDP的数据格式:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

源端口号和目的端口号分别是一个16位的字段,用来表示发送方和接收方的UDP端口。

UDP数据的传输过程:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

每个UDP数据报都有一个长度。如果数据报正确地到达其最终目的地,那么数据报的长度将随数据一道传送给接收端应用程序。而TCP是一个字节流(byte stream)协议,没有任何记录边界。

6、流控制传输协议(SCTP)

SCTP提供的服务与UDP和TCP提供的类似。SCTP在客户和服务器之间提供关联,并像TCP那样给应用层提供可靠性、排序、流量控制以及全双工的数据传输服务

SCTP中使用“关联”取代“连接”是为了避免这样的内涵:一个连接只涉及两个IP地址之间的通信。而一个关联指代可能因为多宿(multihoming)而涉及不止一个地址的两个系统之间的一次通信会话。

与TCP不同的是,SCTP是面向消息的(message-oriented)。它提供各个记录的按序投递服务。与UDP一样,由发送端写入SCTP的每个记录的长度随数据一道传递给接收端应用程序。

SCTP能够在所连接的端点之间提供多个流,每个流各自可靠地按序投递消息。一个流上某个消息的丢失不会阻塞同一关联其他流上消息的投递。这种做法与TCP正好相反,就TCP而言,在单一字节流中任何位置的字节丢失都将阻塞该连接上其后所有数据的投递,知道该丢失被修复为止。

SCTP还提供多宿特性,使得单个SCTP端点能够支持多个IP地址。该特性可以增强针对网络故障的健壮性。一个端点可以有多个冗余的网络连接,每个连接所在的网络有各自接入因特网基础设施的通途。通过把端点切换到已与SCTP关联相关的另一个地址,SCTP能够绕过发生在跨越因特网途中某个网络或通路上的故障。

与TCP一样,SCTP也是面向连接的,因此也有关联的建立与终止的握手过程。不过SCTP的握手过程不同于TCP。

SCTP的四路握手:

(1)服务器必须准备好接受外来的关联。这通过调用socket、bind和listen函数来完成,称为被动打开(passive open)。

(2)客户通过调用connect或者发送一个隐式打开关联的消息进行主动打开(active open)。这使得客户端发送一个INIT消息(表示初始化),它告诉服务器客户的IP地址清单、初始序列号、用于标识本关联中所有分组的起始标志(initiation tag)、客户请求的外出流的数目以及用户能够支持的外来流的数目。

(3)服务器对客户的INIT消息确认以一个INIT ACK消息,其中含有服务器的IP地址清单、初始序列号、起始标志、服务器请求的外出流的数目、服务器能够支持的外来流的数目以及一个状态魔饼(state cookie)。状态魔饼包含服务器用于确信本关联有效所需的所有状态,它是数字化签名过的,以确保其有效性。

(4)客户以一个COOKIE ECHO消息回射服务器的状态魔饼。除COOKIE ACK块外,该消息可能还捆绑了用户数据块。

(5)服务器以一个COOKIE ACK消息确认客户回射的状态魔饼是正确的,本关联从而建立。该消息也可能还捆绑了用户数据块。

以上交换过程至少需要四个消息,因此称之为SCTP的四路握手(four-way handshake)。如下图:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

四路握手过程结束时,两端各自选择一个主宿地址(primary destination address)。当不存在网络故障时,主宿地址将用作数据发送的缺省目的地。

SCTP关联终止:

SCTP不像TCP那样允许半关闭的关联。当一端关闭某个关联时,另一端必须停止从应用进程传入新的用户数据并发送。关联关闭请求的接收端发送完已经排队的数据(如果有的话)后,执行关联的关闭。如下图所示:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

SCTP没有类似TCP的TIME_WAIT状态,因为SCTP使用了验证标志。

7、地址解析协议(ARP)

在以以太网为基础的局域网中,每个网络接口都有一个硬件地址,这是一个48bit的值,用来标识不同的以太网设备,在局域网中必须知道网络设备的硬件地址才能向目的主机发送数据。而在网际网中数据传输的目的地址是IP地址,数据要能够正确地传输,必须建立IP地址和硬件地址的对应关系,ARP协议就是起这种作用的。

ARP协议为IP地址到硬件地址提供动态的映射关系。ARP高速缓存维持这种映射关系,其中存放了最近IP地址到硬件地址的映射记录,高速缓存中的每项记录的生存时间为20分钟,开始时间从映射关系建立时算起。

UNIX/Linux网络编程基础:图解TCP/IP协议栈

可以用arp -a命令查看ARP高速缓存。

ARP分组数据格式:

UNIX/Linux网络编程基础:图解TCP/IP协议栈

ARP协议的实现方式是在以太网上做广播,查询目的IP地址,接收到ARP请求的主机响应请求方,将本机的MAC地址反馈给请求的主机。

ARP请求应答的操作方式很简单,将接受到的数据字段的发送方和接收方的值对调,将所有本机的硬件地址和IP地址的值填充到合适的发送方位置。

UNIX/Linux网络编程基础:图解TCP/IP协议栈