tcp/ip发送接收总体框架      

对于接收到的报文,如果不被丢弃、不被网桥转发,会调用netif_receive_skb()提交给IP层;而对于IP层向外发送的报文,则通过调用dev_queue_xmit()提交给数据链路层。
        本文就以netif_receive_skb()和dev_queue_xmit()为起始,先介绍下传输层(tcp)发送的处理过程:
       sys_sendto(用户态发包调用函数)----》sock_sendmsg(sock发包函数,调用sock中对应的协议族的发包函数)    ----》inet_sendmsg(以太网协议栈发包函数,被赋值于对应协议族的sendmsg字段)---》tcp_sendmsg(用户态发包函数,把用户层的数据,填充到skb中,然后加入到sock的发送队列)----》tcp_push---》__tcp_push_pending_frames(/* 尽可能的将发送队列中的skb发送出去,禁用nalge */ )---》tcp_write_xmit(将发送队列上的SBK发送出去,返回值为0表示发送成功)---》tcp_transmit_skb(该函数会建立IP层的头,并将该头传递给网络层)---》ip_queue_xmit(此步骤已进入IP层了,首先为输入包建立IP包头, 经过本地包过滤器后,再将IP包分片输出(ip_fragment))
再介绍下传输层(tcp)接收数据的处理流程:
三个过程:
1)网口--->触发软中断
    网卡收到网络包后,触发网卡注册的硬中断处理函数,硬中断处理函数负责触发网络收包软中断。
2)软中断--->TCP
    _do_softirq(软中断处理函数调用网络收报处理函数)---》net_rx_action(网络收包软中断函数)---》

简要介绍一下报文在IP层的处理过程。
先来一张图:

报文接收(图中橙色箭头所指)
netif_receive_skb()
对每一种已注册的协议类型调用deliver_skb(),从而调用到其packet_type->func()函数。
对于IP协议,会调用到ip_rcv()。
ip_rcv()
IP报头检查,调用ip_fast_csum()检查校验和。
netfilter:NF_INET_PRE_ROUTING。
调用ip_rcv_finish()。
ip_rcv_finish()
调用ip_route_input_noref()查找路由表,其结果会决定报文的去向。
调用ip_rcv_options()处理IP选项。
调用dst_input(),从而调用到rtable.dst_entry->input()。根据路由不同,主要有ip_forward(转发)、ip_local_deliver(接收)两种取值。
ip_local_deliver()
如果存在分片,调用ip_defrag()完成分片重组。如果分片暂未到齐则直接返回。
netfilter:NF_INET_LOCAL_IN。
调用ip_local_deliver_finish()。
ip_local_deliver_finish()
调用raw_local_deliver()试图按raw socket方式(直接收发IP报文的socket)递交给上层应用,递交成功则返回。
按ip_hdr->protocol取出相应L4协议,调用net_protocol.handler(),从而将报文提交给传输层。主要有的L4协议handler有icmp_rcv()、udp_rcv()、tcp_v4_rcv()、等。

报文发送(图中紫色箭头所指)
  传输层在发送报文时,会调用到IP层的接口。如:ip_queue_xmit()、ip_append_data()/ip_append_page()+ip_push_pending_frames()、ip_local_out()、等。
      这些函数最终会调用到ip_local_out()。
在此之前,报文会被构造好。可能由传输层的代码自己构造、也可能通过调用ip_append_data()这样的辅助函数来构造。
具体构造报文的细节就不细说了,引用ULNI上的一张图,直接看结果:

