深入剖析linux网络发送过程

本文详细剖析了Linux系统中基于TCP/IPV4的网络发送过程,从应用层的send命令开始,深入到传输层的tcp_sendmsg,再到网络层的ip_queue_xmit,以及数据链路层的dev_queue_xmit。重点讨论了数据包在各层的处理,包括内存管理、协议头的添加、路由选择和硬件中断处理等关键步骤。
摘要由CSDN通过智能技术生成

深入剖析网络发送过程

本文在基于以下三个条件所写的:

1)  OSI七层网络通信模型。

2)  所阐述的函数是基于Linux2.6.1内核。

3)  在面向连接的通信协议TCP/IPV4的基础上。

由于七层模型(应用层, 表示层, 会话层, 传输层, 网络层, 数据链路层, 物理层)可以简化为以下五层结构: 应用层(Application Layer), 传输层(Transport Layer), 网络层(Network Layer), 数据链路层(Data Link Layer), 物理层(Physical Layer).其中七层模型中的前三层都归结为五层结构中的应用层。为了简化讨论,本文主要从这五层结构来探讨。

 

Layer 5:应用层(Application Layer)

 

TCP协议上,当通过三方握手建立了连接之后,就进入数据包的实质发送阶段,在本文中以send命令来阐述。当通过send将数据包发送之后,glibc函数库会启用另外一个其定义的别用名函数__libc_sendto(),该函数最后会间接执行到sendto系统调用:

inline_syscall##nr(name, args);// ##nr说明是该系统调用带有nrargs参数sendto系统调用的参数值是6,而name就是sendto

从上面的分析可以看出glibc将要执行的下面一条语句是

inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6)

在该函数中一段主要功能实现代码如下:

__asm__ __volatile__                                    /

          ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7 %8"            /

           : inline_syscall_r0_out_constraint (_sc_0),          /

             "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),          /

             "=r"(_sc_18), "=r"(_sc_20), "=r"(_sc_21)           /

           : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17), "4"(_sc_18), /

             "1"(_sc_19), "5"(_sc_20), "6"(_sc_21)              /

           : inline_syscall_clobbers);                          /

        _sc_ret = _sc_0, _sc_err = _sc_19; 

该代码采用了嵌入汇编(详细介绍查阅嵌入汇编相关书籍),其中:

_sc_0=sendto;

_sc_19 --_sc_21分别是arg1—arg6;

inline_syscall_r0_out_constraint:功能相当于"=r",选用一个寄存器来存储输出变量。

"0"--"6"分别是%0--%6,代表_sc_0--_sc_21

接下来函数最终通过Linux中顶顶有名的INT 0X80陷入系统核心。具体的过程可以参考内核相关书籍。下面是一个兄弟对INT 0X80的简要介绍:

http://blog.chinaunix.net/u2/65427/showart_712571.html

在陷入系统内核以后,最终会调用系统所提供的系统调用函数sys_sendto(),该函数直接调用了__sock_sendmsg(),该函数对进程做一个简单的权限检查之后就触发套接字(socket)中定义的虚拟sendmsg的函数,进而进入到下一层传输层处理。

 

Layer 4: 传输层(Transport Layer)

 

由上层的讨论可知,系统触发了sendmsg虚拟接口函数,其实就是传输层中的tcp_sendmsg或是udp_sendmsg,看你所使用的协议而定。本文介绍tcp_sendmsg().

该函数需要做如下工作:

1)sk_buff(后面简称skb)分配空间,该函数首先尝试在套接字缓冲队列中寻找空闲空间,如果找不到就使用tcp_alloc_pskb()为其重新分配空间。

2)  下面这步就会tcp_sendmsg函数的主要部分了,将数据拷贝到缓冲区。它分为如下两种情况:

2.1)如果skb还有剩余空间的话,就使用skb_add_data()来向skb尾部添加数据包。代码如下:

if (skb_tailroom(skb) > 0) {

                               

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值