一、数据收发操作概览

知道了 IP 地址后,就可以委托操作系统内部的协议栈向Web服务器发送消息了。要发送给Web服务器的 HTTP 消息时一种数字信息(digital data),因此也可以说是委托协议栈来发送数字信息

向操作系统内部的协议栈发出委托时,需要按照指定的顺序来调用 Socket 库中的程序组件

收发数据的操作大致可以总结为一下4个阶段

  1. 创建套接字(创建套接字阶段)
  2. 将管道连接到服务器的套接字上(连接阶段)
  3. 收发数据(通信阶段)
  4. 断开管道并删除套接字(断开阶段)

这4个操作都是由操作系统中协议栈来执行的,浏览器等应用程序并不会自己去做连接管道、放入数据这些工作,而是委托协议栈来代劳。这些委托的操作都是通过吊桶 Socket 库中的程序组件来执行的。

二、创建套接字阶段:创建套接字

客户端创建套接字的操作只需要调用 Socket 库中的 socket 程序组件即可

  1. <描述符> = socket(<使用IPv4>, <流模式>, ...)

套接字创建完成后,协议栈会返回一个描述符,应用程序会将受到的描述符存放在内存中
这个“描述符”是用于应用程序来识别不同的套接字的

三、连接阶段:把管道接上去

应用程序调用 Socket 库中的名为 connect 的程序组件来完成连接阶段的操作,需要指定描述符、服务器IP地址和端口号这3各参数

  1. connect(<描述符>, <服务器的IP地址和端口号>,...)

其中,端口号是为了识别具体套接字的,与前面提到的“描述符不同”

  • 描述符是用来在一台计算机内部识别套接字的机制
  • 端口号是用来让通信的另一方能够识别出套接字的机制

服务器上所使用的端口号是根据应用的种类事先规定好的,比如

  • Web 是80号端口或443端口
  • 电子邮件是25号端口

问:服务器怎么知道客户端套接字的端口号呢?
答:客户端在创建套接字时,协议栈会为这个套接字随便分配一个端口号,然后,当协议栈执行连接操作时,会将这个随便分配的端口号通知给服务器

  • 描述符:应用程序用来识别套接字的机制
  • IP地址和端口号:客户端和服务器之间用来识别对方套接字的机制

四、通信阶段:传递消息

发送数据时,应用程序调用 Socket 库中的名 write 的这个程序组件
接收数据时,调用 read 程序组件

  1. write(<描述符>,<发送数据>,<发送数据长度>)
  2. ...
  3. <接收数据长度> = read(<描述符>, <接收缓冲区>)

调用 write 时,需要指定描述符和发送数据,然后协议栈就会将数据发送到服务器
接下来,服务器执行接收操作,解析收到的数据内容并执行相应的操作向客户端返回响应消息

调用 read 时,需要指定用户存放接收到的响应消息的内存地址,这一内存地址称为接收缓冲区
read 会负责将接收到的响应消息存放到接收缓冲区,由于接收缓冲区是一块位于应用程序内部的内存空间,因此当消息被存放其中时,就相当于移交给了应用程序

五、断开阶段:收发数据结束

当浏览器收到数据之后,收发数据的过程就结束了,调用 Socket 库的 close 程序组件进入断开阶段。最终,连接套接字之间的管道会被断开,套接字本身也会被删除。

根据应用程序种类不同,客户端和服务器哪一方先执行 close 都有可能。有些应用程序是客户端先执行,而另外一些应用则是服务器先执行 close

「@浪里淘沙的小法师」