分享

【底层原理】网络数据传输时经历了哪些buffer

 太极混元天尊 2018-05-22

作者:骏马金龙

链接:http://www.cnblogs.com/f-ck-need-u/

码农有道作了部分修改

码农有道

 

历史文章目录(请戳我)

关于码农有道(请戳我)


打算用一篇文章介绍I/O模型,在引入IO模型前,本文先对io等待时某一段数据的'经历'做一番解释。如图:

当某个进程/线程(后文将不加区分的只认为是进程)需要某段数据时,它只能在用户空间中属于它自己的内存中访问、修改,这段内存暂且称之为app buffer(用户缓冲区)

假设需要的数据在磁盘上,那么进程首先得发起相关系统调用,通知内核去加载磁盘上的文件。但正常情况下,数据只能加载到内核的缓冲区,暂且称之为kernel buffer。数据加载到kernel buffer之后,还需将数据复制到app buffer。到了这里,进程就可以对数据进行访问、修改了。

现在有几个需要说明的问题。

为什么不能直接将数据加载到app buffer呢?

实际上是可以的,有些程序或者硬件为了提高效率和性能,可以实现内核旁路的功能,避过内核的参与,直接在存储设备和app buffer之间进行数据传输,例如RDMA技术就需要实现这样的内核旁路功能。

但是,最普通也是绝大多数的情况下,为了安全和稳定性,数据必须先拷入内核空间的kernel buffer,再复制到app buffer。


上面提到的数据几次拷贝过程,拷贝方式是一样的吗?

不一样。现在的存储设备(包括网卡)基本上都支持DMA操作。什么是DMA(direct memory access,直接内存访问)?简单地说,就是内存和设备之间的数据交互可以直接传输,不再需要计算机的CPU参与,而是通过硬件上的芯片(可以简单地认为是一个小cpu)进行控制。

假设,存储设备不支持DMA,那么数据在内存和存储设备之间的传输,必须通过计算机的CPU计算从哪个地址中获取数据、拷入到对方的哪些地址、拷入多少数据(多少个数据块、数据块在哪里)等等,仅仅完成一次数据传输,CPU都要做很多事情。而DMA就释放了计算机的CPU,让它可以去处理其他任务。

再说kernel buffer和app buffer之间的复制方式,这是两段内存空间的数据传输,只能由CPU来控制。

所以,在加载硬盘数据到kernel buffer的过程是DMA拷贝方式,而从kernel buffer到app buffer的过程是CPU参与的拷贝方式


如果数据要通过TCP连接传输出去要怎么办?

例如,web服务对客户端的响应数据,需要通过TCP连接传输给客户端。

TCP/IP协议栈维护着两个缓冲区:send bufferrecv buffer,它们合称为socket buffer。需要通过TCP连接传输出去的数据,需要先复制到send buffer,再复制给网卡通过网络传输出去。如果通过TCP连接接收到数据,数据首先通过网卡进入recv buffer,再被复制到用户空间的app buffer。

同样,在数据复制到send buffer或从recv buffer复制到app buffer时,是CPU参与的拷贝。从send buffer复制到网卡或从网卡复制到recv buffer时,是DMA操作方式的拷贝。

如下图所示,是通过TCP连接传输数据时的过程。


网络数据一定要从kernel buffer复制到app buffer再复制到send buffer吗

不是。如果进程不需要修改数据,就直接发送给TCP连接的另一端,可以不用从kernel buffer复制到app buffer,而是直接复制到send buffer。这就是零复制技术。

例如httpd不需要访问和修改任何信息时,将数据原原本本地复制到app buffer再原原本本地复制到send buffer然后传输出去,但实际上复制到app buffer的过程是可以省略的。使用零复制技术,就可以减少一次拷贝过程,提升效率。

当然,实现零复制技术的方法有多种,后面会有一篇专门总结零复制的文章

以下是以httpd进程处理文件类请求时比较完整的数据操作流程。

大致解释下:客户端发起对某个文件的请求,通过TCP连接,请求数据进入TCP 的recv buffer,再通过recv()函数将数据读入到app buffer,此时httpd工作进程对数据进行一番解析,知道请求的是某个文件,于是发起某个系统调用(例如要读取这个文件,发起read()),于是内核加载该文件,数据从磁盘复制到kernel buffer再复制到app buffer,此时httpd就要开始构建响应数据了,可能会对数据进行一番修改,例如在响应首部中加一个字段,最后将修改或未修改的数据复制(例如send()函数)到send buffer中,再通过TCP连接传输给客户端。


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多