服务器发送一个TCP消息到底经过了哪些步骤?

场景

服务端主动给客户端发送一条简单的TCP消息,具体的消耗有多大?


所经历的步骤

将数据二进制序列化

  1. 服务器的代码一般都已经全部加载到内存中了,于是不需要去硬盘上读取
  2. 去内存的指定位置调出逻辑代码
  3. 将指令 Decode 成 CPU 可以直接执行的指令
  4. 将指令存入CPU的 高速缓存 和 **指令寄存器(IR)**中
  5. 去内存的指定位置调出要编码的数据
  6. 将数据存入CPU的 高速缓存数据寄存器(DR)
  7. 执行序列化的逻辑运算

补充内容:

  • Fetch-Decode-Execute Cycle
  • 六大寄存器

应用层发送数据

  1. 获得 Socket 句柄
  2. 调用 socket 的 write 函数
  3. 将CPU寄存器中的数据写到内核栈,保留当前程序运行环境
  4. 用户态切换到内核态,将 二进制数据 拷贝到 socket 的 write 缓冲区中
  5. 内核栈中的数据还原到CPU寄存器中,恢复上下文切换前的程序运行环境
  6. 内核态回到用户态

补充内容:

  • socket write 是线程不安全的
  • write分为blocking和nonblock,服务器用的多是nonblock。

操作系统层发送数据

  1. 当缓冲区的数据长度大于等于MSS时(Maxitum Segment Size) 或者 间隔时间达到阈值之后,操作系统就会把数据发送出去
  2. 发送时,操作系统会将 socket 对象中的各个参数取出来,组成TCP协议的头部
  3. 将组装好的数据发送给网卡驱动

补充内容:

  • Nagle算法

网卡层

还没这方面的知识,看完了再补充


衍生问题

  • ** 1次发送3Kb的数据 和 3次发送1Kb的数据 性能差距大吗?**
    当Socket缓存区足够的情况下,1次发送3Kb的数据只需要进行1次系统调用、2次上下文切换;而3次发送1Kb的数据则需要3次系统调用、6次上下文切换;差距还是非常大的。

  • ** 当同时要写入多个socket时,如何减少上下文切换的次数?**
    暂时无解,不过tcp有多播的功能。

  • 业务实现时,使用CPU运算内存数据从而去减少调用 socket write 的次数是值得的,但是如果运算用的数据是从硬盘读取的,那就得不偿失了。(还需要自行考虑代码的可维护性)


版权声明:本文为yxw908186797原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。