struct sock是跟应用创建的socket相对应的结构,其中的sk_write_queue指向待发送的IP报文分片队列,每个分片由一个struct sk_buff来表示。
        由于网络节点存在MTU,也就是最大传输单元,一次提交给数据链路层的报文不能太大(如1500字节),所以过大的IP报文需要分片后发送。
       注意,只有第一个分片有L4的报头,因为对于L4协议来说,这些分片组装成的整体才是一个报文。
        当然,最好的情况是没有分片,也就是L4协议总是发送尺寸小于MTU的报文。
         struct sk_buff中有一组head、data、tail、end这样的指针,指向需要发送的报文buffer。
        struct sk_buff之后会紧跟一个struct skb_shared_info结构。属于同一个分片的报文数据可能分散于多个碎片中,其中的第一个碎片由上述head、data等指针指向,后续碎片则由struct skb_shared_info来指示。
      为什么要有多个碎片呢?
      一方面,因为上层发送数据有可能就是一小片一小片的发送的,比如传送文件,每次读128字节并发送。而这些碎片可以在同一个IP报文中发送,只要总和不超过MTU。
      另一方面,很多硬件支持这样的由多个碎片构成的缓冲区。如果某些硬件不支持的话,那构造sk_buff的时候就只能把每次提交的数据都拷贝到同一块连续的buffer中,这样可能就会多一次拷贝。
当然,就算硬件支持多个碎片,数据拷贝可能也无法避免。比如说当数据源来自于用户空间的时候,就必定存在用户空间到内核空间的一次拷贝(因为用户指定的地址可能存在错误,不能直接提交给网卡)。而在类似于sendfile这样的系统调用中,数据源本身就在内核空间,则可能做到真正的零拷贝。
        ip_append_data()/ip_append_page()就是完成sk_buff构造的辅助函数,调用它往struct sock中塞数据,其内部会控制是否应该分配新的struct sk_buff作为分片、或者数据是否应该作为碎片放入struct skb_shared_info结构。
ip_local_out()
netfilter:NF_INET_LOCAL_OUT。
调用dst_output(),从而调用到ip_output()。
ip_output()
netfilter:NF_INET_POST_ROUTING。
调用ip_finish_output()。
ip_finish_output()
调用ip_fragment()对报文做分片后发送,或直接调用ip_finish_output2()发送。
ip_finish_output2()
调用邻居子系统neigh_output(),最终由邻居子系统调用dev_queue_xmit()发送报文。

报文转发(图中绿色箭头所指)
对于接收到的报文,如果路由子系统认为应该转发,则dst_input()会调用到ip_forward()。
ip_forward()
处理IP选项、递减ttl。
netfilter:NF_INET_FORWARD。
调用ip_forward_finish()。
ip_forward_finish()
调用ip_forward_options()处理IP选项。
调用dst_output(),从而调用到ip_output()。
在上述流程中,有几个点再额外说明一下:

netfilter:IP报文的处理流程中共有PRE_ROUTING、LOCAL_IN、FORWARD、LOCAL_OUT、POST_ROUTING这五个HOOK点。用户可以通过配置netfilter,在这几个节点上添加一些规则,实现对特定IP报文的干预。

route:路由子系统。决定IP报文下一步应该发送到哪个IP地址上(或者自己接收)。这个目的IP地址所对应的主机必定是与本机直接相连、或通过交换机相连的(也就是说,两台机器之前的通信不需要路由器转发,两台机器是“邻居”)。
举个简单的例子,路由表有如下配置:
Destination Gateway Genmask Flags Metric Ref Use Iface
10.20.150.0 * 255.255.255.0 U 0 0 0 eth0
default 10.20.150.254 0.0.0.0 UG 0 0 0 eth0
那么,目的地是10.20.150.0/24这个子网的报文,直接进行转发(目的主机和本机直接就是邻居);而目的地是其他地址的报文,发往默认网关10.20.150.254,由它来继续转发。(注意,默认网关10.20.150.254也是本机的邻居。)

neighbour:邻居子系统。路由子系统确定了报文要发送到的IP地址,而在将报文提交给数据链路层之前,还需要知道目的主机的Mac地址。这就是邻居子系统干的事情。
简单来说,一台机器通过在子网中广播一个ARP报文,来询问目的IP地址的Mac地址是什么。比如目的IP地址是10.20.150.133,本机会广播"Who is 10.20.150.133/24"的ARP报文。像交换机这样的数据链路层设备会将ARP报文转发,从而让每一个邻居都收到。当10.20.150.133收到询问后,会向本机回复其Mac地址。
然后在此基础上,邻居子系统会实现一定的缓存策略,不会对于每个报文件都这么询问一下。

