我发现 Linux 文档写错了

作者:小林coding
图解计算机基础网站:https://xiaolincoding.com
大家好,我是小林。
周末的时候,有位读者疑惑为什么 Linux man 手册中关于 netstat 命令中的 tcp listen 状态下的 Recv-Q 和 Send-Q 这两个信息的描述跟我的图解网络写的不一样?
我看了源码后,确认了这个 man 手册写的不对。没想到 Linux 的 man 手册也会出错。
首先,先给大家介绍下 netstat 命令。netstat 命令是查看网络状态很常见的 Linux 命令。
比如,如果我们想查看系统中的进程监听了哪些 TCP 端口,则可以使用下面这个命令: 
接下来,小林带大家分析,为什么我说 man 手册写错了 netstat 命令中 Recv-Q 和 Send-Q 的描述?
疑惑提出
读者提出的疑惑: 
 
 我先给大家翻译一下,man 手册(https://man7.org/linux/man-pages/man8/netstat.8.html)是怎么说的:
- Recv-Q:如果 TCP 连接状态处于 Established,Recv-Q 的数值表示接收缓冲区中还没拷贝到应用层的数据大小;如果 TCP 连接状态处于 Listen 状态,Recv-Q 的数值表示当前 syn 半连接队列的大小(自内核版本 2.6.18 起)
 - Send-Q:如果 TCP 连接状态处于 Established,Send-Q的数值表示发送缓冲区中已发送但未被确认的数据大小;如果 TCP 连接状态处于 Listen 状态,Send-Q 的数值表示 syn 半连接队列的容量(自内核版本 2.6.18 起)。
 
而我通过查阅内核 2.6.18 版本的源码,得到的结论如下:
- Recv-Q:如果 TCP 连接状态处于 Established,Recv-Q 的数值表示接收缓冲区中还没拷贝到应用层的数据大小;如果 TCP 连接状态处于 Listen 状态,Recv-Q 的数值表示当前 syn 半连接队列的大小 当前全连接队列的大小;
 - Send-Q:如果 TCP 连接状态处于 Established,Send-Q的数值表示发送缓冲区中已发送但未被确认的数据大小;如果 TCP 连接状态处于 Listen 状态,Send-Q 的数值表示 syn 半连接队列的容量
 
上面被我划掉的部分,就是我与 man 手册差异的地方。
什么是 TCP 半连接队列和全链接队列?
在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:
- 半连接队列,也称 SYN 队列;
 - 全连接队列,也称 accept 队列;
 
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到全连接队列,等待进程调用 accept 函数时把连接取出来。
 如果你想知道 TCP 半连接和全连接溢出会发生什么?可以看看这篇文章:TCP 半连接队列和全连接队列满了会发生什么?又该如何应对?
源码分析
netstat 工具在获取 TCP 连接的信息的时候,实际上是读取了 /proc/net/tcp 文件里的数据,而这个文件的数据是由内核由 net/ipv4/tcp_ipv4.c 文件中的 tcp4_seq_show() 函数打印的。
所以,我们直接看 tcp4_seq_show() 函数是根据什么信息打印出 Recv-Q 和 Send-Q 的数据。
有一个网站可以在线看 Linux 内核代码:https://elixir.bootlin.com/,每个内核版本的代码都有,平常我都是在这里看。

这次,我们选择内核版本为 2.6.18 查看 tcp4_seq_show() 函数的实现,如下:
static int tcp4_seq_show(struct seq_file *seq, void *v)
{
 .....
 switch (st->state) {
 case TCP_SEQ_STATE_LISTENING:
 case TCP_SEQ_STATE_ESTABLISHED:
  get_tcp4_sock(v, tmpbuf, st->num);
  break;
 .......
 }
 ...
 return 0;
}
我们只分析 tcp 连接状态为 ESTABLISHED 和 LISTENING 时打印的信息,所以接下来看 get_tcp4_sock 函数。
get_tcp4_sock 函数中,打印信息的代码如下: 
 我在图中标红了两行代码,这两行代码分别是 Recv-Q 和 Send-Q 的数据。
我单独把这两行代码抽了出来:
// Send-Q 打印的数据
tp->write_seq - tp->snd_una,
//Recv-Q 打印的数据
(sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
可以看到, 不管 TCP 连接状态是什么, Send-Q 都是发送缓冲区中已发送但未被确认的数据大小。
然后针对 Recv-Q ,在 TCP 连接状态为 LISTEN 时,打印的是 sk_ack_backlog 的值。
那 sk_ack_backlog 的值代表什么意思呢?
下面这个是判断全连接队列是否溢出的函数:
 可以得知,sk_ack_backlog 其实是当前全连接队列的大小,也就是经历三次握手后等待被应用层 accpet() 的连接的数量。
所以,从上面的源码分析过,得到的结论如下:
- netstat 命令中的 Recv-Q:如果 TCP 连接状态处于 Established,Recv-Q 的数值表示接收缓冲区中还没拷贝到应用层的数据大小;如果 TCP 连接状态处于 Listen 状态,Recv-Q 的数值表示当前全连接队列的大小;
 - netstat 命令中的 Send-Q:表示发送缓冲区中已发送但未被确认的数据大小(不管 TCP 是 Listen 状态还是 Established 状态都表示这个意思);
 
好了,至此就分析完了。
最后
看到这,大家肯定会说:小林你太强了吧,为什么对 Linux 内核源码那么熟,这都能分析出来。
其实,我并没有熟读过 Linux 内核源码啦,其实只要大家有好奇心,其实你也能分析出来。
我也是通过网上的资料,一点一点分析出来的,并不是直接就在内核源码里查,不然那真是大海捞针。
我是这样一步一步查资料分析的:
- 先网上查下 netstat 源码,看是根据什么信息打印 Send-Q 和 Recv-Q,然后看到网上有人说是读 /proc/net/tcp 这个文件;
 - 接着,就网上查 /proc/net/tcp 这个文件是怎么打印的,然后看到网上有人说是由 net/ipv4/tcp_ipv4.c 文件中的 tcp4_seq_show() 函数打印的;
 - 最后,再自己去看 tcp4_seq_show 函数的实现,这个函数的代码也不多,就几十行,所以很容易就分析出来了。
 
你看,其实我也是通过「搜索」一步一步分析出来的,其实并没有什么难度。
只是我比较细节一点。
我发现 Linux 文档写错了的更多相关文章
- 详解Linux文档属性、拥有者、群组、权限、差异
		
写在前面 我们都知道Linux是一个支持多用户.多任务的系统,这也是它最优秀的特性,即可能同时有很多人都在系统上进行工作,所以千万不要强制关机,同时,为了保护每个人的隐私和工作环境,针对某一个文档(文 ...
 - 五分钟搞定 Linux 文档全部知识,就看这篇文章
		
作者:无痴迷,不成功 来源:见文末 写在前面 我们都知道Linux是一个支持多用户.多任务的系统,这也是它最优秀的特性,即可能同时有很多人都在系统上进行工作,所以千万不要强制关机,同时,为了保护每个人 ...
 - 理解Linux文档的默认安全机制、隐藏属性、特殊权限,妈妈在也不用担心你从删库到跑路!!!
		
写在前面 前面的章节 详解Linux文档属性.拥有者.群组.权限.差异,介绍了文档的基本权限,包括读写执行(r,w,x),还有文档若干的属性,包括是否为目录(d).文件(-).链接文件(l).拥有者. ...
 - linux文档常见后缀名
		
echo "Start bakup mdsoss Source code ..."_Name="templatecdr_src_"`date +%Y%m%d%H ...
 - UINavigationController 导航控制器 ,根据文档写的一些东西
		
今天讲了导航控制器UINavigationController 和标签栏视图控制器UITabBarController 先来说一说导航视图控制器 UINavigationController 导航控 ...
 - 解决Linux文档显示中文乱码问题以及编码转换
		
解决Linux文档显示中文乱码问题以及编码转换 解决Linux文档显示中文乱码问题以及编码转换 使vi支持GBK编码 由于Windows下默认编码是GBK,而linux下的默认编码是UTF-8,所以打 ...
 - LDP - Linux文档工程的简介,包括帮助,向导和文档
		
总览 SYNOPSIS Linux文档工程(LDP)为Linux社区提供多种自由文档资源,包括向导 (guide),常见问答 (FAQ),入门 (HOWTO) 以及手册页 (man-pages). 作 ...
 - 使用notepad++远程编辑Linux文档
		
上一篇中,我写了如何使用使用ftp服务器实现很方便的通信,这一篇我分享一个使用notepad++的一个NPPFTP插件远程编辑Linux中的文档的小技巧. 首先要确保你的Linux的ftp服务已经打开 ...
 - Linux文档整理之【Jenkins+Docker自动化部署.Net Core】
		
这次整理的文档是Jenkins+Docker实现自动化部署,很早之前就写的,今天有时间就搬到博客园做个记录. Jenkins是基于Java开发的一种持续集成工具,主要用于持续.自动的构建/测试软件等相 ...
 
随机推荐
- 如何监控 Elasticsearch 集群状态?
			
Marvel 让你可以很简单的通过 Kibana 监控 Elasticsearch.你可以实时查看你 的集群健康状态和性能,也可以分析过去的集群.索引和节点指标.
 - JPA、JTA、XA相关索引
			
JPA和分布式事务简介:https://www.cnblogs.com/onlywujun/p/4784233.html JPA.JTA与JMS区别:https://www.cnblogs.com/y ...
 - Java 中应该使用什么数据类型来代表价格?
			
如果不是特别关心内存和性能的话,使用 BigDecimal,否则使用预定义精度的 double 类型.
 - Numpy计算逆矩阵求解线性方程组
			
对于这样的线性方程组: x + y + z = 6 2y + 5z = -4 2x + 5y - z = 27 可以表示成矩阵的形式: 用公式可以表示为:Ax=b,其中A是矩阵,x和b都是列向量 逆矩 ...
 - java中Object类的getClass方法有什么用以及怎么使用?
			
Object类的getClass的用法: Object类中有一个getClass方法,m a r k- t o- w i n:它会返回一个你的对象所对应的一个Class的对象,这个返回来的对象 ...
 - 【Android开发】监听图库数据库的变化
			
步骤一: 保存图片或者删除之前,初始化ContentObserver ScreenshotContentObserver mScreenObserver = new ScreenshotContent ...
 - 将项目导入eclipse中出现的jsp页面报错
			
图片摘自百度经验,实在是每次都会忘了步骤,每次都得重新百度,所以索性自己总结到博客中,下次如果还记不住就直接从博客中看.原谅我实在学渣,呜呜~~~~(>_<)~~~~
 - css3属性之filter初探
			
filter属性是css不常用的一个属性,但是用好了可以给网页增色不少!ps: IE不支持此属性: img { -webkit-filter: grayscale(100%); /* Chrome, ...
 - 实战-DRF快速写接口(认证权限频率)
			
实战-DRF快速写接口 开发环境 Python3.6 Pycharm专业版2021.2.3 Sqlite3 Django 2.2 djangorestframework3.13 测试工具 Postma ...
 - data_loader读取器
			
import random import numpy as np import pandas as pd import cv2 def date_loader(image_dir, file_name ...