由于4层协议实现复杂度的不对称性,导致3层协议实现也不易统一,换句话说就是同样的3层协议比如IP要为不同的4层协议提供不同的实现,这是因为我们熟知的4层协议分为流和数据报两种类型,流式协议比如tcp在4层就处理了大量的逻辑,比如分段等等,而数据报协议比如 udp却不处理这些,因此当它们被交付到3层的时候,针对于分段来讲,3层逻辑对tcp需要作的事就很少了,而对udp就要有大量的工作要做,这就导致了对于tcp来说,只需要调用简单的ip_queue_xmit即可,而对于udp来说,就需要调用更复杂的 udp_push_pending_frames。从名称上看,pending一词表明,该函数并不是即时调用的,可能4层协议逻辑尽可能多的将udp数据报填充之后再发送到3层的,事实确实是这样的,然而对于tcp来讲也有pending一说,意义是一样的。总之,udp的3层实现更复杂一些,理由就是它的4层实现太简单,而3层的复杂逻辑比如分片是怎么也逃不掉的。
udp的4层发送函数是udp_sendmsg,它进一步又调用了:
err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
sizeof(struct udphdr), &ipc, rt,
corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
if (err)
udp_flush_pending_frames(sk);
else if (!corkreq)
err = udp_push_pending_frames(sk, up);
可见,调用udp_push_pending_frames将数据报发往3层是有条件的,要么应用层强制即时发送不缓存(通过setsockopt的CORK命令),要么缓存已经满了,事实就是,如果你不强制,那么就请尊重内核的决定,任何事情总要有个默认方案的。下面看一下ip_append_data的实现逻辑,它非常复杂,复杂之处在于它帮助3层实现了很多它力所能及或者说是举手之劳的事情,那就是预分片操作。虽然它不负责3层的ip分片这件事,但是它却可以做一些事情使得接下来总逃不过的ip分片更加容易,更加有效率,ip_append_data函数首先将用户传进的数据按照查找到的路由出口mtu分成一个个的小段,然后将这些小段组合,组合的方式根据是否启用分散/聚集IO有两种方式,如果不启用分散/聚集IO,那么将所有的小段连接成一个链表,如果启用了,那么就将第二个到最后一个的片段植入到skb的skb_shinfo(skb)->frags数组中。这只是大体上的流程,细节上稍微复杂一些,在分配内存的时候,该函数根据路由出口考虑到了2层的协议头,它预留了协议头大小的空间,并且如果启用了分散/聚集IO的话,它将不再为每一个mtu大小的数据(加上头)分配一个skb,而是将后续的数据填充到当前skb的 frags数组中,这样在最终网卡发送的时候,只要将这些frags映射到设备空间就可以了。
现在有一个问题,udp_sendmsg中为何要将ip_append_data和udp_push_pending_frames分开呢?实际上这增加了应用程序对底层的控制,udp套结字有一个UDP_CORK的选项,在这个选项置为1的情况下,应用层的数据是不会被发出去的,只有在这个选项置为0的时候才会发送数据,这就实现了累积的发送,同时这个特性会影响到ip_append_data的内存分配,ip_append_data本质上就是帮ip层忙的,如果UDP_CORK为1的话,ip_append_data的falg参数将会加上MSG_MORE,这样在分配内存的时候就会分配一个mtu的大小而不仅仅是当前数据的大小,因为它知道马上还会有数据来,即使当前的数据长度没有一个mtu的大小,接下来的数据还是可以使用剩余空间的,但是如果启用了分散/聚集IO的话就不能这样了,因为分散 /聚集IO的本质就是“呆在原地”:
if ((flags & MSG_MORE) && !(rt->u.dst.dev->features&NETIF_F_SG))
alloclen = maxfraglen;
另外的一个特性是,如果路由出口网卡启用了分散/聚集IO,那么就不是往skb的剩余空间塞数据了,而是往page的剩余空间塞数据:
if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
unsigned int off;
off = skb->len;
if (getfrag(from, skb_put(skb, copy), offset, copy, off, skb) < 0) {
...
}
} else {
int i = skb_shinfo(skb)->nr_frags;
skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
struct page *page = sk->sk_sndmsg_page;
int off = sk->sk_sndmsg_off;
unsigned int left;
if (page && (left = PAGE_SIZE - off) > 0) {
if (page != frag->page) {
get_page(page);
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
frag = &skb_shinfo(skb)->frags[i];
}
} else if (i < MAX_SKB_FRAGS) {
page = alloc_pages(sk->sk_allocation, 0);
sk->sk_sndmsg_page = page;
sk->sk_sndmsg_off = 0;
skb_fill_page_desc(skb, i, page, 0, 0);
frag = &skb_shinfo(skb)->frags[i];
skb->truesize += PAGE_SIZE;
atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
}
...
if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0)
...
分散/聚集IO尽可能的不拷贝数据,它尽可能的将数据集中在整个页面内部。
分离了ip_append_data和udp_push_pending_frames,应用程序可以多次调用ip_append_data,然后一次性发送,以此可以控制数据收发的响应速度和吞吐量。对于tcp来讲,它也有一个TCP_CORK选项,然而这个cork和udp的意义不同,tcp的cork并没有强制性,也就是说就算你设置了cork,数据在一定条件下也是会自动发出去的,道理在于,首先tcp的实现要遵从它的协议标准,然后再考虑效率优化和应用程序定制,而cork就是为了优化和定制而产生的,因此它也就是只能在毫无连接和任何控制机制的udp协议上实施专制和独裁。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dog250/archive/2010/10/13/5939241.aspx
分享到:
相关推荐
python入门-30.寻找列表中只出现一次的数字——寻找单身狗.py
linux优化笔记,配套视频:https://www.bilibili.com/list/474327672?sid=4496133&spm_id_from=333.999.0.0&desc=1
知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载,CRMEB知识付费分销与直播营销系统是由西安众邦科技自主开发的一款在线教育平台,该系统不仅拥有独立的知识产权,还采用了先进的ThinkPhp5.0框架和Vue前端技术栈,集成了在线直播教学及课程分销等多种功能,旨在为用户提供全方位的学习体验,默认解压密码youyacaocom
美妆神域-JAVA-基于springBoot美妆神域设计与实现
原生js制作Google粘土logo动画涂鸦代码.zip
golin 扫描工具使用, 检查系统漏洞、web程序漏洞
原生态纯js图片网格鼠标悬停放大显示特效代码下载.zip
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手
去水印web端独立版web
原生js制作左侧浮动可折叠在线客服代码.zip
Chrome 谷歌浏览器下载
全新完整版H5商城系统源码 自己花钱买的,亲测可用,需要自行下载 H5商城系统设置是实现商城基本功能的核心部分,涵盖了从网站配置、短信和支付配置,到商品、工单、订单、分站和提现管理等多个模块的设置。以下是详细的设置指南,帮助您快速上手并高效管理商城系统。 测试环境:Nginx+PHP7.0+MySQL5.6 1. 网站配置 设置商城名称、LOGO、标题、联系方式和SEO关键词等,确保商城专业和易于搜索。 2. 短信配置 配置短信接口和模板,用于发送订单通知、验证码等,提升用户体验。 3. 支付接口配置 配置微信、支付宝等支付接口,填写API密钥和回调地址,确保支付流畅。 4. 商品分类管理 对商品进行分类和排序,设置分类名称和图标,便于用户查找商品。 5. 商品管理 添加和管理商品信息、规格、图片等,确保商品信息准确丰富。 6. 工单管理 查看和回复用户工单,记录售后问题,提升用户服务质量。 7. 订单管理 查看订单详情,更新订单状态,支持批量导出,方便订单跟踪。 8. 分站管理 创建不同区域分站,设置权限,统一管理各区域市场。 9. 提现管理
apk安装包
原生js选项卡插件自定义图片滑动选项卡切换.zip
宗教信息佛教佛寺寺庙庵堂相关数据集提供了全国各个地区省市县各个佛教寺庙的详细信息。这些数据不仅包括寺庙的名称和负责人姓名,还涵盖了所属省份、地级市、区县、具体地址、建立日期以及支派类别等关键信息。该数据集整理了超过3万条样本,为研究中国佛教寺庙的分布、历史和文化提供了丰富的第一手资料。这些信息有助于了解佛教在中国的传播和发展,以及寺庙在社会和文化中的作用。数据的整理和提供,对于宗教学、社会学、历史学和文化研究等领域的学者来说,是一个宝贵的资源。
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手
简单的 Python 版本管理pyenvpyenv 可让您轻松在多个 Python 版本之间切换。它简单、不引人注目,并遵循 UNIX 传统,即使用单一用途的工具来做好一件事。该项目由rbenv和 ruby-build分叉而来,并针对 Python 进行了修改。pyenv 的作用是什么......允许您根据每个用户更改全局 Python 版本。为每个项目的 Python 版本提供支持。允许您使用环境变量覆盖 Python 版本。一次搜索多个 Python 版本的命令。这可能有助于使用tox跨 Python 版本进行测试。与 pythonbrew 和 pythonz 相比,pyenv没有……依赖于Python本身。pyenv由纯shell脚本制作。不存在Python的引导问题。需要加载到你的 shell 中。相反,pyenv 的 shim 方法通过向你的 中添加目录来工作PATH。管理虚拟环境。当然,你可以自己创建虚拟环境 ,或者使用pyenv-virtualenv 来自动化该过程。目录安装获取 PyenvLinux/UNIX自动安装程序基本
Notepad-v2.20工具,是替代Notepad++的首选工具
原生js随机图片拖拽排序代码.zip
更快、更好、更稳定的Redis桌面(GUI)管理客户端,兼容Windows、Mac、Linux,性能出众,轻松加载海量键值