[kernel] 使用sendfile

linux内核里对于要发送到网络上去的包,是通过sk_buffer结构组织的,这个结构主要就是包含一个指针和一个长度,指针指向要发送数据的开头处,长度当然就是要发送的长度。当我们使用send系统调用时,内核要把用户空间的数据拷往内核空间在(创建一个副本),然后构造sk_buffer指向这个内核空间里的副本,接着把sk_buffer排到队列里去,等待网卡处理。
后来诞生了sendfile,sendfile会直接将sK_buffer指向文件在内存中的cache,这样就节省了一次拷贝。
这里有个注意事项:sendfile不适合频繁改动的文件。假如你调用了一次sendfile,sk_buffer指向文件的某块cache,然后被放入队列;接着,你改动了文件的内容,那么排在发送队列里的那个sk_buffer指向的cache内容就变化了!那发出去的消息就是你改动后的数据。在不知道sk_buffer是否已发往网络的情况下,一边改动文件一边调用sendfile会造成发送出去的内容不确定。所以,sendfile更适合用在静态文件的场合。
当然,如果有个办法能查询sk_buffer是否真的发送出去了(而不是呆在发送队列里),那么“改一次文件内容,调一次sendfile;再改一次文件内容,再调一次sendfile”也是一个不错的节省拷贝时间的发送策略。

相关文章

分类

4 Comments

Clan said:

类似的系统调用还有 spice/vmsplice

不过现在不知道怎么对SSL采用这种方式避免多次拷贝?

DongHao Author Profile Page said:

vmsplice只能输出到pipe,不能输出到socket吧?

Clan said:

早就注意到了这点,但以前一直认为socket也算是一种(广义的)pipe,也许也能用。刚测试了一下,确认目前这里的pipe是狭义的pipe,及由pipe()创建的pipe。但未来不是不可能也支持socket。一个链接: http://kerneltrap.org/node/6505

Clan said:

http://lwn.net/Articles/181169/

估计短时间内还不会实现vmsplice 对socket的支持,:(

留言:

关于文章

This page contains a single entry by DongHao published on 06 21, 2010 1:50 PM.

[kernel] 在release方法里,而不是flush方法里释放 was the previous entry in this blog.

如厕 is the next entry in this blog.

Find recent content on the main index or look in the 存档 to find all content.