学习自《网络是怎样连接的》的系列。这一系列博客将从协议栈通过TCP协议收发数据的操作开始写起。以下为系列的连接。

1.协议栈的内部结构

协议栈的内部如图1所示,分为了几个部分,分别承担不同的功能。

图1 TCP/IP软件的分层结构

上层会向下层逐层委派工作

从上到下来说,最上面是网络应用程序,也就是浏览器、电子邮件、Web服务器等,它们会将收发数据等工作委派给下层的部分来完成。也就是说,尽管不同的应用程序收发的数据内容不同,但收发数据的操作是共通的
应用程序的下层是Socket库,其中包括解析器(向DNS服务器发出查询)。
再下一层就是操作系统了,包括协议栈,协议栈分为两块,分别是负责用TCP协议收发数据的部分,和负责用UDP协议收发数据的部分。像浏览器,邮件等一般的应用程序都是使用TCP收发数据的,而像DNS查询等收发较短的控制数据的时候则使用UDP。
下一半使用IP协议控制网络包收发操作的部分。在传送数据时,数据会被切分成一个一个的网络包,而将网络包发送给通信对象的操作就是由IP来负责的。ICMP用于告知网络报传送过程产生的错误以及各种控制消息,ARP用于根据IP地址查询相应的以太网MAC地址。
IP下层的网卡驱动程序负责控制网卡硬件,而最下面的网卡则完成实际的收发操作,也就是对网线中的信号执行发送和接受不了的操作。

2.套接字的实体就是通信控制信息

在协议栈内部有一块用于存放控制信息的内存空间,这里记录了用于控制通信操作的控制信息,例如通信对象的IP地址,端口号,通信操作的进行状态等。本来套接字就只是一个概念而已,并不存在实体,如果一定要赋予它一个实体,那么可以说这些控制信息就是套接字的实体,或者说存放控制信息的内存空间就是套接字的实体。
协议栈在执行操作时需要参阅这些控制信息。例如在发送数据时,需要看一看套接字中的通信对象IP地址和端口号,以便向指定的IP地址和端口发送数据。在发送数据之后,协议栈需要等待对方返回收到的数据响应信息,但数据也有可能在中途丢失,永远也等不到对方的响应,在这样的情况下,需要重新发送丢失的数据,这就需要套接字中记录是否收到响应以及发送数据后经过了多长的时间,才能根据这些信息按照需要执行重发操作。总之,协议栈是根据套接字中记录的控制信息来工作的

查看真正的套接字

终端输入netstat命令可以查看真正的套接字。如图2所示。

图2 终端显示目前的套接字

这里的每一行相当于一个套接字,当创建套接字时,这里就会增加一行新的控制信息。Proto表示协议类型,可以看到有tcp4,也有tcp6,还有udp,local address显示本地的IP地址和端口号,0.0.0.0表示不绑定IP地址,Foreign Addrerss代表远程的IP地址和端口号。State表示通信状态,比如ESTABLISHED,FIN_WAIT_1,CLOSING等。

3.调用socket时的操作

图3 消息收发操作

如图三所示,创建套接字时,首先分配一个套接字所需的内存空间,然后向其中写入初始状态
接下来,需要将表示这个套接字的描述符告知应用程序,这样,应用程序在向协议栈进行收发数据委托时就需要提供这个描述符。由于套接字中记录了通信双方的信息以及通信处于怎样的状态,所以只要通过描述符确定了响应的套接字,协议栈就能获取所有的相关信息,这样一来,应用程序就不需要每次都告诉协议栈应该和谁进行通信了。