tcp/ip发送接收总体框架相关推荐

  1. TCP/IP 与 DBUS 发送数据速度对比 进程间通信

    图片为测试每次发送长度 1024*1024 Byte数据的延时,每次间隔20毫秒,同一台电脑,WIN10系统,32G内存,24核心; 测试代码用QT自带例子修改. 结果: TCP/IP 延时30毫秒左 ...

  2. TCP/IP 协议栈4层结构及3次握手4次挥手

    TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...

  3. TCP/IP连接释放

    TCP/IP 的连接释放 总体流程图 连接过程 SYN = 1 说这次报文为建立连接报文 seq = x 本次请求的序号 ACK = 1 说明这次请求是响应报文 TCP 的连接过程就是我们常说的三次握 ...

  4. 杂谈——TCP/IP 协议栈详解

    说到协议栈,我们就先来看看它的定义是什么. TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输. 本帅博主之前写过一篇 ...

  5. 简述TCP/IP 协议栈

    TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...

  6. 一文搞懂TCP/IP 协议栈原理

    转载自:https://www.toutiao.com/a6708509605044945421/?app=news_article_lite&is_hit_share_recommend=0 ...

  7. 深入浅出TCP/IP协议栈

    本文转载于:深入浅出TCP/IP协议栈 https://www.cnblogs.com/onepixel/p/7092302.html TCP/IP 协议栈是一系列协议的总和,是构成网络通信的核心骨架 ...

  8. 深入浅出 TCP/IP 协议栈丨手写代码实现网络协议栈

    TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...

  9. 深入浅出 TCP/IP 协议栈

    TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...

  10. 网络编程-TCP/IP协议栈-IP协议

    协议 协议就是约定的一种规则,例如扑克游戏中约定好的各种规则,2<3<4<5<-等,以此作为游戏规则.当所有人都遵循这个规则,那么久可以不需要任何多余的交流就可以进行游戏,这个 ...

最新文章

  1. python在日常工作处理中的应用-记 Python 在实际工作中的第一次应用
  2. CTFshow 命令执行 web71
  3. SAP Spartacus的一个问题 - CheckoutStepsSetGuard无法import
  4. 【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记24 popovers弹窗
  5. 中风偏瘫疾病的预防方法是什么
  6. java中的多对多关系解析_Java中多对多映射关系
  7. 【干货】400+页的《面向机器学习的数学》pdf
  8. LINQ to Entities 比较日期
  9. 受两大市场拖累 IC Insights下调物联网半导体增长预期
  10. 始于CSDN,归于CSDN【一个七年老码农的心声】
  11. Win10系统怎么映射网络驱动器?
  12. 每日一记,养成记录的习惯
  13. matlab画三维图如何更改颜色,MATLAB画三维图像
  14. 163手机登录邮箱显示服务器无法登录,163邮箱登陆不了_为何无法正常登录邮箱 ?...
  15. 高中计算机教学心得,高中教学心得随笔
  16. 西米推荐-FileYee:可能是最简单安全的数据文件备份软件
  17. 采购工作的基本内容和注意事项
  18. 韩国大面积断网,电信公司KT承认其配置错误,此前甩锅DDoS攻击
  19. 区别css单位px、em、rem
  20. html中stroke函数,HTML中stroke是什么意思?

热门文章

  1. ldap 测试表设计
  2. 016.2 String
  3. Jquery对话框基本配置
  4. mysql-mysqldump命令导出多个数据库结构(实战)
  5. 20150109--面向对象+对象传值-01
  6. 新浪网产品设计指南(含UI规范)
  7. 标签 'http' 已声明。标签名称在批查询或存储过程内部必须唯一。
  8. asp2.0 GridView OnRowDataBound event
  9. (JS基础)操作表单
  10. sql中毫秒数与格式化时间的转换