Skip to main content

Tmux 快速参考手册

· 7 min read
Mo
Software Engineer

注意C-b 表示同时按住 Ctrlb 键,这是默认前缀键。按下 C-b 后,释放按键,然后按后续命令键。

核心命令

以下是快速上手 tmux 的最常用命令。

会话管理

命令 / 快捷键描述注释
tmux启动一个新会话默认创建未命名会话
tmux new -s name启动一个命名的会话使用 name 替换为自定义会话名,例如 mysession
tmux ls列出所有会话显示所有正在运行的 tmux 会话
tmux a附着到最近使用的会话快速恢复上次会话
tmux a -t name附着到指定会话使用会话名,例如 tmux a -t mysession
C-b d从当前会话分离会话继续在后台运行,可稍后重新附着
C-b $重命名当前会话弹出提示框输入新名称

注释:会话管理是 tmux 的核心功能,建议为长期运行的任务创建命名会话,以便更容易管理和重新附着。

窗口操作

基本操作

快捷键描述注释
C-b c创建新窗口新窗口添加到窗口列表末尾
C-b ,重命名当前窗口弹出提示框输入新名称
C-b &关闭当前窗口需要确认,防止误操作
C-b w列出所有窗口显示交互式窗口列表,可选择切换
C-b f按名称查找窗口输入窗口名称的一部分进行搜索

注释:窗口类似于浏览器标签页,适合组织多个任务。使用 C-b w 可以快速预览和切换窗口。

窗口导航

快捷键描述注释
C-b n切换到下一个窗口按窗口顺序循环
C-b p切换到上一个窗口按窗口顺序循环
C-b l切换到上次活动窗口在当前和上一个窗口间快速切换
C-b 0-9切换到指定编号的窗口编号从 0 开始,快速定位
C-b :按索引切换窗口输入窗口索引号,适合精确选择

窗口排列

快捷键描述注释
C-b :移动窗口到指定索引输入新索引号,例如 :move-window -t 2
C-b :swap-window -t交换窗口位置需要在命令模式下输入目标窗口索引
C-b {与上一个窗口交换需要在 tmux.conf 中配置自定义绑定
C-b }与下一个窗口交换需要在 tmux.conf 中配置自定义绑定

注释:窗口排列功能适合调整窗口顺序,C-b {C-b } 需要自定义配置,建议参考 tmux 文档。

命令行管理

命令描述注释
tmux new-window创建新窗口默认添加到当前会话
tmux new-window -n name创建指定名称的窗口例如 tmux new-window -n mywindow
tmux select-window -t :0-9按索引选择窗口例如 tmux select-window -t :2
tmux select-window -t :name按名称选择窗口例如 tmux select-window -t :mywindow
tmux rename-window "new name"重命名当前窗口例如 tmux rename-window "code"
tmux kill-window关闭当前窗口等同于 C-b &
tmux list-windows列出当前会话的所有窗口显示窗口编号和名称

窗格操作

创建窗格

快捷键描述注释
C-b %垂直分割窗格(左右)将当前窗格一分为二
C-b "水平分割窗格(上下)将当前窗格一分为二
C-b !将窗格转换为窗口创建一个新窗口,仅包含此窗格
C-b x关闭当前窗格需要确认,防止误操作

注释:窗格是 tmux 的最小工作单元,适合在单一窗口内运行多个终端任务。

窗格导航

快捷键描述注释
C-b ←↑→↓在窗格间移动使用方向键切换到指定方向的窗格
C-b o切换到下一个窗格按窗格顺序循环
C-b ;切换到上次活动窗格快速在两个窗格间切换
C-b q显示窗格编号编号短暂显示,快速按编号键切换
C-b z切换窗格缩放最大化/恢复当前窗格,适合专注单一任务

窗格调整

