由于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
分享到:
相关推荐
根据提供的文件标题、描述、标签以及部分内容,我们可以推断出这份文档主要关注的是Linux内核中的TCP/IP协议栈实现分析。接下来将详细阐述这一主题下的关键知识点。 ### 一、Linux内核源码剖析概述 #### 1. Linux...
在Linux内核中,TCP和UDP的实现位于`net/ipv4/tcp.c`和`net/ipv4/udp.c`等文件中。 3. **网络层**:网络层主要负责数据包的路由选择和寻址,核心协议是IP(互联网协议)。Linux内核中的IP协议实现位于`...
在Linux内核中,TCP和UDP模块处理连接建立、数据传输、流量控制和拥塞控制等问题。 5. **应用层**:这一层包含各种应用协议,如HTTP、FTP、SMTP等,它们直接与用户交互。Linux内核通过socket API为上层应用提供了与...
6. **网络协议栈**:Linux内核实现了完整的TCP/IP协议栈,包括网络接口层、网际层、传输层和应用层,支持多种网络协议,如TCP、UDP、HTTP、FTP等。 7. **系统调用**:系统调用是用户程序与内核交互的唯一途径,如...
6. 网络协议栈:这部分内容解析了内核如何实现TCP/IP协议,包括网络接口层、网络层、传输层和应用层的处理细节,如ARP、IP、TCP、UDP等协议的实现。 7. 中断和异常处理:中断是硬件事件通知内核的方式,而异常则...
在本资料"Linux内核TCP/IP协议栈分析"中,我们将深入探讨这个核心组件的工作原理。 TCP/IP协议栈分为四个主要层次:应用层、传输层、网络层和数据链路层。在Linux内核中,每一层都有相应的模块负责处理相关的协议和...
在Linux内核中,网络栈分为五层:物理层(数据链路层)、网络层(IP层)、传输层(TCP/UDP层)、会话层以及应用层。Linux 2.4.0内核网络栈的设计遵循了TCP/IP协议族的分层模型,每层都有其特定的任务和功能。 1. **...
Linux内核是操作系统的核心部分,负责管理系统的进程、内存、设备驱动、文件系统以及网络协议等。Linux-2.6.11内核是Linux发展历史中的一个重要版本,发布于2005年,它在前一版本的基础上进行了许多改进和优化。这个...
每一层都有一些关键的协议和技术,比如网络层的IP协议和ICMP协议、传输层的TCP和UDP协议,以及应用层的各种应用协议。 总而言之,面试中对于TCP与UDP的考察是检验求职者是否具有扎实的网络编程基础和对网络协议深入...
5. **网络协议栈**:详述了Linux内核中的网络处理流程,包括网络接口层、IP层、TCP/UDP层以及应用层协议,如HTTP、FTP等,这有助于理解网络通信的底层机制。 6. **设备驱动程序**:设备驱动是连接硬件和内核的桥梁...
5. **网络堆栈**:Linux的网络子系统在2.4.16内核中已经相当强大,支持TCP/IP协议族,包括TCP、UDP、ICMP等。同时,它还支持socket接口,为用户空间应用程序提供网络通信的能力。 6. **系统调用**:系统调用是用户...
### 基于Linux的TCP-IP网络通信 #### 引言 随着互联网技术的快速发展,传统的文件传输方式已无法满足现代经济发展的需求。Linux作为一种免费且开源的Unix类操作系统,因其优秀的网络支持能力和严谨的安全架构,...
在信息技术领域,Linux内核的网络协议栈是实现操作系统与网络通信的核心组件。对于任何对网络编程、系统优化或者网络设备驱动开发感兴趣的IT专业人士来说,理解Linux网络协议栈的工作原理是至关重要的。本文将基于...
Linux 支持 BSD 套接字和全部的 TCP/IP 协议,是通过网络协议将其视为一组相连的软件层来实现的。 在 Linux 环境下,TCP/IP 网络通信编程方法包括 TCP/IP 协议、BSD 套接字和 Socket 编程。TCP/IP 协议是 Linux ...
- 路由选择是网络层的重要功能,Linux内核通过路由表实现。 4. **传输层**: - TCP(传输控制协议)和UDP(用户数据报协议)是传输层的主要协议,分别提供面向连接和无连接的服务。 - TCP/IP协议栈中,TCP由`tcp...
2. **发送路径**:应用程序通过套接字API发送数据时,数据首先被传输层封装,添加TCP或UDP头,然后在网络层加上IP头,最后由网络接口设备驱动发送到网络。 3. **协议处理**:每个层次都有相应的协议处理器,如TCP、...
TCP/IP协议族是互联网通信的基础,它由应用层、传输层、网络层和数据链路层组成,每一层都负责特定的网络功能,如应用层的HTTP、FTP,传输层的TCP和UDP,网络层的IP以及数据链路层的MAC地址。 在Linux平台上,我们...
例如,应用层包括了基于TCP/IP的各种应用程序,传输层主要处理TCP和UDP协议,网络层则负责数据包的路由,而网络接口层则负责数据包的物理传输。 文章详细阐述了Linux网络数据处理流程,从进程角度出发,说明了如何...