Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)
本文将介绍网络连接建立的过程、收发包流程,以及当中应用层、tcp层、ip层、设备层和驱动层各层发挥的作用。
1、应用层
对于使用socket进行网络连接的server端程序。我们会先调用socket函数创建一个套接字:
- fd = socket(AF_INET, SOCK_STREAM, 0);
以上指定了连接协议,socket调用返回一个文件句柄,与socket文件相应的inode不在磁盘上,而是存在于内存。
之后我们指定监听的port、同意与哪些ip建立连接,并调用bind完毕port绑定:
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(PORT);
- server_addr.sin_addr.s_addr = INADDR_ANY;
- bind(fd, (struct sockaddr_in *)&server_addr, sizeof(struct sockaddr_in));
port作为进程的标识,client依据serverip和port号就能找到对应进程。
接着我们调用listen函数。对port进行监听:
- listen(fd, backlog);
backlog值指定了监听队列的长度,下面内核參数限制了backlog可设定的最大值:
- linux # sysctl -a | grep somaxconn
- net.core.somaxconn = 128
监听port在listen调用后变为LISTEN状态:
- linux # netstat -antp | grep 9999
- Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
- tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 8709/server
对应地。client调用connect进行连接,tcp三次握手在connect调用返回之前完毕:
假设server端向client发送SYN+ACK后。client不返回ACK,则server保持半连接(SYN_RECV)状态:
- linux # netstat -np | grep SYN_RECV
- tcp 0 0 0.0.0.0:9999 127.0.0.0.1:5334 SYN_RECV -
若队列中的连接均处于半连接状态。server将不能处理正常的请求,syn泛洪攻击(syn flood)就是利用这个特点完毕DoS(拒绝服务攻击)。
当连接数超过队列长度backlog时。超出的连接也保持为半连接状态。直到数量达到内核參数tcp_max_syn_backlog值,超出该值的连接请求将被丢弃:
- linux # sysctl -a | grep tcp_max_syn
- net.ipv4.tcp_max_syn_backlog = 1024
accept调用用于处理新到来的连接:
- new_fd = accept(fd, (struct sockaddr*)&client_addr, &sin_size);
其返回一个文件描写叙述符。兴许我们能够对该文件描写叙述符调用write、read等操作函数。原监听port仍处于LISTEN状态:
- linux # netstat -antp | grep 9999
- tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 8709/server
- tcp 0 0 127.0.0.1:9999 127.0.0.1:52274 ESTABLISHED -
以上为网络连接建立过程中。应用层所做的工作,server端完毕了socket创建、port绑定、port监听、连接和收发包任务,而client端相对简单,仅仅需包括连接和收发包。
2、tcp层
内核代码中。tcp_sendmsg是tcp发包的主入口函数,该函数中struct
sk_buff结构用于描写叙述一个数据包。
对于超过MTU(maximum transmission unit, 最大传输单元)的数据包。tcp层会对数据包进行拆分,若开启了网口的tcp
segmentation offload功能,则拆分工作由网卡完毕:
- linux # ethtool -k ether
- Offload parameters for eth1:
- rx-checksumming: on
- tx-checksumming: on
- scatter-gather: on
- tcp segmentation offload: on
下面内核參数是内核为tcp socket预留的用于发送数据包的缓冲区大小,单位为byte:
- linux # sysctl -a | grep tcp_wmem
- net.ipv4.tcp_wmem = 4096 16384 131072
默认的用于包发送的缓冲区大小为16M。
除了用于缓冲收发数据包。对于每一个socket,内核还要分配一些数据结构用于保持连接状态,内核对tcp层可使用的内存大小进行了限制:
- linux # sysctl -a | grep tcp_mem
- net.ipv4.tcp_mem = 196608 262144 393216
以上值以页为单位。分别相应最小值、压力值和最大值,并在系统启动、tcp栈初始化时依据内存总量设定。通过proc提供的接口,我们能够查到tcp已用的内存页数:
- linux # cat /proc/net/sockstat
- sockets : used 91
- TCP : inuse 8 orphan 0 tw 11 alloc 13 mem 2
3、ip层
内核代码中。ip_queue_xmit函数是ip层的主入口函数,注意ip层与tcp层操作的都是同一块内存(sk_buff结构)。期间并没有发生数据包相关的内存拷贝。
ip层主要完毕查找路由的任务,其依据路由表配置,决定数据包发往哪个网口,另外,该层实现netfilter的功能。
4、网络设备层
dev_queue_xmit是网络设备层的主入口函数,该层为每一个网口维护一条数据包队列。由ip层下发的数据包放入相应网口的队列中。在该层中。数据包不是直接交给网卡,而是先缓冲起来,再通过软中断(NET_TX_SOFTIRQ)调用qdisc_run函数。该函数将数据包进一步交由网卡处理。
我们运行ifconfig时。txqueuelen指示了网络设备层中。网口队列的长度。
5、驱动层
使用不同驱动的网卡,对应的驱动层代码就不一样。这里以e1000网卡为例。e1000_xmit_frame是该层的主入口函数。该层利用环形队列进行数据包管理,由两个指针负责维护环形队列。运行ethtool命令,我们能够查询网口驱动层环形队列长度:
- linux # ethtool -g eth1
- Ring parameters for ether
- Pre-set maximums:
- RX : 511
- RX Mini : 0
- RX Jumbo : 0
- TX : 511
- Current hardware settings:
- RX : 200
- RX Mini : 0
- RX Jumbo : 0
- TX : 511
以上RX与TX分别指示收包队列与发包队列长度,单位为包个数。
网卡接收到数据包时将产生中断,以通知cpu数据包到来的消息。而网卡接收包又很繁忙,假设每次收发包都向cpu发送硬中断,那cpu将忙于处理网卡中断。
对应的优化方案是NAPI(New API)模式,其关闭网卡硬中断,使网卡不发送中断。而非使cpu不接收网卡中断。在e1000驱动代码中。由e1000_clean函数实现NAPI模式。
不像写文件的过程,磁盘设备层完毕内存数据到磁盘拷贝后,会将消息层层上报,这里的网卡驱动层发包后不会往上层发送通知消息。
收包过程
以上为网络发包所需经过的层次结构,以及各层的大体功能,以下我们简单看下收包过程。
网卡接收到数据包后,通知上层,该过程不会发生拷贝,数据包丢给ip层。
内核代码中,ip_rcv是ip层收包的主入口函数,该函数由软中断调用。
存放数据包的sk_buff结构包括有目的地ip和port信息,此时ip层进行检查,假设目的地ip不是本机。则将包丢弃,假设配置了netfilter。则依照配置规则对包进行转发。
tcp_v4_rcv是tcp层收包的接收入口。其调用__inet_lookup_skb函数查到数据包须要往哪个socket传送。之后将数据包放入tcp层收包队列中,假设应用层有read之类的函数调用。队列中的包将被取出。
tcp层收包使用的内存相同有限制:
- linux # sysctl -a | grep rmem
- net.ipv4.tcp_rmem = 4096 16384 131072
Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)的更多相关文章
- 图解 TCP/IP 第六章 TCP与UDP 笔记6.1 传输层的作用
图解 TCP/IP 第六章 TCP与UDP 笔记6.1 传输层的作用 传输层必须指出这个具体的程序,为了实现这一功能,使用端口号这样一种识别码.根据端口号,就可以识别在传输层上一层的应用程 ...
- Linux音频驱动学习之:(2)移植wm8976声卡驱动(linux-3.4.2)
1.wm8976驱动程序: /* * wm8976.h -- WM8976 Soc Audio driver * * This program is free software; you can re ...
- Linux USB驱动学习总结(一)---- USB基本概念及驱动架构
USB,Universal Serial Bus(通用串行总线),是一个外部总线标准,用于规范电脑与外部设备的连接和通讯.是应用在PC领域的接口技术.USB接口支持设备的即插即用和热插拔功能.USB是 ...
- Linux网络编程学习(六) ----- 管道(第四章)
1.管道的定义 管道就是将一个程序的输出和另外一个程序的输入连接起来的单向通道,比如命令: ls -l|more,就建立了一个管道,获取ls -l的输出作为more的输入,数据就沿着管道从管道的左边流 ...
- 嵌入式Linux驱动学习之路(二十五)虚拟网卡驱动程序
一.协议栈层次对比 设备无关层到驱动层的体系结构 1).网络协议接口层向网络层协议提供提供统一的数据包收发接口,不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过 ...
- TCP/IP协议学习(六) 链路层详解
学习知识很简单,但坚持不懈却又是如此的困难,即使一直对自己说"努力,不能停下"的我也慢慢懈怠了... 闲话不多说,本篇将讲述TCP/IP协议栈的链路层.在本系列第一篇我讲到,TCP ...
- Linux 网卡驱动学习(一)(分析一个虚拟硬件的网络驱动样例)
在Linux,网络分为两个层,各自是网络堆栈协议支持层,以及接收和发送网络协议的设备驱动程序层. 网络堆栈是硬件中独立出来的部分.主要用来支持TCP/IP等多种协议,网络设备驱动层是连接网络堆栈协议层 ...
- Linux摄像头驱动学习之:(六)UVC-基本框架代码分析
仿照内核的自带UVC(usb video class)驱动程序写的一版简化驱动,仅供学习,实际项目开发中应该尽量使用内核自带的驱动,除非内核自带的驱动不支持此款硬件才需要自己写驱动. 下面就直接上代码 ...
- Linux网卡驱动
<网络知识> a:网络模型 OSI模型 TCP模型 虽然OSI模型看着挺完美的,但是过于复杂,这样就会导致不实用,在Linux系统中 ...
随机推荐
- JQuery常用的api[最好是系统地学习一下《锋利的JQuery》]
text http://api.jquery.com/text/ Get the combined text contents of each element in the set of matche ...
- [.Net] Excel导入导出各种方式分析
1.引言 1.1解决哪些问题 现在很多公司用的导出基本上采用的通过gridView导出excel,此种导出存在以下几种问题 1.数据量大的时候有时导出有时会让浏览器卡死,因为导出的excel不是真 ...
- php !=和!==
今天测试了一下!=和!== <?phpheader("Content-type: text/html; charset=utf-8"); if (1!="1&quo ...
- TensorFlow——分布式的TensorFlow运行环境
当我们在大型的数据集上面进行深度学习的训练时,往往需要大量的运行资源,而且还要花费大量时间才能完成训练. 1.分布式TensorFlow的角色与原理 在分布式的TensorFlow中的角色分配如下: ...
- linux编译安装gdb7.10.1
1.下载GDB7.10.1安装包 #wget http://ftp.gnu.org/gnu/gdb/gdb-7.10.1.tar.gz 2.解压 #.tar.gz 3.创建安装目录 #/ #cd /u ...
- O - Masha and Bears
Problem description A family consisting of father bear, mother bear and son bear owns three cars. Fa ...
- Android java处理保留小数点后几位
方式一: 四舍五入 double f = 111231.5585; BigDecimal b = new BigDecimal(f); double f1 = ...
- Python 之 面向对象(一)
一.dir内置函数 在标识符/数据后输入一个.,然后按下TAB键,ipython会 提示该对象能够调用的方法列表 使用内置函数dir传入标识符/数据后,可以查看对象内所有的属性及方法 #查看注释 de ...
- poj3083 Children of the Candy Corn 深搜+广搜
这道题有深搜和广搜.深搜还有要求,靠左或靠右.下面以靠左为例,可以把简单分为上北,下南,左西,右东四个方向.向东就是横坐标i不变,纵坐标j加1(i与j其实就是下标).其他方向也可以这样确定.通过上一步 ...
- MySQL 5.6 Reference Manual-14.4 InnoDB Configuration
14.4 InnoDB Configuration 14.4.1 InnoDB Initialization and Startup Configuration 14.4.2 Configuring ...