快捷键描述注释
C-b Ctrl+←↑→↓调整窗格大小按住 Ctrl 和方向键,逐步调整
C-b Alt+←↑→↓快速调整窗格(5 格)按住 Alt 和方向键,适合大幅调整
C-b :resize-pane -D 10向下调整 10 格可使用 -U(上)、-L(左)、-R(右)
C-b {与上一个窗格交换调整窗格顺序
C-b }与下一个窗格交换调整窗格顺序

窗格布局

快捷键描述注释
C-b space循环切换预设布局提供多种窗格排列方式
C-b Alt+1切换到均匀水平布局所有窗格水平均分
C-b Alt+2切换到均匀垂直布局所有窗格垂直均分
C-b Alt+3切换到主水平布局一个主窗格在上,其余在下
C-b Alt+4切换到主垂直布局一个主窗格在左,其余在右
C-b Alt+5切换到平铺布局所有窗格尽可能均匀分布

注释:布局功能适合根据任务需求调整窗格排列,C-b space 是快速尝试不同布局的便捷方式。

复制模式与滚动

基本操作

快捷键描述注释
C-b [进入复制模式用于滚动和复制文本
q退出复制模式直接返回正常模式
C-b ]粘贴复制的文本粘贴上次复制的内容

导航(复制模式)

按键描述注释
←↑→↓移动光标vi 模式下使用 hjkl
PgUp, PgDn上下翻页快速滚动缓冲区
g跳转到缓冲区顶部vi 模式下为 gg
G跳转到缓冲区底部vi 模式下为 G
H, M, L移动到屏幕顶部/中间/底部快速定位屏幕位置
w, b前进/后退一个单词适合文本导航
0, ^, $移动到行首/首非空字符/行尾精确控制光标

选择与复制(复制模式)

按键描述注释
Space开始选择vi 模式下为 v
Enter复制选择并退出vi 模式下为 y
Esc清除选择取消当前选中内容
A追加到缓冲区将新选择追加到已有缓冲区
R切换矩形选择vi 模式下为 C-v,用于块选择

搜索(复制模式)

按键描述注释
/向前搜索输入文本后按 Enter 搜索
?向后搜索输入文本后按 Enter 搜索
n下一个匹配项继续搜索下一个
N上一个匹配项继续搜索上一个
C-r增量反向搜索vi 风格,边输入边显示结果
C-s增量向前搜索vi 风格,边输入边显示结果

注释:复制模式是 tmux 的强大功能,适合查看历史输出或复制命令结果。vi 模式需要启用 set -g mode-keys vi

高级会话管理

命令行管理

命令描述注释
tmux attach -t mysession附着到指定会话例如 tmux attach -t mysession
tmux kill-session -t mysession删除指定会话谨慎使用,删除后无法恢复
tmux kill-server终止 tmux 服务器及所有会话所有会话将丢失,谨慎操作
tmux switch -t mysession从当前会话切换到指定会话在 tmux 内部使用
tmux rename-session -t old-name new-name重命名会话例如 tmux rename-session -t old new

快捷键

快捷键描述注释
C-b )切换到下一个会话按会话顺序循环
C-b (切换到上一个会话按会话顺序循环
C-b s选择要分离的客户端适合多客户端附着同一会话时使用
C-b D创建新会话使用命令模式创建
C-b :new -s name切换到最后会话需要在 tmux.conf 中配置

注释:高级会话管理适合多任务场景,例如同时运行多个项目。使用 tmux ls 定期检查会话状态。


© 2025 TmuxAI | https://tmuxai.dev

深入理解Linux中的网络地址转换(NAT)和数据包重定向

· 8 min read
Mo
Software Engineer

Source: Imgur

想象一栋房子里所有设备都连接到你的Wi-Fi网络。从任何设备上,尝试通过访问https://www.whatismyip.com/来查找你的公共IP地址。IPv4地址字段对所有设备来说都应相同。这是你的互联网服务提供商(ISP)分配给路由器的IP地址,该路由器作为你互联网的网关。

那么这里发生了什么?如果IPv4地址相同,路由器如何区分这些设备?为什么不能为每个设备分配一个唯一的IPv4地址?

IPv4地址的大小为4字节或32位。因此,全球范围内可以有2^32个唯一的IPv4地址。2^32 = 4,294,967,296。约40亿个地址。现在,想象一个数据中心试图搭建由数千台服务器组成的网络。想象一个家庭拥有5台设备。想象一家拥有数千名员工的公司,每位员工至少拥有一台设备。如果为每个设备分配一个唯一的IPv4地址,我们很快就会耗尽地址资源。

网络入门课程可能会提到IPv6。通过计算(2^128),IPv6可支持多达340万亿亿亿个地址。这确实是海量地址!那么这应该能解决IPv4问题,对吧?只需迁移到IPv6即可大功告成!但现实情况令人失望。要实现这一点,全球每一家互联网服务提供商(ISP)都必须迁移到IPv6。全球所有基于IPv4设计的硬件和软件都必须支持IPv6。过渡过程需要在一段时间内同时运行IPv4和IPv6。应用程序需要更新以支持IPv6。归根结底:这需要大量工作。

那么在此之前我们该怎么办?如果每个路由设备都有一个唯一的、公开可见的IPv4地址,而网络内的每个设备都有一个私有IPv4地址呢?而路由器则负责维护一个映射表,类似于:

${private_ip}:${private_port} -> ${shared_public_ip}:${public_port}`

路由器只需在转发数据包前重写其头部信息。

这就是网络地址转换(NAT)的基本原理。

历史

根据1994年的RFC 1631,NAT被提议作为解决IPv4地址短缺问题的短期解决方案。如今,在2025年,NAT已被广泛应用于各个领域。

一个永久存在的临时方案。这听起来是否很熟悉?

本应埋设地下的电缆却暴露在外。来源:Twitter.

类型

  1. 基本/静态NAT

最简单的NAT类型提供IP地址的一对一转换。以下是两个使用不同IP地址范围的网络示例:

Network A: uses 192.168.1.0/24
Network B: uses 10.0.0.0/24

如果您需要网络 A 上的设备与网络 B 进行通信,可以使用 NAT 设备来转换 IP 地址。

一个示例映射如下所示:

192.168.1.10 (Network A) <-> 10.0.0.10 (Network B equivalent)
  1. 端口地址转换(PAT)

基本NAT过于简单,无法支持同一网络中的多个设备。端口地址转换(PAT)是一种技术,允许私有网络中的多个设备通过使用不同端口共享单个公共IP地址。与仅使用单个私有IP到公共IP映射不同,PAT通过结合IP地址和端口号来唯一标识每个设备。

  1. 全锥形NAT / 一对一NAT / NAT 1

一旦内部设备向外部主机发送数据包,任何外部主机只要知道公共IP地址和端口号,即可向该内部设备发送数据包。

  1. 受限锥形NAT / NAT 2

与全锥形NAT类似,但增加了限制。只有之前曾向其发送过数据包的外部主机才能向您发送数据包。

  1. 端口受限锥形NAT / NAT 3

这是受限锥形NAT的更严格版本。外部主机不仅必须与IP地址匹配,还必须与出站通信中指定的端口号匹配。

  1. 对称NAT / NAT 4

这是最严格的NAT类型。来自同一私有IP地址和端口发送到特定目标IP地址和端口的请求将映射到相同的IP地址和端口。如果主机向不同目标发送具有相同源IP地址和端口号的数据包,则使用不同的NAT映射。

对于构建依赖于WebRTC的应用程序的人来说,此类NAT会导致WebRTC无法通过STUN正常工作。您需要使用TURN服务器在两个设备之间中继数据包。

您可以通过使用Check My NAT等工具来查看您当前的NAT类型。

需要注意的是,上述列表中的类型并非互斥。例如,受限锥形NAT与PAT行为可能同时存在。

路由器是如何实现NAT的?

OpenWrt这样的路由器操作系统项目在底层使用Linux,具体来说是nftables模块。我深入研究了Linux中的nftables源代码。

由于NAT涉及对IP地址和端口的操作,因此只有在涉及TCP和UDP时讨论它才有意义。这与我们在nfnathelper.h中看到的内容一致。该头文件中包含两个核心函数:nf_nat_mangle_udp_packetnf_nat_mangle_tcp_packet

让我们来看看 nf_nat_mangle_udp_packet

if (skb_ensure_writable(skb, skb->len)) return false;

在NAT进行任何编辑操作之前,它会确保数据包内存可写。我喜欢这种不做任何假设的处理方式。这种对可变性的明确检查非常简洁。

if (rep_len > match_len &&
rep_len - match_len > skb_tailroom(skb) &&
!enlarge_skb(skb, rep_len - match_len))
return false;

如果替换字符串比原字符串更长,且空间不足,请尝试扩展缓冲区。如果扩展缓冲区失败,则放弃操作。

mangle_contents(skb, protoff + sizeof(*udph),
match_offset, match_len, rep_buffer, rep_len);

这是核心部分:将位于 match_offset 处的 match\_len 个字节替换为来自 rep_bufferrep_len 个字节。此操作会修改数据包中实际的有效负载内容。

udph->len = htons(datalen);

当您更改有效负载大小时,必须更新头部的 .len 字段以匹配新的数据包长度。

nf_nat_csum_recalc(...)

NAT 不仅仅涉及 IP 地址和端口。它必须更新校验和,以确保数据包保持有效。否则,接收主机将将其视为损坏并拒绝。

因此,NAT 可以说是一种实时进行的数据包处理操作,直接在数据传输路径中完成!

作为工程师,你身边的 NAT 应用——Docker!

即使你从未编写过防火墙规则,只要使用过 Docker,你就依赖于 Linux NAT。每次你运行:

docker run -p 8080:80 nginx # ${host_port}:${container_port}

根据 Docker 的 文档,他们使用 iptables。因此,我们应该期望看到类似以下的规则:

iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80

这告诉 Linux 内核:“如果有一个数据包到达主机的 8080 端口,将其目标 IP 和端口重写,然后将其发送到容器中。”

重点是:NAT 不仅仅是数据中心或 ISP 的事情。它无处不在!

限制

尽管NAT(网络地址转换)帮助互联网突破了IPv4的限制,但它并非完美解决方案。

问题:

  1. 它破坏了端到端连接。
  2. 它使加密变得更加困难,因为它会修改数据包头。
  3. 它使点对点应用程序变得复杂。增加了复杂性,有时甚至增加了延迟。
  4. 它需要内存来存在,因为它必须维护所有连接的映射。

IPv6

IPv6 可以真正解决 NAT 的限制。它提供了更大的地址空间,允许更多设备连接到互联网而无需 NAT。

根据https://www.google.com/intl/en/ipv6/statistics.html,我们尚未达到这一目标。

from to vivekn

Ubuntu 20.04 添加和配置 Swap 空间

· 4 min read
Mo
Software Engineer

创建交换空间文件

在此教程中,我们将创建2 GB大小的交换空间文件。如果要添加更多交换空间,请将2G替换为你所需交换空间的大小。

创建一个指定大小文件的方式在Ubuntu 20.04中有两种,分别fallocate和dd命令。但你也可以使用你喜欢的方式创建交换空间文件,

fallocate和dd命令都可以帮助快速创建指定大小的文件,fallocate比dd命令更易于理解。具体选择取决于你。

如果您的系统上没有fallocate命令,或者您收到一条错误消息,提示fallocate failed: Operation not supported操作不支持。

你可使用dd命令创建swap交换空间文件。以下fallocate和dd命令将会在你Ubuntu 20.04的根目录中创建交换空间文件/swapfile,大小是2G。

Debian apt-get update NO_PUBKEY 问题解决方法

· One min read
Mo
Software Engineer

I had the same problem of "gpg: keyserver timed out" with a couple of different servers. Finally, it turned out that I didn't need to do that manually at all. On a Debian system, the simple solution which fixed it was just (as root or precede with sudo):