检查 Linux 系统上的网络连接

Summary: Linux 系统提供了许多有用的命令来检查网络配置和连接。下面来看几个，包括 ifquery、ifup、ifdown 和 ifconfig。

>
> Linux 系统提供了许多有用的命令来检查网络配置和连接。下面来看几个，包括 `ifquery`、`ifup`、`ifdown` 和 `ifconfig`。
>
>
>

Linux 上有许多可用于查看网络设置和连接的命令。在今天的文章中，我们将会通过一些非常方便的命令来看看它们是如何工作的。

![](/data/attachment/album/201712/01/201507wrds6brsa7aq7sdd.jpeg)

### ifquery 命令

一个非常有用的命令是 `ifquery`。这个命令应该会显示一个网络接口列表。但是，你可能只会看到类似这样的内容 - 仅显示回环接口：

```
$ ifquery --list
lo

```

如果是这种情况，那说明你的 `/etc/network/interfaces` 不包括除了回环接口之外的网络接口信息。在下面的例子中，假设你使用 DHCP 来分配地址，且如果你希望它更有用的话，你可以添加例子最后的两行。

```
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp

```

### ifup 和 ifdown 命令

可以使用相关的 `ifup` 和 `ifdown` 命令来打开网络连接并根据需要将其关闭，只要该文件具有所需的描述性数据即可。请记住，“if” 在这里意思是<ruby> 接口 <rt>  interface </rt></ruby>，这与 `ifconfig` 命令中的一样，而不是<ruby> 如果我只有一个大脑 <rt>  if I only had a brain </rt></ruby> 中的 “if”。

### ifconfig 命令

另外，`ifconfig` 命令完全不读取 `/etc/network/interfaces`，但是仍然提供了网络接口相当多的有用信息 —— 配置数据以及可以告诉你每个接口有多忙的数据包计数。`ifconfig` 命令也可用于关闭和重新启动网络接口（例如：`ifconfig eth0 down`）。

```
$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:1e:4f:c8:43:fc
          inet addr:192.168.0.6  Bcast:192.168.0.255  Mask:255.255.255.0
          inet6 addr: fe80::b44b:bdb6:2527:6ae9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:60474 errors:0 dropped:0 overruns:0 frame:0
          TX packets:33463 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:43922053 (43.9 MB)  TX bytes:4000460 (4.0 MB)
          Interrupt:21 Memory:fe9e0000-fea00000

```

输出中的 RX 和 TX 数据包计数很低。此外，没有报告错误或数据包冲突。或许可以用 `uptime` 命令确认此系统最近才重新启动。

上面显示的广播 （Bcast） 和网络掩码 （Mask） 地址表明系统运行在 C 类等效网络（默认）上，所以本地地址范围从 `192.168.0.1` 到 `192.168.0.254`。

### netstat 命令

`netstat` 命令提供有关路由和网络连接的信息。`netstat -rn` 命令显示系统的路由表。192.168.0.1 是本地网关 （Flags=UG)。

```
$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.0.1     0.0.0.0         UG        0 0          0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U         0 0          0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0

```

上面输出中的 `169.254.0.0` 条目仅在你正在使用或计划使用本地链路通信时才有必要。如果不是这样的话，你可以在 `/etc/network/if-up.d/avahi-autoipd` 中注释掉相关的行：

```
$ tail -12 /etc/network/if-up.d/avahi-autoipd
#if [ -x /bin/ip ]; then
#       # route already present?
#       ip route show | grep -q '^169.254.0.0/16[[:space:]]' && exit 0
#
#       /bin/ip route add 169.254.0.0/16 dev $IFACE metric 1000 scope link
#elif [ -x /sbin/route ]; then
#       # route already present?
#       /sbin/route -n | egrep -q "^169.254.0.0[[:space:]]" && exit 0
#
#       /sbin/route add -net 169.254.0.0 netmask 255.255.0.0 dev $IFACE metric 1000
#fi

```

### netstat -a 命令

`netstat -a` 命令将显示“所有”网络连接。为了将其限制为显示正在监听和已建立的连接（通常更有用），请改用 `netstat -at` 命令。

```
$ netstat -at
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 *:ssh                   *:*                     LISTEN
tcp        0      0 localhost:ipp           *:*                     LISTEN
tcp        0      0 localhost:smtp          *:*                     LISTEN
tcp        0    256 192.168.0.6:ssh         192.168.0.32:53550      ESTABLISHED
tcp6       0      0 [::]:http               [::]:*                  LISTEN
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN
tcp6       0      0 ip6-localhost:ipp       [::]:*                  LISTEN
tcp6       0      0 ip6-localhost:smtp      [::]:*                  LISTEN

```

### host 命令

`host` 命令就像 `nslookup` 一样，用来查询远程系统的 IP 地址，但是还提供系统的邮箱处理地址。

```
$ host world.std.com
world.std.com has address 192.74.137.5
world.std.com mail is handled by 10 smtp.theworld.com.

```

### nslookup 命令

`nslookup` 还提供系统中（本例中是本地系统）提供 DNS 查询服务的信息。

```
$ nslookup world.std.com
Server:         127.0.1.1
Address:        127.0.1.1#53

Non-authoritative answer:
Name:   world.std.com
Address: 192.74.137.5

```

### dig 命令

`dig` 命令提供了很多有关连接到远程系统的信息 - 包括与我们通信的名称服务器以及查询需要多长时间进行响应，并经常用于故障排除。

```
$ dig world.std.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> world.std.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28679
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;world.std.com.                 IN      A

;; ANSWER SECTION:
world.std.com.          78146   IN      A       192.74.137.5

;; Query time: 37 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Mon Oct 09 13:26:46 EDT 2017
;; MSG SIZE  rcvd: 58

```

### nmap 命令

`nmap` 经常用于探查远程系统，但是同样也用于报告本地系统提供的服务。在下面的输出中，我们可以看到登录可以使用 ssh、smtp 用于电子邮箱、web 站点也是启用的，并且 ipp 打印服务正在运行。

```
$ nmap localhost

Starting Nmap 7.01 ( https://nmap.org ) at 2017-10-09 15:01 EDT
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00016s latency).
Not shown: 996 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
25/tcp  open  smtp
80/tcp  open  http
631/tcp open  ipp

Nmap done: 1 IP address (1 host up) scanned in 0.09 seconds

```

Linux 系统提供了很多有用的命令用于查看网络配置和连接。如果你都探索完了，请记住 `apropos network` 或许会让你了解更多。

---

via: <https://www.networkworld.com/article/3230519/linux/examining-network-connections-on-linux-systems.html>

作者：[Sandra Henry-Stocker](https://www.networkworld.com/author/Sandra-Henry_Stocker/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何在 Linux 下安装安卓文件传输助手

如果你尝试在 Ubuntu 下连接你的安卓手机，你也许可以试试 Linux 下的安卓文件传输助手。

本质上来说，这个应用是谷歌 macOS 版本的一个克隆。它是用 Qt 编写的，用户界面非常简洁，使得你能轻松在 Ubuntu 和安卓手机之间传输文件和文件夹。

现在，有可能一部分人想知道有什么是这个应用可以做，而 Nautilus（Ubuntu 默认的文件资源管理器）不能做的，答案是没有。

当我将我的 Nexus 5X（记得选择 [媒体传输协议 MTP](https://en.wikipedia.org/wiki/Media_Transfer_Protocol) 选项）连接在 Ubuntu 上时，在 [GVfs](https://en.wikipedia.org/wiki/GVfs)（LCTT 译注： GNOME 桌面下的虚拟文件系统）的帮助下，我可以打开、浏览和管理我的手机，就像它是一个普通的 U 盘一样。

[![Nautilus MTP integration with a Nexus 5X](/data/attachment/album/201712/03/104921py9cpjjbmdmvzya2.jpg)](http://www.omgubuntu.co.uk/wp-content/uploads/2017/11/browsing-android-mtp-nautilus.jpg)

但是*一些*用户在使用默认的文件管理器时，在 MTP 的某些功能上会出现问题：比如文件夹没有正确加载，创建新文件夹后此文件夹不存在，或者无法在媒体播放器中使用自己的手机。

这就是要为 Linux 系统用户设计一个安卓文件传输助手应用的原因，将这个应用当做将 MTP 设备安装在 Linux 下的另一种选择。如果你使用 Linux 下的默认应用时一切正常，你也许并不需要尝试使用它 (除非你真的很想尝试新鲜事物)。

![Android File Transfer Linux App](/data/attachment/album/201712/03/104923x8lhru37kv4b6bnu.jpg)

该 app 特点：

* 简洁直观的用户界面
* 支持文件拖放功能（从 Linux 系统到手机）
* 支持批量下载 (从手机到 Linux系统)
* 显示传输进程对话框
* FUSE 模块支持
* 没有文件大小限制
* 可选命令行工具

### Ubuntu 下安装安卓手机文件助手的步骤

以上就是对这个应用的介绍，下面是如何安装它的具体步骤。

这有一个 [PPA]（个人软件包集）源为 Ubuntu 14.04 LTS、16.04 LTS 和 Ubuntu 17.10 提供可用应用。

为了将这一 PPA 加入你的软件资源列表中，执行这条命令：

```
sudo add-apt-repository ppa:samoilov-lex/aftl-stable

```

接着，为了在 Ubuntu 下安装 Linux版本的安卓文件传输助手，执行：

```
sudo apt-get update && sudo apt install android-file-transfer

```

这样就行了。

你会在你的应用列表中发现这一应用的启动图标。

在你启动这一应用之前，要确保没有其他应用（比如 Nautilus）已经挂载了你的手机。如果其它应用正在使用你的手机，就会显示“无法找到 MTP 设备”。要解决这一问题，将你的手机从 Nautilus（或者任何正在使用你的手机的应用）上移除，然后再重新启动安卓文件传输助手。

---

via: <http://www.omgubuntu.co.uk/2017/11/android-file-transfer-app-linux>

作者：[JOEY SNEDDON](https://plus.google.com/117485690627814051450/?rel=author) 译者：[wenwensnow](https://github.com/wenwensnow) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


开源云技能认证：系统管理员的核心竞争力

![os jobs](/data/attachment/album/201712/03/105709hqovjlzrh9rd49jy.jpg "os jobs")

>
> [2017年开源工作报告](https://www.linuxfoundation.org/blog/2017-jobs-report-highlights-demand-open-source-skills/)（以下简称“报告”）显示，具有开源云技术认证的系统管理员往往能获得更高的薪酬。
>
>
>

报告调查的受访者中，53% 认为系统管理员是雇主们最期望被填补的职位空缺之一，因此，技术娴熟的系统管理员更受青睐而收获高薪职位，但这一职位，并没想象中那么容易填补。

系统管理员主要负责服务器和其他电脑操作系统的安装、服务支持和维护，及时处理服务中断和预防其他问题的出现。

总的来说，今年的报告指出开源领域人才需求最大的有开源云（47%），应用开发（44%），大数据（43%），开发运营和安全（42%）。

此外，报告对人事经理的调查显示，58% 期望招揽更多的开源人才，67% 认为开源人才的需求增长会比业内其他领域更甚。有些单位视开源人才为招聘最优选则，它们招聘的开源人才较上年增长了 2 个百分点。

同时，89% 的人事经理认为很难找到颇具天赋的开源人才。

### 为什么要获取认证

报告显示，对系统管理员的需求刺激着人事经理为 53% 的组织/机构提供正规的培训和专业技术认证，而这一比例去年为 47%。

对系统管理方面感兴趣的 IT 人才考虑获取 Linux 认证已成为行业规律。随便查看几个知名的招聘网站，你就能发现：[CompTIA Linux+](https://certification.comptia.org/certifications/linux?tracking=getCertified/certifications/linux.aspx) 认证是入门级 Linux 系统管理员的最高认证；如果想胜任高级别的系统管理员职位，获取[红帽认证工程师（RHCE）](https://www.redhat.com/en/services/certification/rhce)和[红帽认证系统管理员（RHCSA）](https://www.redhat.com/en/services/certification/rhcsa)则是不可或缺的。

戴士（Dice）[2017 技术行业薪资调查](http://marketing.dice.com/pdf/Dice_TechSalarySurvey_2017.pdf?aliId=105832232)显示，2016 年系统管理员的薪水为 79,538 美元，较上年下降了 0.8%；系统架构师的薪水为 125,946 美元，同比下降 4.7%。尽管如此，该调查发现“高水平专业人才仍最受欢迎，特别是那些精通支持产业转型发展所需技术的人才”。

在开源技术方面，HBase（一个开源的分布式数据库）技术人才的薪水在戴士 2017 技术行业薪资调查中排第一。在计算机网络和数据库领域，掌握 OpenVMS 操作系统技术也能获得高薪。

### 成为出色的系统管理员

出色的系统管理员须在问题出现时马上处理，这意味着你必须时刻准备应对可能出现的状况。这个职位追求“零责备的、精益的、流程或技术上交互式改进的”思维方式和善于自我完善的人格，成为一个系统管理员意味着“你必将与开源软件如 Linux、BSD 甚至开源 Solaris 等结下不解之缘”，Paul English  译注1 在 [opensource.com](https://opensource.com/article/17/7/truth-about-sysadmins) 上发文指出。

Paul English 认为，现在的系统管理员较以前而言，要更多地与软件打交道，而且要能够编写脚本来协助系统管理。

>
> 译注1：Paul English，计算机科学学士，UNIX/Linux 系统管理员，PreOS Security Inc. 公司 CEO，2015-2017 年于为推动系统管理员发展实践的非盈利组织——<ruby> 专业系统管理员联盟 <rt>  League of Professional System Administrator </rt></ruby>担任董事会成员。
>
>
>

### 展望 2018

[Robert Half 2018 年技术人才薪资导览](https://www.roberthalf.com/salary-guide/technology)预测 2018 年北美地区许多单位将聘用大量系统管理方面的专业人才，同时个人软实力和领导力水平作为优秀人才的考量因素，越来越受到重视。

该报告指出：“良好的聆听能力和批判性思维能力对于理解和解决用户的问题和担忧至关重要，也是 IT 从业者必须具备的重要技能，特别是从事服务台和桌面支持工作相关的技术人员。”

这与[Linux基金会](https://www.linux.com/learn/10-essential-skills-novice-junior-and-senior-sysadmins%20%20) 译注2 提出的不同阶段的系统管理员必备技能相一致，都强调了强大的分析能力和快速处理问题的能力。

>
> 译注2：<ruby> Linux 基金会 <rt>  The Linux Foundation </rt></ruby>，成立于 2000 年，致力于围绕开源项目构建可持续发展的生态系统，以加速开源项目的技术开发和商业应用；它是世界上最大的开源非盈利组织，在推广、保护和推进 Linux 发展，协同开发，维护“历史上最大的共享资源”上功勋卓越。
>
>
>

如果想逐渐爬上系统管理员职位的金字塔上层，还应该对系统配置的结构化方法充满兴趣；且拥有解决系统安全问题的经验；用户身份验证管理的经验；与非技术人员进行非技术交流的能力；以及优化系统以满足最新的安全需求的能力。

* [下载](http://bit.ly/2017OSSjobsreport)2017年开源工作报告全文，以获取更多信息。

---

via: <https://www.linux.com/blog/open-source-cloud-skills-and-certification-are-key-sysadmins>

作者：[linux.com](https://www.linux.com/blog/open-source-cloud-skills-and-certification-are-key-sysadmins) 译者：[wangy325](https://github.com/wangy325) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


在命令行中使用 DuckDuckGo 搜索

Summary: 像 Googler 一样，ddgr 是一个完全开源而且非官方的工具。没错，它并不属于 DuckDuckGo。所以，如果你发现它返回的结果有些奇怪，请先询问这个工具的开发者，而不是搜索引擎的开发者。

![](/data/attachment/album/201712/03/110113cfcblroim9qorqlq.png)

此前我们介绍了[如何在命令行中使用 Google 搜索](http://www.omgubuntu.co.uk/2017/08/search-google-from-the-command-line)。许多读者反馈说他们平时使用 [Duck Duck Go](http://duckduckgo.com/)，这是一个功能强大而且保密性很强的搜索引擎。

正巧，最近出现了一款能够从命令行搜索 DuckDuckGo 的工具。它叫做 ddgr（我把它读作 “dodger”），非常好用。

像 [Googler](https://github.com/jarun/googler) 一样，ddgr 是一个完全开源而且非官方的工具。没错，它并不属于 DuckDuckGo。所以，如果你发现它返回的结果有些奇怪，请先询问这个工具的开发者，而不是搜索引擎的开发者。

### DuckDuckGo 命令行应用

![](/data/attachment/album/201712/03/110114spmjuykxre0555jm.gif)

[DuckDuckGo Bangs（DuckDuckGo 快捷搜索）](https://duckduckgo.com/bang) 可以帮助你轻易地在 DuckDuckGo 上找到想要的信息（甚至 *本网站 omgubuntu* 都有快捷搜索）。ddgr 非常忠实地呈现了这个功能。

和网页版不同的是，你可以更改每页返回多少结果。这比起每次查询都要看三十多条结果要方便一些。默认界面经过了精心设计，在不影响可读性的情况下尽量减少了占用空间。

`ddgr` 有许多功能和亮点，包括：

* 更改搜索结果数
* 支持 Bash 自动补全
* 使用 DuckDuckGo Bangs
* 在浏览器中打开链接
* ”手气不错“选项
* 基于时间、地区、文件类型等的筛选功能
* 极少的依赖项

你可以从 Github 的项目页面上下载支持各种系统的 `ddgr`：

* [从 Github 下载 “ddgr”](https://github.com/jarun/ddgr/releases/tag/v1.1)

另外，在 Ubuntu 16.04 LTS 或更新版本中，你可以使用 PPA 安装 ddgr。这个仓库由 ddgr 的开发者维护。如果你想要保持在最新版本的话，推荐使用这种方式安装。

需要提醒的是，在本文创作时，这个 PPA 中的 ddgr *并不是* 最新版本，而是一个稍旧的版本（缺少 -num 选项）。

使用以下命令添加 PPA：

```
sudo add-apt-repository ppa:twodopeshaggy/jarun
sudo apt-get update

```

### 如何使用 ddgr 在命令行中搜索 DuckDuckGo

安装完毕后，你只需打开你的终端模拟器，并运行：

```
ddgr

```

然后输入查询内容：

```
search-term

```

你可以限制搜索结果数：

```
ddgr --num 5 search-term

```

或者自动在浏览器中打开第一条搜索结果：

```
ddgr -j search-term

```

你可以使用参数和选项来提高搜索精确度。使用以下命令来查看所有的参数：

```
ddgr -h

```

---

via: <http://www.omgubuntu.co.uk/2017/11/duck-duck-go-terminal-app>

作者：[JOEY SNEDDON](https://plus.google.com/117485690627814051450/?rel=author) 译者：[yixunx](https://github.com/yixunx) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


回复：块层介绍第一部分 - 块 I/O 层

回复：amarao 在[块层介绍第一部分：块 I/O 层](https://lwn.net/Articles/737588/) 中提的问题

先前的文章：[块层介绍第一部分：块 I/O 层](https://lwn.net/Articles/736534/)

![](/data/attachment/album/201712/03/111453ac1rfngngbnb2fct.png)

嗨，

你在这里描述的问题与块层不直接相关。这可能是一个驱动错误、可能是一个 SCSI 层错误，但绝对不是一个块层的问题。

不幸的是，报告针对 Linux 的错误是一件难事。有些开发者拒绝去看 bugzilla，有些开发者喜欢它，有些（像我这样）只能勉强地使用它。

另一种方法是发送电子邮件。为此，你需要选择正确的邮件列表，还有也许是正确的开发人员，当他们心情愉快，或者不是太忙或者不是假期时找到它们。有些人会努力回复所有，有些是完全不可预知的 - 这对我来说通常会发送一个补丁，包含一些错误报告。如果你只是有一个你自己几乎都不了解的 bug，那么你的预期响应率可能会更低。很遗憾，但这是是真的。

许多 bug 都会得到回应和处理，但很多 bug 都没有。

我不认为说没有人关心是公平的，但是没有人认为它如你想的那样重要是有可能的。如果你想要一个解决方案，那么你需要驱动它。一个驱动它的方法是花钱请顾问或者与经销商签订支持合同。我怀疑你的情况没有上面的可能。另一种方法是了解代码如何工作，并自己找到解决方案。很多人都这么做，但是这对你来说可能不是一种选择。另一种方法是在不同的相关论坛上不断提出问题，直到得到回复。坚持可以见效。你需要做好准备去执行任何你所要求的测试，可能包括建立一个新的内核来测试。

如果你能在最近的内核(4.12 或者更新)上复现这个 bug，我建议你邮件报告给 [linux-kernel@vger.kernel.org](mailto:linux-kernel@vger.kernel.org)、[linux-scsi@vger.kernel.org](mailto:linux-scsi@vger.kernel.org) 和我（[neilb@suse.com](mailto:neilb@suse.com)）（注意你不必订阅这些列表来发送邮件，只需要发送就行）。描述你的硬件以及如何触发问题的。

包含所有进程状态是 “D” 的栈追踪。你可以用 “cat /proc/$PID/stack” 来得到它，这里的 “$PID” 是进程的 pid。

确保避免抱怨或者说这个已经坏了好几年了以及这是多么严重不足。没有人关心这个。我们关心的是 bug 以及如何修复它。因此只要报告相关的事实就行。

尝试在邮件中而不是链接到其他地方的链接中包含所有事实。有时链接是需要的，但是对于你的脚本，它只有 8 行，所以把它包含在邮件中就行（并避免像 “fuckup” 之类的描述。只需称它为<ruby> “坏的” <rp>  （ </rp> <rt>  broken </rt> <rp>  ） </rp></ruby>或者类似的）。同样确保你的邮件发送的不是 HTML 格式。我们喜欢纯文本。HTML 被所有的 @vger.kernel.org 邮件列表拒绝。你或许需要配置你的邮箱程序不发送 HTML。

---

via: <https://lwn.net/Articles/737655/>

作者：[neilbrown](https://lwn.net/Articles/737655/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


容器技术和 K8S 的下一站

Summary: 想知道容器编排管理和 K8S 的最新展望么？来看看专家怎么说。

想知道容器编排管理和 K8S 的最新展望么？来看看专家怎么说。

>
> 想知道容器编排管理和 K8S 的最新展望么？来看看专家怎么说。
>
>
>

![CIO_Big Data Decisions_2](/data/attachment/album/201712/03/175452doyee18n18zse88f.png "CIO_Big Data Decisions_2")

如果你想对容器在未来的发展方向有一个整体把握，那么你一定要跟着钱走，看看钱都投在了哪里。当然了，有很多很多的钱正在投入容器的进一步发展。相关研究预计 2020 年容器技术的投入将占有 [27 亿美元](https://451research.com/images/Marketing/press_releases/Application-container-market-will-reach-2-7bn-in-2020_final_graphic.pdf) 的市场份额。而在 2016 年，容器相关技术投入的总额为 7.62 亿美元，只有 2020 年投入预计的三分之一。巨额投入的背后是一些显而易见的基本因素，包括容器化的迅速增长以及并行化的大趋势。随着容器被大面积推广和使用，容器编排管理也会被理所当然的推广应用起来。

来自 [The new stack](https://thenewstack.io/) 的调研数据表明，容器的推广使用是编排管理被推广的主要的催化剂。根据调研参与者的反馈数据，在已经将容器技术使用到生产环境中的使用者里，有六成使用者正在将 Kubernetes（K8S）编排管理广泛的应用在生产环境中，另外百分之十九的人员则表示他们已经处于部署 K8S 的初级阶段。在容器部署初期的使用者当中，虽然只有百分之五的人员表示已经在使用 K8S ，但是百分之五十八的人员表示他们正在计划和准备使用 K8S。总而言之，容器和 Kubernetes 的关系就好比是鸡和蛋一样，相辅相成紧密关联。众多专家一致认为编排管理工具对容器的[长周期管理](https://enterprisersproject.com/article/2017/10/microservices-and-containers-6-management-tips-long-haul) 以及其在市场中的发展有至关重要的作用。正如 [Cockroach 实验室](https://www.cockroachlabs.com/) 的 Alex Robinson 所说，容器编排管理被更广泛的拓展和应用是一个总体的大趋势。毫无疑问，这是一个正在快速演变的领域，且未来潜力无穷。鉴于此，我们对 Robinson 和其他的一些容器的实际使用和推介者做了采访，来从他们作为容器技术的践行者的视角上展望一下容器编排以及 K8S 的下一步发展。

### 容器编排将被主流接受

像任何重要技术的转型一样，我们就像是处在一个高崖之上一般，在经过了初期步履蹒跚的跋涉之后将要来到一望无际的广袤平原。广大的新天地和平实真切的应用需求将会让这种新技术在主流应用中被迅速推广，尤其是在大企业环境中。正如 Alex Robinson 说的那样，容器技术的淘金阶段已经过去，早期的技术革新创新正在减速，随之而来的则是市场对容器技术的稳定性和可用性的强烈需求。这意味着未来我们将不会再见到大量的新的编排管理系统的涌现，而是会看到容器技术方面更多的安全解决方案，更丰富的管理工具，以及基于目前主流容器编排系统的更多的新特性。

### 更好的易用性

人们将在简化容器的部署方面下大功夫，因为容器部署的初期工作对很多公司和组织来说还是比较复杂的，尤其是容器的[长期管理维护](https://enterprisersproject.com/article/2017/10/microservices-and-containers-6-management-tips-long-haul)更是需要投入大量的精力。正如 [Codemill AB](https://codemill.se/) 公司的 My Karlsson 所说，容器编排技术还是太复杂了，这导致很多使用者难以娴熟驾驭和充分利用容器编排的功能。很多容器技术的新用户都需要花费很多精力，走很多弯路，才能搭建小规模的或单个的以隔离方式运行的容器系统。这种现象在那些没有针对容器技术设计和优化的应用中更为明显。在简化容器编排管理方面有很多优化可以做，这些优化和改造将会使容器技术更加具有可用性。

### 在混合云以及多云技术方面会有更多侧重

随着容器和容器编排技术被越来越多的使用，更多的组织机构会选择扩展他们现有的容器技术的部署，从之前的把非重要系统部署在单一环境的使用情景逐渐过渡到更加[复杂的使用情景](https://www.redhat.com/en/challenges/integration?intcmp=701f2000000tjyaAAA)。对很多公司来说，这意味着他们必须开始学会在 [混合云](https://enterprisersproject.com/hybrid-cloud) 和 [多云](https://enterprisersproject.com/article/2017/7/multi-cloud-vs-hybrid-cloud-whats-difference) 的环境下，全局化的去管理那些容器化的应用和微服务。正如红帽 [Openshift 部门产品战略总监](https://www.redhat.com/en) [Brian Gracely](https://enterprisersproject.com/user/brian-gracely) 所说，“容器和 K8S 技术的使用使得我们成功的实现了混合云以及应用的可移植性。结合 Open Service Broker API 的使用，越来越多的结合私有云和公有云资源的新应用将会涌现出来。” 据 [CloudBees](https://www.cloudbees.com/) 公司的高级工程师 Carlos Sanchez 分析，联合服务（Federation）将会得到极大推动，使一些诸如多地区部署和多云部署等的备受期待的新特性成为可能。

**[ 想知道 CIO 们对混合云和多云的战略构想么? 请参看我们的这条相关资源， [Hybrid Cloud: The IT leader's guide](https://enterprisersproject.com/hybrid-cloud?sc_cid=70160000000h0aXAAQ)。 ]**

### 平台和工具的持续整合及加强

对任何一种科技来说，持续的整合和加强从来都是大势所趋；容器编排管理技术在这方面也不例外。来自 [Sumo Logic](https://www.sumologic.com/) 的首席分析师 Ben Newton 表示，随着容器化渐成主流，软件工程师们正在很少数的一些技术上做持续整合加固的工作，来满足他们的一些微应用的需求。容器和 K8S 将会毫无疑问的成为容器编排管理方面的主流平台，并轻松碾压其它的一些小众平台方案。因为 K8S 提供了一个相当清晰的可以摆脱各种特有云生态的途径，K8S 将被大量公司使用，逐渐形成一个不依赖于某个特定云服务的<ruby> “中立云” <rt>  cloud-neutral </rt></ruby>。

### K8S 的下一站

来自 [Alcide](http://alcide.io/) 的 CTO 和联合创始人 Gadi Naor 表示，K8S 将会是一个有长期和远景发展的技术，虽然我们的社区正在大力推广和发展 K8S，K8S 仍有很长的路要走。

专家们对[日益流行的 K8S 平台](https://enterprisersproject.com/article/2017/10/how-explain-kubernetes-plain-english)也作出了以下一些预测：

***来自 Alcide 的 Gadi Naor 表示：*** “运营商会持续演进并趋于成熟，直到在 K8S 上运行的应用可以完全自治。利用 [OpenTracing](http://opentracing.io/) 和诸如 [istio](https://istio.io/) 技术的 service mesh 架构，在 K8S 上部署和监控微应用将会带来很多新的可能性。”

***来自 Red Hat 的 Brian Gracely 表示：*** “K8S 所支持的应用的种类越来越多。今后在 K8S 上，你不仅可以运行传统的应用程序，还可以运行原生的云应用、大数据应用以及 HPC 或者基于 GPU 运算的应用程序，这将为灵活的架构设计带来无限可能。”

***来自 Sumo Logic 的 Ben Newton 表示：*** “随着 K8S 成为一个具有统治地位的平台，我预计更多的操作机制将会被统一化，尤其是 K8S 将和第三方管理和监控平台融合起来。”

***来自 CloudBees 的 Carlos Sanchez 表示：*** “在不久的将来我们就能看到不依赖于 Docker 而使用其它运行时环境的系统，这将会有助于消除任何可能的 lock-in 情景“ [编辑提示：[CRI-O](http://cri-o.io/) 就是一个可以借鉴的例子。]“而且我期待将来会出现更多的针对企业环境的存储服务新特性，包括数据快照以及在线的磁盘容量的扩展。”

***来自 Cockroach Labs 的 Alex Robinson 表示：*** “ K8S 社区正在讨论的一个重大发展议题就是加强对[有状态程序](https://opensource.com/article/17/2/stateful-applications)的管理。目前在 K8S 平台下，实现状态管理仍然非常困难，除非你所使用的云服务商可以提供远程固定磁盘。现阶段也有很多人在多方面试图改善这个状况，包括在 K8S 平台内部以及在外部服务商一端做出的一些改进。”

---

via: <https://enterprisersproject.com/article/2017/11/containers-and-kubernetes-whats-next>

作者：[Kevin Casey](https://enterprisersproject.com/user/kevin-casey) 译者：[yunfengHe](https://github.com/yunfengHe) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


用户指南：Linux 文件系统的链接

>
> 学习如何使用链接，通过从 Linux 文件系统多个位置来访问文件，可以让日常工作变得轻松。
>
>
>

![linux 文件链接用户指南](/data/attachment/album/201712/03/193119ay3qk3y9e0qq4xex.png "A user's guide to links in the Linux filesystem")

在我为 opensource.com 写过的关于 Linux 文件系统方方面面的文章中，包括 [Linux 的 EXT4 文件系统的历史、特性以及最佳实践](/article-8685-1.html)； [在 Linux 中管理设备](/article-8099-1.html)；[Linux 文件系统概览](/article-8887-1.html) 和 [用户指南：逻辑卷管理](https://opensource.com/business/16/9/linux-users-guide-lvm)，我曾简要的提到过 Linux 文件系统一个有趣的特性，它允许用户从多个位置来访问 Linux 文件目录树中的文件来简化一些任务。

Linux 文件系统中有两种<ruby> 链接 <rt>  link </rt></ruby>：<ruby> 硬链接 <rt>  hard link </rt></ruby>和<ruby> 软链接 <rt>  soft link </rt></ruby>。虽然二者差别显著，但都用来解决相似的问题。它们都提供了对单个文件的多个目录项（引用）的访问，但实现却大为不同。链接的强大功能赋予了 Linux 文件系统灵活性，因为[一切皆是文件](https://opensource.com/life/15/9/everything-is-a-file)。

举个例子，我曾发现一些程序要求特定的版本库方可运行。 当用升级后的库替代旧库后，程序会崩溃，提示旧版本库缺失。通常，库名的唯一变化就是版本号。出于直觉，我仅仅给程序添加了一个新的库链接，并以旧库名称命名。我试着再次启动程序，运行良好。程序就是一个游戏，人人都明白，每个玩家都会尽力使游戏进行下去。

事实上，几乎所有的应用程序链接库都使用通用的命名规则，链接名称中包含了主版本号，链接所指向的文件的文件名中同样包含了小版本号。再比如，程序的一些必需文件为了迎合 Linux 文件系统规范，从一个目录移动到另一个目录中，系统为了向后兼容那些不能获取这些文件新位置的程序在旧的目录中存放了这些文件的链接。如果你对 `/lib64` 目录做一个长清单列表，你会发现很多这样的例子。

```
lrwxrwxrwx.  1 root root       36 Dec  8  2016 cracklib_dict.hwm -> ../../usr/share/cracklib/pw_dict.hwm
lrwxrwxrwx.  1 root root       36 Dec  8  2016 cracklib_dict.pwd -> ../../usr/share/cracklib/pw_dict.pwd
lrwxrwxrwx.  1 root root       36 Dec  8  2016 cracklib_dict.pwi -> ../../usr/share/cracklib/pw_dict.pwi
lrwxrwxrwx.  1 root root       27 Jun  9  2016 libaccountsservice.so.0 -> libaccountsservice.so.0.0.0
-rwxr-xr-x.  1 root root   288456 Jun  9  2016 libaccountsservice.so.0.0.0
lrwxrwxrwx   1 root root       15 May 17 11:47 libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x   1 root root    36472 May 17 11:47 libacl.so.1.1.0
lrwxrwxrwx.  1 root root       15 Feb  4  2016 libaio.so.1 -> libaio.so.1.0.1
-rwxr-xr-x.  1 root root     6224 Feb  4  2016 libaio.so.1.0.0
-rwxr-xr-x.  1 root root     6224 Feb  4  2016 libaio.so.1.0.1
lrwxrwxrwx.  1 root root       30 Jan 16 16:39 libakonadi-calendar.so.4 -> libakonadi-calendar.so.4.14.26
-rwxr-xr-x.  1 root root   816160 Jan 16 16:39 libakonadi-calendar.so.4.14.26
lrwxrwxrwx.  1 root root       29 Jan 16 16:39 libakonadi-contact.so.4 -> libakonadi-contact.so.4.14.26

```

`/lib64` 目录下的一些链接

在上面展示的 `/lib64` 目录清单列表中，文件模式第一个字母 `l` （小写字母 l）表示这是一个软链接（又称符号链接）。

### 硬链接

在 [Linux 的 EXT4 文件系统的历史、特性以及最佳实践](/article-8685-1.html)一文中，我曾探讨过这样一个事实，每个文件都有一个包含该文件信息的 inode，包含了该文件的位置信息。上述文章中的[图2](/article-8685-1.html#3_19182)展示了一个指向 inode 的单一目录项。每个文件都至少有一个目录项指向描述该文件信息的 inode ，目录项是一个硬链接，因此每个文件至少都有一个硬链接。

如下图 1 所示，多个目录项指向了同一 inode 。这些目录项都是硬链接。我曾在三个目录项中使用波浪线 (`~`) 的缩写，这是用户目录的惯例表示，因此在该例中波浪线等同于 `/home/user` 。值得注意的是，第四个目录项是一个完全不同的目录，`/home/shared`，可能是该计算机上用户的共享文件目录。

![fig1directory_entries.png](/data/attachment/album/201712/03/193119c6gwzmmu6tbee4mm.png)

*图 1*

硬链接被限制在一个单一的文件系统中。此处的“文件系统” 是指挂载在特定挂载点上的分区或逻辑卷，此例中是 `/home`。这是因为在每个文件系统中的 inode 号都是唯一的。而在不同的文件系统中，如 `/var` 或 `/opt`，会有和 `/home` 中相同的 inode 号。

因为所有的硬链接都指向了包含文件元信息的单一 inode ，这些属性都是文件的一部分，像所属关系、权限、到该 inode 的硬链接数目，对每个硬链接来说这些特性没有什么不同的。这是一个文件所具有的一组属性。唯一能区分这些文件的是包含在 inode 信息中的文件名。链接到同一目录中的单一文件/ inode 的硬链接必须拥有不同的文件名，这是基于同一目录下不能存在重复的文件名的事实的。

文件的硬链接数目可通过 `ls -l` 来查看，如果你想查看实际节点号，可使用 `ls -li` 命令。

### 符号（软）链接

硬链接和软链接（也称为<ruby> 符号链接 <rt>  symlink </rt></ruby>）的区别在于，硬链接直接指向属于该文件的 inode ，而软链接直接指向一个目录项，即指向一个硬链接。因为软链接指向的是一个文件的硬链接而非该文件的 inode ，所以它们并不依赖于 inode 号，这使得它们能跨越不同的文件系统、分区和逻辑卷起作用。

软链接的缺点是，一旦它所指向的硬链接被删除或重命名后，该软链接就失效了。软链接虽然还在，但所指向的硬链接已不存在。所幸的是，`ls` 命令能以红底白字的方式在其列表中高亮显示失效的软链接。

### 实验项目: 链接实验

我认为最容易理解链接用法及其差异的方法是动手搭建一个项目。这个项目应以非超级用户的身份在一个空目录下进行。我创建了 `~/temp` 目录做这个实验，你也可以这么做。这么做可为项目创建一个安全的环境且提供一个新的空目录让程序运作，如此以来这儿仅存放和程序有关的文件。

#### 初始工作

首先，在你要进行实验的目录下为该项目中的任务创建一个临时目录，确保当前工作目录（PWD）是你的主目录，然后键入下列命令。

```
mkdir temp

```

使用这个命令将当前工作目录切换到 `~/temp`。

```
cd temp

```

实验开始，我们需要创建一个能够链接到的文件，下列命令可完成该工作并向其填充内容。

```
du -h > main.file.txt

```

使用 `ls -l` 长列表命名确认文件正确地创建了。运行结果应类似于我的。注意文件大小只有 7 字节，但你的可能会有 1～2 字节的变动。

```
[dboth@david temp]$ ls -l
total 4
-rw-rw-r-- 1 dboth dboth 7 Jun 13 07:34 main.file.txt

```

在列表中，文件模式串后的数字 `1` 代表存在于该文件上的硬链接数。现在应该是 1 ，因为我们还没有为这个测试文件建立任何硬链接。

#### 对硬链接进行实验

硬链接创建一个指向同一 inode 的新目录项，当为文件添加一个硬链接时，你会看到链接数目的增加。确保当前工作目录仍为 `~/temp`。创建一个指向 `main.file.txt` 的硬链接，然后查看该目录下文件列表。

```
[dboth@david temp]$ ln main.file.txt link1.file.txt
[dboth@david temp]$ ls -l
total 8
-rw-rw-r-- 2 dboth dboth 7 Jun 13 07:34 link1.file.txt
-rw-rw-r-- 2 dboth dboth 7 Jun 13 07:34 main.file.txt

```

目录中两个文件都有两个链接且大小相同，时间戳也一样。这就是有一个 inode 和两个硬链接（即该文件的目录项）的一个文件。再建立一个该文件的硬链接，并列出目录清单内容。你可以建立硬链接： `link1.file.txt` 或 `main.file.txt`。

```
[dboth@david temp]$ ln link1.file.txt link2.file.txt ; ls -l
total 16
-rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 link1.file.txt
-rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 link2.file.txt
-rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 main.file.txt

```

注意，该目录下的每个硬链接必须使用不同的名称，因为同一目录下的两个文件不能拥有相同的文件名。试着创建一个和现存链接名称相同的硬链接。

```
[dboth@david temp]$ ln main.file.txt link2.file.txt
ln: failed to create hard link 'link2.file.txt': File exists

```

显然不行，因为 `link2.file.txt` 已经存在。目前为止我们只在同一目录下创建硬链接，接着在临时目录的父目录（你的主目录）中创建一个链接。

```
[dboth@david temp]$ ln main.file.txt ../main.file.txt ; ls -l ../main*
-rw-rw-r--    4 dboth dboth     7 Jun 13 07:34 main.file.txt

```

上面的 `ls` 命令显示 `main.file.txt` 文件确实存在于主目录中，且与该文件在 `temp` 目录中的名称一致。当然它们不是不同的文件，它们是同一文件的两个链接，指向了同一文件的目录项。为了帮助说明下一点，在 `temp` 目录中添加一个非链接文件。

```
[dboth@david temp]$ touch unlinked.file ; ls -l
total 12
-rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link1.file.txt
-rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link2.file.txt
-rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 main.file.txt
-rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file

```

使用 `ls` 命令的 `i` 选项查看 inode 的硬链接号和新创建文件的硬链接号。

```
[dboth@david temp]$ ls -li
total 12
657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link1.file.txt
657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link2.file.txt
657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 main.file.txt
657863 -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file

```

注意上面文件模式左边的数字 `657024` ，这是三个硬链接文件所指的同一文件的 inode 号，你也可以使用 `i` 选项查看主目录中所创建的链接的节点号，和该值相同。而那个只有一个链接的 inode 号和其他的不同，在你的系统上看到的 inode 号或许不同于本文中的。

接着改变其中一个硬链接文件的大小。

```
[dboth@david temp]$ df -h > link2.file.txt ; ls -li
total 12
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link1.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link2.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 main.file.txt
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

```

现在所有的硬链接文件大小都比原来大了，因为多个目录项都链接着同一文件。

下个实验在我的电脑上会出现这样的结果，是因为我的 `/tmp` 目录在一个独立的逻辑卷上。如果你有单独的逻辑卷或文件系统在不同的分区上（如果未使用逻辑卷），确定你是否能访问那个分区或逻辑卷，如果不能，你可以在电脑上挂载一个 U 盘，如果上述方式适合你，你可以进行这个实验。

试着在 `/tmp` 目录中建立一个 `~/temp` 目录下文件的链接（或你的文件系统所在的位置）。

```
[dboth@david temp]$ ln link2.file.txt /tmp/link3.file.txt
ln: failed to create hard link '/tmp/link3.file.txt' => 'link2.file.txt':
Invalid cross-device link

```

为什么会出现这个错误呢？ 原因是每一个单独的可挂载文件系统都有一套自己的 inode 号。简单的通过 inode 号来跨越整个 Linux 文件系统结构引用一个文件会使系统困惑，因为相同的节点号会存在于每个已挂载的文件系统中。

有时你可能会想找到一个 inode 的所有硬链接。你可以使用 `ls -li` 命令。然后使用 `find` 命令找到所有硬链接的节点号。

```
[dboth@david temp]$ find . -inum 657024
./main.file.txt
./link1.file.txt
./link2.file.txt

```

注意 `find` 命令不能找到所属该节点的四个硬链接，因为我们在 `~/temp` 目录中查找。 `find` 命令仅在当前工作目录及其子目录中查找文件。要找到所有的硬链接，我们可以使用下列命令，指定你的主目录作为起始查找条件。

```
[dboth@david temp]$ find ~ -samefile main.file.txt
/home/dboth/temp/main.file.txt
/home/dboth/temp/link1.file.txt
/home/dboth/temp/link2.file.txt
/home/dboth/main.file.txt

```

如果你是非超级用户，没有权限，可能会看到错误信息。这个命令也使用了 `-samefile` 选项而不是指定文件的节点号。这个效果和使用 inode 号一样且更容易，如果你知道其中一个硬链接名称的话。

#### 对软链接进行实验

如你刚才看到的，不能跨越文件系统边界创建硬链接，即在逻辑卷或文件系统中从一个文件系统到另一个文件系统。软链接给出了这个问题的解决方案。虽然它们可以达到相同的目的，但它们是非常不同的，知道这些差异是很重要的。

让我们在 `~/temp` 目录中创建一个符号链接来开始我们的探索。

```
[dboth@david temp]$ ln -s link2.file.txt link3.file.txt ; ls -li
total 12
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link1.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link2.file.txt
658270 lrwxrwxrwx 1 dboth dboth   14 Jun 14 15:21 link3.file.txt ->
link2.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 main.file.txt
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

```

拥有节点号 `657024` 的那些硬链接没有变化，且硬链接的数目也没有变化。新创建的符号链接有不同的 inode 号 `658270`。 名为 `link3.file.txt` 的软链接指向了 `link2.file.txt` 文件。使用 `cat` 命令查看 `link3.file.txt` 文件的内容。符号链接的 inode 信息以字母 `l` （小写字母 l）开头，意味着这个文件实际是个符号链接。

上例中软链接文件 `link3.file.txt` 的大小只有 14 字节。这是文本内容 `link3.file.txt` 的大小，即该目录项的实际内容。目录项 `link3.file.txt` 并不指向一个 inode ；它指向了另一个目录项，这在跨越文件系统建立链接时很有帮助。现在试着创建一个软链接，之前在 `/tmp` 目录中尝试过的。

```
[dboth@david temp]$ ln -s /home/dboth/temp/link2.file.txt
/tmp/link3.file.txt ; ls -l /tmp/link*
lrwxrwxrwx 1 dboth dboth 31 Jun 14 21:53 /tmp/link3.file.txt ->
/home/dboth/temp/link2.file.txt

```

#### 删除链接

当你删除硬链接或硬链接所指的文件时，需要考虑一些问题。

首先，让我们删除硬链接文件 `main.file.txt`。注意指向 inode 的每个目录项就是一个硬链接。

```
[dboth@david temp]$ rm main.file.txt ; ls -li
total 8
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link1.file.txt
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link2.file.txt
658270 lrwxrwxrwx 1 dboth dboth   14 Jun 14 15:21 link3.file.txt ->
link2.file.txt
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

```

`main.file.txt` 是该文件被创建时所创建的第一个硬链接。现在删除它，仍然保留着原始文件和硬盘上的数据以及所有剩余的硬链接。要删除原始文件，你必须删除它的所有硬链接。

现在删除 `link2.file.txt` 硬链接文件。

```
[dboth@david temp]$ rm link2.file.txt ; ls -li
total 8
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link1.file.txt
658270 lrwxrwxrwx 1 dboth dboth   14 Jun 14 15:21 link3.file.txt ->
link2.file.txt
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 main.file.txt
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

```

注意软链接的变化。删除软链接所指的硬链接会使该软链接失效。在我的系统中，断开的链接用颜色高亮显示，目标的硬链接会闪烁显示。如果需要修复这个损坏的软链接，你需要在同一目录下建立一个和旧链接相同名字的硬链接，只要不是所有硬链接都已删除就行。您还可以重新创建链接本身，链接保持相同的名称，但指向剩余的硬链接中的一个。当然如果软链接不再需要，可以使用 `rm` 命令删除它们。

`unlink` 命令在删除文件和链接时也有用。它非常简单且没有选项，就像 `rm` 命令一样。然而，它更准确地反映了删除的基本过程，因为它删除了目录项与被删除文件的链接。

### 写在最后

我用过这两种类型的链接很长一段时间后，我开始了解它们的能力和特质。我为我所教的 Linux 课程编写了一个实验室项目，以充分理解链接是如何工作的，并且我希望增进你的理解。

（题图： [Paul Lewin](https://www.flickr.com/photos/digypho/7905320090)，Opensource.com 修改。 [CC BY-SA 2.0](https://creativecommons.org/licenses/by/2.0/)）

---

作者简介：

戴维.布斯 - 戴维.布斯是 Linux 和开源倡导者，居住在北卡罗莱纳的罗列 。他在 IT 行业工作了四十年，为 IBM 工作了 20 多年的 OS/2。在 IBM 时，他在 1981 年编写了最初的 IBM PC 的第一个培训课程。他为 RedHat 教授过 RHCE 班，并曾在 MCI Worldcom、思科和北卡罗莱纳州工作。他已经用 Linux 和开源软件工作将近 20 年了。

---

via: <https://opensource.com/article/17/6/linking-linux-filesystem>

作者：[David Both](https://opensource.com/users/dboth) 译者：[yongshouzhang](https://github.com/yongshouzhang) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


请允悲，发行了 23 年的《Linux Journal》最终停刊了

Summary: 有着 23 年历史的著名 Linux 和开源期刊《Linux Journal》结束了，其发行人 Carlie Fairchild 在 12 月 1 日撰文称，《Linux Journal》宣布停刊——如果没有奇迹出现的话。

允悲

为LJ默哀，再次证明了，商业化才是生存之道。

昔日闭源急先锋微软，摇身一变成为开源领袖。

商业化可能会毁了一个品牌，但是没有商业化，注定会毁掉一个品牌。

抱歉，有钱真的可以为所欲为。

![](/data/attachment/album/201712/03/232739e1gkvzkpv8nmvnhv.jpeg)

有着 23 年历史的著名 Linux 和开源期刊《[Linux Journal](http://www.linuxjournal.com/)》结束了，其发行人 Carlie Fairchild 在 12 月 1 日撰文称，《[Linux Journal](http://www.linuxjournal.com/)》[宣布停刊](http://www.linuxjournal.com/content/linux-journal-ceases-publication)——如果没有奇迹出现的话。

看的出来，Fairchild 的告别信充满了悲伤、释然和获得帮助的一线期望。《[Linux Journal](http://www.linuxjournal.com/)》创刊于 1994 年，仅比 Linux 内核发布 0.01 版本的 1991 年晚 3 年，而 1994 年 Linux 内核才刚刚发布了 1.0。其后，2011 年的时候，该杂志停止了纸质杂志的出版，仅发行电子版；而如今，经过 6 年之后，连电子版的发行也难以维系，只能无奈的宣布停刊了。

虽然社区也在讨论是不是可以发起募捐或众筹来帮助它度过难关，但是，问题是我们能帮助它多久？

而另外一方面，《[Linux Journal](http://www.linuxjournal.com/)》的停刊，仅仅是时代变迁带来的变化么？这件事会给我们带来什么思考？

![](/data/attachment/album/201712/03/231934dxbt84tt7i3mbcbr.jpg)

以下是 Fairchild 发布的[告别信](http://www.linuxjournal.com/content/linux-journal-ceases-publication)译文：

---

结束了。

看起来我们走到了尽头。根据计划，虽然我们并不想这样做，11 月这一期的《Linux Journal》是我们最后的一期了。

简单的来说，就是我们没钱了，连同期权也用光了。我们没有一个富有的母公司，也没有一个聚宝盆，从头至尾，我们就不算是一个正常的出版商。很长时间以来，我们一直在勉力挣扎于盈亏线之上，当这个平衡终于翻转时，我们最终坠毁在这个 11 月。

我们所能看到的未来和出版业的过去一样——广告商赞助一个出版物是因为它的品牌和读者——而如今的广告世界更喜欢追逐眼球，喜欢在读者的浏览器中植入信标，在读者看到的每个角度用广告去轰炸他们。但是未来不再，过去已逝。

或许还有一点希望，我们觉得，救世主也许会来；但是那需要接过我们的债务、我们的品牌、归档、域名和订阅者及读者。如果你知道任何人真心愿意接手，一定要让我们知道。否则，来看看 [LinuxJournal.com](http://www.linuxjournal.com/) 吧，希望，至少我们的旧归档（可以追溯到 1994 年 4 月创刊，其时 Linux 刚刚发布 1.0）不会消失，这里有许多极棒的内容，以及许多我们怀念的历史。

我们最大的遗憾是，我们没有足够的钱来返还给那些对我们最有价值的人们：我们的订阅者。对此我们表示深切的、真诚的道歉。我们可以为订阅者做的事情有：

《Linux Pro 杂志》为我们的订阅者提供了六期免费杂志，这是一份我们 《Linux Journal》 一直推崇的出版物。在我们需要的时候，他们是第一个出现的人，我们也非常感谢他们的盛情邀请。我们今天刚刚完成了我们的 2017 归档，包括了我们曾经出版过的从开始到最后的每一期。一般我们按 $25 的价格销售它，但是订阅者们这次会免费得到它。请订阅者注意接收邮件了解详情。

我们也希望能得到一些安慰，要知道我们非常、非常地努力才使《Linux Journal》维持下来，我们已经做了太久了，并且以我们所能做到的，以尽可能低、尽可能少的成本来运营。我们基本上是志愿者群体，我们的一些员工已经几个月没有得到报酬了。并且，我们还欠一些自由职业者的钱。出版商对这些情况能承受多少时间是有限度的，而现在已经到了极限了。

这是一件伟大的事情，兄弟们！向那些为我们的诞生、成功和执着而奉献的人们致敬！我们希望列出他们的名字，但是这个名单太长了，以至于我们无法一一列出。但是我们记得你。再次感谢！

本文作者是：《[Linux Journal](http://www.linuxjournal.com/)》发行人 [Carlie Fairchild](mailto:carlie@linuxjournal.com)。


Translate Shell ：一款在 Linux 命令行中使用谷歌翻译的工具

粤语转换不太行啊

输入trans命令根本久没反应

要换api，默认Google的，GitHub上说支持bing的api

![](/data/attachment/album/201712/04/213512ugw2stsgg6gf9sya.jpg)

我对 CLI 应用非常感兴趣，因此热衷于使用并分享 CLI 应用。 我之所以更喜欢 CLI 很大原因是因为我在大多数的时候都使用的是字符界面（black screen），已经习惯了使用 CLI 应用而不是 GUI 应用。

我写过很多关于 CLI 应用的文章。 最近我发现了一些谷歌的 CLI 工具，像 “Google Translator”、“Google Calendar” 和 “Google Contacts”。 这里，我想在给大家分享一下。

今天我们要介绍的是 “Google Translator” 工具。 由于我的母语是泰米尔语，我在一天内用了很多次才理解了它的意义。

谷歌翻译为其它语系的人们所广泛使用。

### 什么是 Translate Shell

[Translate Shell](https://github.com/soimort/translate-shell) (之前叫做 Google Translate CLI) 是一款借助谷歌翻译（默认）、必应翻译、Yandex.Translate 以及 Apertium 来翻译的命令行翻译器。它让你可以在终端访问这些翻译引擎。 Translate Shell 在大多数 Linux 发行版中都能使用。

### 如何安装 Translate Shell

有三种方法安装 Translate Shell。

* 下载自包含的可执行文件
* 手工安装
* 通过包管理器安装

#### 方法 1 : 下载自包含的可执行文件

下载自包含的可执行文件放到 `/usr/bin` 目录中。

```
$ wget git.io/trans
$ chmod +x ./trans
$ sudo mv trans /usr/bin/

```

#### 方法 2 : 手工安装

克隆 Translate Shell 的 GitHub 仓库然后手工编译。

```
$ git clone https://github.com/soimort/translate-shell && cd translate-shell
$ make
$ sudo make install

```

#### 方法 3 : 通过包管理器

有些发行版的官方仓库中包含了 Translate Shell，可以通过包管理器来安装。

对于 Debian/Ubuntu， 使用 [APT-GET 命令](https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/) 或者 [APT 命令](https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/)来安装。

```
$ sudo apt-get install translate-shell

```

对于 Fedora, 使用 [DNF 命令](https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/) 来安装。

```
$ sudo dnf install translate-shell

```

对于基于 Arch Linux 的系统, 使用 [Yaourt 命令](https://www.2daygeek.com/install-yaourt-aur-helper-on-arch-linux/) 或 [Packer 明快](https://www.2daygeek.com/install-packer-aur-helper-on-arch-linux/) 来从 AUR 仓库中安装。

```
$ yaourt -S translate-shell
or
$ packer -S translate-shell

```

### 如何使用 Translate Shell

安装好后，打开终端闭关输入下面命令。 谷歌翻译会自动探测源文本是哪种语言，并且在默认情况下将之翻译成你的 `locale` 所对应的语言。

```
$ trans [Words]

```

下面我将泰米尔语中的单词 “நன்றி” (Nanri) 翻译成英语。 这个单词的意思是感谢别人。

```
$ trans நன்றி
நன்றி
(Naṉṟi)

Thanks

Definitions of நன்றி
[ தமிழ் -> English ]

noun
    gratitude
        நன்றி
    thanks
        நன்றி

நன்றி
    Thanks

```

使用下面命令也能将英语翻译成泰米尔语。

```
$ trans :ta thanks
thanks
/THaNGks/

நன்றி
(Naṉṟi)

Definitions of thanks
[ English -> தமிழ் ]

noun
    நன்றி
        gratitude, thanks

thanks
    நன்றி

```

要将一个单词翻译到多个语种可以使用下面命令(本例中，我将单词翻译成泰米尔语以及印地语)。

```
$ trans :ta+hi thanks
thanks
/THaNGks/

நன்றி
(Naṉṟi)

Definitions of thanks
[ English -> தமிழ் ]

noun
    நன்றி
        gratitude, thanks

thanks
    நன்றி

thanks
/THaNGks/

धन्यवाद
(dhanyavaad)

Definitions of thanks
[ English -> हिन्दी ]

noun
    धन्यवाद
        thanks, thank, gratitude, thankfulness, felicitation

thanks
    धन्यवाद, शुक्रिया

```

使用下面命令可以将多个单词当成一个参数（句子）来进行翻译。(只需要把句子应用起来作为一个参数就行了)。

```
$ trans :ta "what is going on your life?"
what is going on your life?

உங்கள் வாழ்க்கையில் என்ன நடக்கிறது?
(Uṅkaḷ vāḻkkaiyil eṉṉa naṭakkiṟatu?)

Translations of what is going on your life?
[ English -> தமிழ் ]

what is going on your life?
    உங்கள் வாழ்க்கையில் என்ன நடக்கிறது?

```

下面命令单独地翻译各个单词。

```
$ trans :ta curios happy
curios

ஆர்வம்
(Ārvam)

Translations of curios
[ Română -> தமிழ் ]

curios
    ஆர்வம், அறிவாளிகள், ஆர்வமுள்ள, அறிய, ஆர்வமாக
happy
/ˈhapē/

சந்தோஷமாக
(Cantōṣamāka)

Definitions of happy
[ English -> தமிழ் ]

    மகிழ்ச்சியான
        happy, convivial, debonair, gay
    திருப்தி உடைய
        happy

adjective
    இன்பமான
        happy

happy
    சந்தோஷமாக, மகிழ்ச்சி, இனிய, சந்தோஷமா

```

简洁模式：默认情况下，Translate Shell 尽可能多的显示翻译信息。如果你希望只显示简要信息，只需要加上 `-b`选项。

```
$ trans -b :ta thanks
நன்றி

```

字典模式：加上 `-d` 可以把 Translate Shell 当成字典来用。

```
$ trans -d :en thanks
thanks
/THaNGks/

Synonyms
    noun
        - gratitude, appreciation, acknowledgment, recognition, credit

    exclamation
        - thank you, many thanks, thanks very much, thanks a lot, thank you kindly, much obliged, much appreciated, bless you, thanks a million

Examples
    - In short, thanks for everything that makes this city great this Thanksgiving.

    - many thanks

    - There were no thanks in the letter from him, just complaints and accusations.

    - It is a joyful celebration in which Bolivians give thanks for their freedom as a nation.

    - festivals were held to give thanks for the harvest

    - The collection, as usual, received a great response and thanks is extended to all who subscribed.

    - It would be easy to dwell on the animals that Tasmania has lost, but I prefer to give thanks for what remains.

    - thanks for being so helpful

    - It came back on about half an hour earlier than predicted, so I suppose I can give thanks for that.

    - Many thanks for the reply but as much as I tried to follow your advice, it's been a bad week.

    - To them and to those who have supported the office I extend my grateful thanks .

    - We can give thanks and words of appreciation to others for their kind deeds done to us.

    - Adam, thanks for taking time out of your very busy schedule to be with us tonight.

    - a letter of thanks

    - Thank you very much for wanting to go on reading, and thanks for your understanding.

    - Gerry has received a letter of thanks from the charity for his part in helping to raise this much needed cash.

    - So thanks for your reply to that guy who seemed to have a chip on his shoulder about it.

    - Suzanne, thanks for being so supportive with your comments on my blog.

    - She has never once acknowledged my thanks , or existence for that matter.

    - My grateful thanks go to the funders who made it possible for me to travel.

    - festivals were held to give thanks for the harvest

    - All you secretaries who made it this far into the article… thanks for your patience.

    - So, even though I don't think the photos are that good, thanks for the compliments!

    - And thanks for warning us that your secret service requires a motorcade of more than 35 cars.

    - Many thanks for your advice, which as you can see, I have passed on to our readers.

    - Tom Ryan was given a bottle of wine as a thanks for his active involvement in the twinning project.

    - Mr Hill insists he has received no recent complaints and has even been sent a letter of thanks from the forum.

    - Hundreds turned out to pay tribute to a beloved former headteacher at a memorial service to give thanks for her life.

    - Again, thanks for a well written and much deserved tribute to our good friend George.

    - I appreciate your doing so, and thanks also for the compliments about the photos!

See also
    Thanks!, thank, many thanks, thanks to, thanks to you, special thanks, give thanks, thousand thanks, Many thanks!, render thanks, heartfelt thanks, thanks to this

```

使用下面格式可以使用 Translate Shell 来翻译文件。

```
$ trans :ta file:///home/magi/gtrans.txt
உங்கள் வாழ்க்கையில் என்ன நடக்கிறது?

```

下面命令可以让 Translate Shell 进入交互模式。 在进入交互模式之前你需要明确指定源语言和目标语言。本例中，我将英文单词翻译成泰米尔语。

```
$ trans -shell en:ta thanks
Translate Shell
(:q to quit)
thanks
/THaNGks/

நன்றி
(Naṉṟi)

Definitions of thanks
[ English -> தமிழ் ]

noun
    நன்றி
        gratitude, thanks

thanks
    நன்றி

```

想知道语言代码，可以执行下面命令。

```
$ trans -R

```

或者

```
$ trans -T
┌───────────────────┬────────────────────┬────────────────────┐
│ Afrikaans      -   af │ Hindi          -   hi │ Punjabi        -   pa │
│ Albanian       -   sq │ Hmong          -  hmn │ Querétaro Otomi-  otq │
│ Amharic        -   am │ Hmong Daw      -  mww │ Romanian       -   ro │
│ Arabic         -   ar │ Hungarian      -   hu │ Russian        -   ru │
│ Armenian       -   hy │ Icelandic      -   is │ Samoan         -   sm │
│ Azerbaijani    -   az │ Igbo           -   ig │ Scots Gaelic   -   gd │
│ Basque         -   eu │ Indonesian     -   id │ Serbian (Cyr...-sr-Cyrl
│ Belarusian     -   be │ Irish          -   ga │ Serbian (Latin)-sr-Latn
│ Bengali        -   bn │ Italian        -   it │ Sesotho        -   st │
│ Bosnian        -   bs │ Japanese       -   ja │ Shona          -   sn │
│ Bulgarian      -   bg │ Javanese       -   jv │ Sindhi         -   sd │
│ Cantonese      -  yue │ Kannada        -   kn │ Sinhala        -   si │
│ Catalan        -   ca │ Kazakh         -   kk │ Slovak         -   sk │
│ Cebuano        -  ceb │ Khmer          -   km │ Slovenian      -   sl │
│ Chichewa       -   ny │ Klingon        -  tlh │ Somali         -   so │
│ Chinese Simp...- zh-CN│ Klingon (pIqaD)tlh-Qaak Spanish        -   es │
│ Chinese Trad...- zh-TW│ Korean         -   ko │ Sundanese      -   su │
│ Corsican       -   co │ Kurdish        -   ku │ Swahili        -   sw │
│ Croatian       -   hr │ Kyrgyz         -   ky │ Swedish        -   sv │
│ Czech          -   cs │ Lao            -   lo │ Tahitian       -   ty │
│ Danish         -   da │ Latin          -   la │ Tajik          -   tg │
│ Dutch          -   nl │ Latvian        -   lv │ Tamil          -   ta │
│ English        -   en │ Lithuanian     -   lt │ Tatar          -   tt │
│ Esperanto      -   eo │ Luxembourgish  -   lb │ Telugu         -   te │
│ Estonian       -   et │ Macedonian     -   mk │ Thai           -   th │
│ Fijian         -   fj │ Malagasy       -   mg │ Tongan         -   to │
│ Filipino       -   tl │ Malay          -   ms │ Turkish        -   tr │
│ Finnish        -   fi │ Malayalam      -   ml │ Udmurt         -  udm │
│ French         -   fr │ Maltese        -   mt │ Ukrainian      -   uk │
│ Frisian        -   fy │ Maori          -   mi │ Urdu           -   ur │
│ Galician       -   gl │ Marathi        -   mr │ Uzbek          -   uz │
│ Georgian       -   ka │ Mongolian      -   mn │ Vietnamese     -   vi │
│ German         -   de │ Myanmar        -   my │ Welsh          -   cy │
│ Greek          -   el │ Nepali         -   ne │ Xhosa          -   xh │
│ Gujarati       -   gu │ Norwegian      -   no │ Yiddish        -   yi │
│ Haitian Creole -   ht │ Pashto         -   ps │ Yoruba         -   yo │
│ Hausa          -   ha │ Persian        -   fa │ Yucatec Maya   -  yua │
│ Hawaiian       -  haw │ Polish         -   pl │ Zulu           -   zu │
│ Hebrew         -   he │ Portuguese     -   pt │                       │
└───────────────────┴────────────────────┴────────────────────┘

```

想了解更多选项的内容，可以查看其 man 手册。

```
$ man trans

```

---

via: <https://www.2daygeek.com/translate-shell-a-tool-to-use-google-translate-from-command-line-in-linux/>

作者：[Magesh Maruthamuthu](https://www.2daygeek.com/author/magesh/) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


使用 DNSTrails 自动找出每个域名的拥有者

![](/data/attachment/album/201712/04/215650blxa4lj6bgsj7n6s.jpg)

今天，我们很高兴地宣布我们最近几周做的新功能。它是 Whois 聚合工具，现在可以在 [DNSTrails](https://dnstrails.com/) 上获得。

在过去，查找一个域名的所有者会花费很多时间，因为大部分时间你都需要把域名翻译为一个 IP 地址，以便找到同一个人拥有的其他域名。

使用老的方法，在得到你想要的域名列表之前，你在一个工具和另外一个工具的一日又一日的研究和交叉比较结果中经常会花费数个小时。

感谢这个新工具和我们的智能 [WHOIS 数据库](https://securitytrails.com/forensics)，现在你可以搜索任何域名，并获得组织或个人注册的域名的完整列表，并在几秒钟内获得准确的结果。

### 我如何使用 Whois 聚合功能？

第一步：打开 [DNSTrails.com](https://dnstrails.com/)

第二步：搜索任何域名，比如：godaddy.com

第三步：在得到域名的结果后，如下所见，定位下面的 Whois 信息：

![Domain name search results](/data/attachment/album/201712/04/215935adtcp721n4bbn451.png)

第四步：你会看到那里有有关域名的电话和电子邮箱地址。

第五步：点击右边的链接，你会轻松地找到用相同电话和邮箱注册的域名。

![All domain names by the same owner](/data/attachment/album/201712/04/220005eselwnx6b1rvbs14.png)

如果你正在调查互联网上任何个人的域名所有权，这意味着即使域名甚至没有指向注册服务商的 IP，如果他们使用相同的电话和邮件地址，我们仍然可以发现其他域名。

想知道一个人拥有的其他域名么？亲自试试 [DNStrails](https://dnstrails.com/) 的 [WHOIS 聚合功能](http://dnstrails.com/#/domain/domain/ueland.com)或者[使用我们的 API 访问](https://securitytrails.com/contact)。

---

via: <https://securitytrails.com/blog/find-every-domain-someone-owns>

作者：[SECURITYTRAILS TEAM](https://securitytrails.com/blog/find-every-domain-someone-owns)  译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Photon 也许能成为你最喜爱的容器操作系统

Summary: Photon 就是这样的一个发行版。这个特殊的版本是由 VMware 于 2005 年创建的，它包含了 Docker 的守护进程，并可与容器框架（如 Mesos 和 Kubernetes ）一起使用。Photon 经过优化可与 VMware vSphere 协同工作，而且可用于裸机、Microsoft Azure、 Google Compute Engine、 Amazon Elastic Compute Cloud 或者 VirtualBox 等。

![Photon OS](/data/attachment/album/201712/04/223630pii8gzm6v2hkh3mm.jpg "Photon OS")

>
> Phonton OS 专注于容器，是一个非常出色的平台。 —— Jack Wallen
>
>
>

容器在当下的火热，并不是没有原因的。正如[之前](https://www.linux.com/learn/intro-to-linux/2017/11/how-install-and-use-docker-linux)讨论的，容器可以使您轻松快捷地将新的服务与应用部署到您的网络上，而且并不耗费太多的系统资源。比起专用硬件和虚拟机，容器都是更加划算的，除此之外，他们更容易更新与重用。

更重要的是，容器喜欢 Linux（反之亦然）。不需要太多时间和麻烦，你就可以启动一台 Linux 服务器，运行[Docker](https://www.docker.com/)，然后部署容器。但是，哪种 Linux 发行版最适合部署容器呢？我们的选择很多。你可以使用标准的 Ubuntu 服务器平台（更容易安装 Docker 并部署容器）或者是更轻量级的发行版 —— 专门用于部署容器。

[Photon](https://vmware.github.io/photon/) 就是这样的一个发行版。这个特殊的版本是由 [VMware](https://www.vmware.com/) 于 2005 年创建的，它包含了 Docker 的守护进程，并可与容器框架（如 Mesos 和 Kubernetes ）一起使用。Photon 经过优化可与 [VMware vSphere](https://www.vmware.com/products/vsphere.html) 协同工作，而且可用于裸机、[Microsoft Azure](https://azure.microsoft.com/)、 [Google Compute Engine](https://cloud.google.com/compute/)、 [Amazon Elastic Compute Cloud](https://aws.amazon.com/ec2/) 或者 [VirtualBox](https://www.virtualbox.org/) 等。

Photon 通过只安装 Docker 守护进程所必需的东西来保持它的轻量。而这样做的结果是，这个发行版的大小大约只有 300MB。但这足以让 Linux 的运行一切正常。除此之外，Photon 的主要特点还有：

* 内核为性能而调整。
* 内核根据[内核自防护项目](https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Project)（KSPP）进行了加固。
* 所有安装的软件包都根据加固的安全标识来构建。
* 操作系统在信任验证后启动。
* Photon 的管理进程可以管理防火墙、网络、软件包，和远程登录在 Photon 机器上的用户。
* 支持持久卷。
* [Project Lightwave](http://vmware.github.io/lightwave/) 整合。
* 及时的安全补丁与更新。

Photon 可以通过 [ISO 镜像](https://github.com/vmware/photon/wiki/Downloading-Photon-OS)、[OVA](https://github.com/vmware/photon/wiki/Downloading-Photon-OS)、[Amazon Machine Image](https://github.com/vmware/photon/wiki/Downloading-Photon-OS)、[Google Compute Engine 镜像](https://github.com/vmware/photon/wiki/Downloading-Photon-OS) 和 [Azure VHD](https://github.com/vmware/photon/wiki/Downloading-Photon-OS) 安装使用。现在我将向您展示如何使用 ISO 镜像在 VirtualBox 上安装 Photon。整个安装过程大概需要五分钟，在最后您将有一台随时可以部署容器的虚拟机。

### 创建虚拟机

在部署第一台容器之前，您必须先创建一台虚拟机并安装 Photon。为此，打开 VirtualBox 并点击“新建”按钮。跟着创建虚拟机向导进行配置（根据您的容器将需要的用途，为 Photon 提供必要的资源）。在创建好虚拟机后，您所需要做的第一件事就是更改配置。选择新建的虚拟机（在 VirtualBox 主窗口的左侧面板中），然后单击“设置”。在弹出的窗口中，点击“网络”（在左侧的导航中）。

在“网络”窗口（图1）中，你需要在“连接”的下拉窗口中选择桥接。这可以确保您的 Photon 服务与您的网络相连。完成更改后，单击确定。

![change settings](/data/attachment/album/201712/04/223630jajqateefe9hszzw.jpg "change setatings")

*图 1： 更改 Photon 在 VirtualBox 中的网络设置。[经许可使用](https://www.linux.com/licenses/category/used-permission)*

从左侧的导航选择您的 Photon 虚拟机，点击启动。系统会提示您去加载 ISO 镜像。当您完成之后，Photon 安装程序将会启动并提示您按回车后开始安装。安装过程基于 ncurses（没有 GUI），但它非常简单。

接下来（图2），系统会询问您是要最小化安装，完整安装还是安装 OSTree 服务器。我选择了完整安装。选择您所需要的任意选项，然后按回车继续。

![installation type](/data/attachment/album/201712/04/223631avqbvimavqqiwvek.jpg "Photon")

*图 2： 选择您的安装类型。[经许可使用](https://www.linux.com/licenses/category/used-permission)*

在下一个窗口，选择您要安装 Photon 的磁盘。由于我们将其安装在虚拟机，因此只有一块磁盘会被列出（图3）。选择“自动”按下回车。然后安装程序会让您输入（并验证）管理员密码。在这之后镜像开始安装在您的磁盘上并在不到 5 分钟的时间内结束。

![Photon](/data/attachment/album/201712/04/223631fs4nmgqgsqg60202.jpg "installation type")

*图 3： 选择安装 Photon 的硬盘。[经许可使用](https://www.linux.com/licenses/category/used-permission)*

安装完成后，重启虚拟机并使用安装时创建的用户 root 和它的密码登录。一切就绪，你准备好开始工作了。

在开始使用 Docker 之前，您需要更新一下 Photon。Photon 使用 `yum` 软件包管理器，因此在以 root 用户登录后输入命令 `yum update`。如果有任何可用更新，则会询问您是否确认（图4）。

![Updating](/data/attachment/album/201712/04/223631uxqi49fmz9zulhzx.jpg "Updating")

*图 4： 更新 Photon。[经许可使用](https://www.linux.com/licenses/category/used-permission)*

### 用法

正如我所说的，Photon 提供了部署容器甚至创建 Kubernetes 集群所需要的所有包。但是，在使用之前还要做一些事情。首先要启动 Docker 守护进程。为此，执行以下命令：

```
systemctl start docker
systemctl enable docker

```

现在我们需要创建一个标准用户，以便我们可以不用 root 去运行 `docker` 命令。为此，执行以下命令：

```
useradd -m USERNAME
passwd USERNAME

```

其中 “USERNAME” 是我们新增的用户的名称。

接下来，我们需要将这个新用户添加到 “docker” 组，执行命令：

```
usermod -a -G docker USERNAME

```

其中 “USERNAME” 是刚刚创建的用户的名称。

注销 root 用户并切换为新增的用户。现在，您已经可以不必使用 `sudo` 命令或者切换到 root 用户来使用 `docker` 命令了。从 Docker Hub 中取出一个镜像开始部署容器吧。

### 一个优秀的容器平台

在专注于容器方面，Photon 毫无疑问是一个出色的平台。请注意，Photon 是一个开源项目，因此没有任何付费支持。如果您对 Photon 有任何的问题，请移步 Photon 项目的 GitHub 下的 [Issues](https://github.com/vmware/photon/issues)，那里可以供您阅读相关问题，或者提交您的问题。如果您对 Photon 感兴趣，您也可以在该项目的官方 [GitHub](https://github.com/vmware/photon)中找到源码。

尝试一下 Photon 吧，看看它是否能够使得 Docker 容器和 Kubernetes 集群的部署更加容易。

欲了解 Linux 的更多信息，可以通过学习 Linux 基金会和 edX 的免费课程，[“Linux 入门”](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)。

---

via: <https://www.linux.com/learn/intro-to-linux/2017/11/photon-could-be-your-new-favorite-container-os>

作者：[JACK WALLEN](https://www.linux.com/users/jlwallen) 译者：[KeyLD](https://github.com/KeyLd) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何在 Linux 系统里用 Scrot 截屏

最近，我们介绍过 [gnome-screenshot](https://www.howtoforge.com/tutorial/taking-screenshots-in-linux-using-gnome-screenshot/) 工具，这是一个很优秀的屏幕抓取工具。但如果你想找一个在命令行运行的更好用的截屏工具，你一定要试试 Scrot。这个工具有一些 gnome-screenshot 没有的独特功能。在这篇文章里，我们会通过简单易懂的例子来详细介绍 Scrot。

![](/data/attachment/album/201712/05/112340yiuqlqnnqnv6qqfi.jpg)

请注意一下，这篇文章里的所有例子都在 Ubuntu 16.04 LTS 上测试过，我们用的 scrot 版本是 0.8。

### 关于 Scrot

[Scrot](https://en.wikipedia.org/wiki/Scrot) （**SCR**eensh**OT**） 是一个屏幕抓取工具，使用 imlib2 库来获取和保存图片。由 Tom Gilbert 用 C 语言开发完成，通过 BSD 协议授权。

### 安装 Scrot

scort 工具可能在你的 Ubuntu 系统里预装了，不过如果没有的话，你可以用下面的命令安装：

```
sudo apt-get install scrot

```

安装完成后，你可以通过下面的命令来使用：

```
scrot [options] [filename]

```

**注意**：方括号里的参数是可选的。

### Scrot 的使用和特点

在这个小节里，我们会介绍如何使用 Scrot 工具，以及它的所有功能。

如果不带任何选项执行命令，它会抓取整个屏幕。

 [![使用 Scrot](/data/attachment/album/201712/05/112345dn46i1bdiyjaab1c.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/scrot.png)

默认情况下，抓取的截图会用带时间戳的文件名保存到当前目录下，不过你也可以在运行命令时指定截图文件名。比如：

```
scrot [image-name].png

```

### 获取程序版本

你想的话，可以用 `-v` 选项来查看 scrot 的版本。

```
scrot -v

```

这是例子：

 [![获取 scrot 版本](/data/attachment/album/201712/05/112346k0178ggzg857estm.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/version.png)

### 抓取当前窗口

这个工具可以限制抓取当前的焦点窗口。这个功能可以通过 `-u` 选项打开。

```
scrot -u

```

例如，这是我在命令行执行上边命令时的桌面：

 [![用 scrot 截取窗口](/data/attachment/album/201712/05/112346mm2im2hecamof64g.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/desktop.png)

这是另一张用 scrot 抓取的截图：

 [![用 scrot 抓取的图片](/data/attachment/album/201712/05/112346mpw8ewwnewkjjeps.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/active.png)

### 抓取选定窗口

这个工具还可以让你抓取任意用鼠标点击的窗口。这个功能可以用 `-s` 选项打开。

```
scrot -s

```

例如，在下面的截图里你可以看到，我有两个互相重叠的终端窗口。我在上层的窗口里执行上面的命令。

 [![选择窗口](/data/attachment/album/201712/05/112346go9iyn0xn55ysxcl.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/select1.png)

现在假如我想抓取下层的终端窗口。这样我只要在执行命令后点击窗口就可以了 —— 在你用鼠标点击之前，命令的执行不会结束。

这是我点击了下层终端窗口后的截图：

 [![窗口截图](/data/attachment/album/201712/05/112346qpt0pifxi36fqtf0.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/select2.png)

**注意**：你可以在上面的截图里看到，下层终端窗口的整个显示区域都被抓去下来了，甚至包括了上层窗口的部分叠加内容。

### 在截屏时包含窗口边框

我们之前介绍的 `-u` 选项在截屏时不会包含窗口边框。不过，需要的话你也可以在截屏时包含窗口边框。这个功能可以通过 `-b` 选项打开（当然要和 `-u` 选项一起）。

```
scrot -ub

```

下面是示例截图：

 [![截屏时包含窗口边框](/data/attachment/album/201712/05/112346bwzcdcaquyqokwmc.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/border-new.png)

**注意**：截屏时包含窗口边框同时也会增加一点额外的背景。

### 延时截屏

你可以在开始截屏时增加一点延时。需要在 `--delay` 或 `-d` 选项后设定一个时间值参数。

```
scrot --delay [NUM]

scrot --delay 5

```

例如：

 [![延时截屏](/data/attachment/album/201712/05/112347whcgccqujmubcrme.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/delay.png)

在这例子里，scrot 会等待 5 秒再截屏。

### 截屏前倒数

这个工具也可以在你使用延时功能后显示一个倒计时。这个功能可以通过 `-c` 选项打开。

```
scrot –delay [NUM] -c

scrot -d 5 -c

```

下面是示例截图：

 [![延时截屏示例](/data/attachment/album/201712/05/112347o2sizrmzhz1q6sic.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/countdown.png)

### 图片质量

你可以使用这个工具来调整截图的图片质量，范围是 1-100 之间。较大的值意味着更大的文件大小以及更低的压缩率。默认值是 75，不过最终效果根据选择的文件类型也会有一些差异。

这个功能可以通过 `--quality` 或 `-q` 选项打开，但是你必须提供一个 1 - 100 之间的数值作为参数。

```
scrot –quality [NUM]

scrot –quality 10

```

下面是示例截图：

 [![截屏质量](/data/attachment/album/201712/05/112347nlhxbjb5xobp2b8j.jpg)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/img-quality.jpg)

你可以看到，`-q` 选项的参数更靠近 1 让图片质量下降了很多。

### 生成缩略图

scort 工具还可以生成截屏的缩略图。这个功能可以通过 `--thumb` 选项打开。这个选项也需要一个 NUM 数值作为参数，基本上是指定原图大小的百分比。

```
scrot --thumb NUM

scrot --thumb 50

```

**注意**：加上 `--thumb` 选项也会同时保存原始截图文件。

例如，下面是我测试的原始截图：

 [![原始截图](/data/attachment/album/201712/05/112347txddqcc3cduoeqoc.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/orig.png)

下面是保存的缩略图：

 [![截图缩略图](/data/attachment/album/201712/05/112347hxbwexedqeomoxiw.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/thmb.png)

### 拼接多显示器截屏

如果你的电脑接了多个显示设备，你可以用 scort 抓取并拼接这些显示设备的截图。这个功能可以通过 `-m` 选项打开。

```
scrot -m

```

下面是示例截图：

 [![拼接截屏](/data/attachment/album/201712/05/112347bv4rvrchrtvftv1c.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/multiple.png)

### 在保存截图后执行操作

使用这个工具，你可以在保存截图后执行各种操作 —— 例如，用像 gThumb 这样的图片编辑器打开截图。这个功能可以通过 `-e` 选项打开。下面是例子：

```
scrot abc.png -e 'gthumb abc.png'

```

这个命令里的 gthumb 是一个图片编辑器，上面的命令在执行后会自动打开。

下面是命令的截图：

 [![截屏后执行命令](/data/attachment/album/201712/05/112348u2cedjma4c3kpubq.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/exec1.png)

这个是上面命令执行后的效果：

 [![示例截图](/data/attachment/album/201712/05/112348gr1ku52a165emuk1.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/exec2.png)

你可以看到 scrot 抓取了屏幕截图，然后再启动了 gThumb 图片编辑器打开刚才保存的截图图片。

如果你截图时没有指定文件名，截图将会用带有时间戳的文件名保存到当前目录 —— 这是 scrot 的默认设定，我们前面已经说过。

下面是一个使用默认名字并且加上 `-e` 选项来截图的例子：

```
scrot -e 'gthumb $n'

```

 [![scrot 截屏后运行 gthumb](/data/attachment/album/201712/05/112348do7hr66zc6zkvcv6.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/exec3.png)

有个地方要注意的是 `$n` 是一个特殊字符串，用来获取当前截图的文件名。关于特殊字符串的更多细节，请继续看下个小节。

### 特殊字符串

scrot 的 `-e`（或 `--exec`）选项和文件名参数可以使用格式说明符。有两种类型格式。第一种是以 `%` 加字母组成，用来表示日期和时间，第二种以 `$` 开头，scrot 内部使用。

下面介绍几个 `--exec` 和文件名参数接受的说明符。

`$f` – 让你可以使用截图的全路径（包括文件名）。

例如：

```
scrot ashu.jpg -e ‘mv $f ~/Pictures/Scrot/ashish/’

```

下面是示例截图：

 [![示例](/data/attachment/album/201712/05/112348hj0fxqxc56f7m3jo.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/f.png)

如果你没有指定文件名，scrot 默认会用日期格式的文件名保存截图。这个是 scrot 的默认文件名格式：`%yy-%mm-%dd-%hhmmss_$wx$h_scrot.png`。

`$n` – 提供截图文件名。下面是示例截图：

 [![scrot $n variable](/data/attachment/album/201712/05/112348d00jeahxhllrc9p9.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/n.png)

`$s` – 获取截图的文件大小。这个功能可以像下面这样使用。

```
scrot abc.jpg -e ‘echo $s’

```

下面是示例截图：

 [![scrot $s 变量](/data/attachment/album/201712/05/112349ju3yzv96bbk2uvpb.png)](https://www.howtoforge.com/images/how-to-take-screenshots-in-linux-with-scrot/big/s.png)

类似的，你也可以使用其他格式字符串 `$p`、`$w`、 `$h`、`$t`、`$$` 以及 `\n` 来分别获取图片像素大小、图像宽度、图像高度、图像格式、输入 `$` 字符、以及换行。你可以像上面介绍的 `$s` 格式那样使用这些字符串。

### 结论

这个应用能轻松地安装在 Ubuntu 系统上，对初学者比较友好。scrot 也提供了一些高级功能，比如支持格式化字符串，方便专业用户用脚本处理。当然，如果你想用起来的话有一点轻微的学习曲线。

---

via: <https://www.howtoforge.com/tutorial/how-to-take-screenshots-in-linux-with-scrot/>

作者：[Himanshu Arora](https://www.howtoforge.com/tutorial/how-to-take-screenshots-in-linux-with-scrot/) 译者：[zpl1025](https://github.com/zpl1025) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


vim 的酷功能：会话！

Summary: 昨天我在编写我的vimrc的时候了解到一个很酷的 vim 功能！（主要为了添加 fzf 和 ripgrep 插件）。这是一个内置功能，不需要特别的插件。

![](/data/attachment/album/201712/05/113217zsgadesas32a07bb.jpg)

昨天我在编写我的 [vimrc](https://github.com/jvns/vimconfig/blob/master/vimrc) 的时候了解到一个很酷的 vim 功能！（主要为了添加 fzf 和 ripgrep 插件）。这是一个内置功能，不需要特别的插件。

所以我画了一个漫画。

基本上你可以用下面的命令保存所有你打开的文件和当前的状态

```
:mksession ~/.vim/sessions/foo.vim

```

接着用 `:source ~/.vim/sessions/foo.vim` 或者 `vim -S ~/.vim/sessions/foo.vim` 还原会话。非常酷！

一些 vim 插件给 vim 会话添加了额外的功能：

* <https://github.com/tpope/vim-obsession>
* <https://github.com/mhinz/vim-startify>
* <https://github.com/xolox/vim-session>

这是漫画：

![](/data/attachment/album/201712/05/113232vdme81leptot984u.png)

---

via: <https://jvns.ca/blog/2017/09/10/vim-sessions/>

作者：[Julia Evans](https://jvns.ca/about) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


面向初学者的 Linux 网络硬件：软件思维

Summary: 没有路由和桥接，我们将会成为孤独的小岛，你将会在这个网络教程中学到更多知识。

没有路由和桥接，我们将会成为孤独的小岛，你将会在这个网络教程中学到更多知识。

![island network](/data/attachment/album/201712/05/215725lg096gq9m9ue9xom.jpg "island network")

>
> 没有路由和桥接，我们将会成为孤独的小岛，你将会在这个网络教程中学到更多知识。
>
>
>

上周，我们学习了本地网络硬件知识，本周，我们将学习网络互联技术和在移动网络中的一些很酷的黑客技术。

### 路由器

网络路由器就是计算机网络中的一切，因为路由器连接着网络，没有路由器，我们就会成为孤岛。图一展示了一个简单的有线本地网络和一个无线接入点，所有设备都接入到互联网上，本地局域网的计算机连接到一个连接着防火墙或者路由器的以太网交换机上，防火墙或者路由器连接到网络服务供应商（ISP）提供的电缆箱、调制调节器、卫星上行系统……好像一切都在计算中，就像是一个带着不停闪烁的的小灯的盒子。当你的网络数据包离开你的局域网，进入广阔的互联网，它们穿过一个又一个路由器直到到达自己的目的地。

![simple LAN](/data/attachment/album/201712/05/215727gsmsh510hws94ezw.png "simple LAN")

*图一：一个简单的有线局域网和一个无线接入点。*

路由器可以是各种样式：一个只专注于路由的小巧特殊的小盒子，一个将会提供路由、防火墙、域名服务，以及 VPN 网关功能的大点的盒子，一台重新设计的台式电脑或者笔记本，一个树莓派计算机或者一个 Arduino，体积臃肿矮小的像 PC Engines 这样的单板计算机，除了苛刻的用途以外，普通的商品硬件都能良好的工作运行。高端的路由器使用特殊设计的硬件每秒能够传输最大量的数据包。它们有多路数据总线，多个中央处理器和极快的存储。（可以通过了解 Juniper 和思科的路由器来感受一下高端路由器书什么样子的，而且能看看里面是什么样的构造。）

接入你的局域网的无线接入点要么作为一个以太网网桥，要么作为一个路由器。桥接器扩展了这个网络，所以在这个桥接器上的任意一端口上的主机都连接在同一个网络中。一台路由器连接的是两个不同的网络。

### 网络拓扑

有多种设置你的局域网的方式，你可以把所有主机接入到一个单独的<ruby> 平面网络 <rt>  flat network </rt></ruby>，也可以把它们划分为不同的子网。如果你的交换机支持 VLAN 的话，你也可以把它们分配到不同的 VLAN 中。

平面网络是最简单的网络，只需把每一台设备接入到同一个交换机上即可，如果一台交换上的端口不够使用，你可以将更多的交换机连接在一起。有些交换机有特殊的上行端口，有些是没有这种特殊限制的上行端口，你可以连接其中的任意端口，你可能需要使用交叉类型的以太网线，所以你要查阅你的交换机的说明文档来设置。

平面网络是最容易管理的，你不需要路由器也不需要计算子网，但它也有一些缺点。它们的伸缩性不好，所以当网络规模变得越来越大的时候就会被广播网络所阻塞。将你的局域网进行分段将会提升安全保障， 把局域网分成可管理的不同网段将有助于管理更大的网络。图二展示了一个分成两个子网的局域网络：内部的有线和无线主机，和一个托管公开服务的主机。包含面向公共的服务器的子网称作非军事区域 DMZ，（你有没有注意到那些都是主要在电脑上打字的男人们的术语？）因为它被阻挡了所有的内部网络的访问。

![LAN](/data/attachment/album/201712/05/215729daq5yvetxqsxq5zb.png "LAN")

*图二：一个分成两个子网的简单局域网。*

即使像图二那样的小型网络也可以有不同的配置方法。你可以将防火墙和路由器放置在一台单独的设备上。你可以为你的非军事区域设置一个专用的网络连接，把它完全从你的内部网络隔离，这将引导我们进入下一个主题：一切基于软件。

### 软件思维

你可能已经注意到在这个简短的系列中我们所讨论的硬件，只有网络接口、交换机，和线缆是特殊用途的硬件。 其它的都是通用的商用硬件，而且都是软件来定义它的用途。Linux 是一个真实的网络操作系统，它支持大量的网络操作：网关、虚拟专用网关、以太网桥、网页、邮箱以及文件等等服务器、负载均衡、代理、服务质量、多种认证、中继、故障转移……你可以在运行着 Linux 系统的标准硬件上运行你的整个网络。你甚至可以使用 Linux 交换应用（LISA）和VDE2 协议来模拟以太网交换机。

有一些用于小型硬件的特殊发行版，如 DD-WRT、OpenWRT，以及树莓派发行版，也不要忘记 BSD 们和它们的特殊衍生用途如 pfSense 防火墙/路由器，和 FreeNAS 网络存储服务器。

你知道有些人坚持认为硬件防火墙和软件防火墙有区别？其实是没有区别的，就像说硬件计算机和软件计算机一样。

### 端口聚合和以太网绑定

聚合和绑定，也称链路聚合，是把两条以太网通道绑定在一起成为一条通道。一些交换机支持端口聚合，就是把两个交换机端口绑定在一起，成为一个是它们原来带宽之和的一条新的连接。对于一台承载很多业务的服务器来说这是一个增加通道带宽的有效的方式。

你也可以在以太网口进行同样的配置，而且绑定汇聚的驱动是内置在 Linux 内核中的，所以不需要任何其他的专门的硬件。

### 随心所欲选择你的移动宽带

我期望移动宽带能够迅速增长来替代 DSL 和有线网络。我居住在一个有 25 万人口的靠近一个城市的地方，但是在城市以外，要想接入互联网就要靠运气了，即使那里有很大的用户上网需求。我居住的小角落离城镇有 20 分钟的距离，但对于网络服务供应商来说他们几乎不会考虑到为这个地方提供网络。 我唯一的选择就是移动宽带；这里没有拨号网络、卫星网络（即使它很糟糕）或者是 DSL、电缆、光纤，但却没有阻止网络供应商把那些我在这个区域从没看到过的 Xfinity 和其它高速网络服务的传单塞进我的邮箱。

我试用了 AT&T、Version 和 T-Mobile。Version 的信号覆盖范围最广，但是 Version 和 AT&T 是最昂贵的。 我居住的地方在 T-Mobile 信号覆盖的边缘，但迄今为止他们给了最大的优惠，为了能够能够有效的使用，我必须购买一个 WeBoost 信号放大器和一台中兴的移动热点设备。当然你也可以使用一部手机作为热点，但是专用的热点设备有着最强的信号。如果你正在考虑购买一台信号放大器，最好的选择就是 WeBoost，因为他们的服务支持最棒，而且他们会尽最大努力去帮助你。在一个小小的 APP [SignalCheck Pro](http://www.bluelinepc.com/signalcheck/) 的协助下设置将会精准的增强你的网络信号，他们有一个功能较少的免费的版本，但你将一点都不会后悔去花两美元使用专业版。

那个小巧的中兴热点设备能够支持 15 台主机，而且还有拥有基本的防火墙功能。 但你如果你使用像 Linksys WRT54GL这样的设备，可以使用 Tomato、OpenWRT，或者 DD-WRT 来替代普通的固件，这样你就能完全控制你的防护墙规则、路由配置，以及任何其它你想要设置的服务。

（题图：Pixabay）

---

via: <https://www.linux.com/learn/intro-to-linux/2017/10/linux-networking-hardware-beginners-think-software>

作者：[CARLA SCHRODER](https://www.linux.com/users/cschroder) 译者：[FelixYFZ](https://github.com/FelixYFZ) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何在 Linux 系统中通过用户组来管理用户

Summary: 本教程可以了解如何通过用户组和访问控制表（ACL）来管理用户。

本教程可以了解如何通过用户组和访问控制表（ACL）来管理用户。

![groups](/data/attachment/album/201712/05/224222k2uqlslgchuws8uj.jpg)

>
> 本教程可以了解如何通过用户组和访问控制表（ACL）来管理用户。
>
>
>

当你需要管理一台容纳多个用户的 Linux 机器时，比起一些基本的用户管理工具所提供的方法，有时候你需要对这些用户采取更多的用户权限管理方式。特别是当你要管理某些用户的权限时，这个想法尤为重要。比如说，你有一个目录，某个用户组中的用户可以通过读和写的权限访问这个目录，而其他用户组中的用户对这个目录只有读的权限。在 Linux 中，这是完全可以实现的。但前提是你必须先了解如何通过用户组和访问控制表（ACL）来管理用户。

我们将从简单的用户开始，逐渐深入到复杂的访问控制表（ACL）。你可以在你所选择的 Linux 发行版完成你所需要做的一切。本文的重点是用户组，所以不会涉及到关于用户的基础知识。

为了达到演示的目的，我将假设：

你需要用下面两个用户名新建两个用户：

* olivia
* nathan

你需要新建以下两个用户组：

* readers
* editors

olivia 属于 editors 用户组，而 nathan 属于 readers 用户组。reader 用户组对 `/DATA` 目录只有读的权限，而 editors 用户组则对 `/DATA` 目录同时有读和写的权限。当然，这是个非常小的任务，但它会给你基本的信息，你可以扩展这个任务以适应你其他更大的需求。

我将在 Ubuntu 16.04 Server 平台上进行演示。这些命令都是通用的，唯一不同的是，要是在你的发行版中不使用 `sudo` 命令，你必须切换到 root 用户来执行这些命令。

### 创建用户

我们需要做的第一件事是为我们的实验创建两个用户。可以用 `useradd` 命令来创建用户，我们不只是简单地创建一个用户，而需要同时创建用户和属于他们的家目录，然后给他们设置密码。

```
sudo useradd -m olivia
sudo useradd -m nathan

```

我们现在创建了两个用户，如果你看看 `/home` 目录，你可以发现他们的家目录（因为我们用了 `-m` 选项，可以在创建用户的同时创建他们的家目录。

之后，我们可以用以下命令给他们设置密码：

```
sudo passwd olivia
sudo passwd nathan

```

就这样，我们创建了两个用户。

### 创建用户组并添加用户

现在我们将创建 readers 和 editors 用户组，然后给它们添加用户。创建用户组的命令是：

```
addgroup readers
addgroup editors

```

（LCTT 译注：当你使用 CentOS 等一些 Linux 发行版时，可能系统没有 `addgroup` 这个命令，推荐使用 `groupadd` 命令来替换 `addgroup` 命令以达到同样的效果）

![groups](/data/attachment/album/201712/05/224231hdo32xtx3i26qc86.jpg)

*图一：我们可以使用刚创建的新用户组了。*

创建用户组后，我们需要添加我们的用户到这两个用户组。我们用以下命令来将 nathan 用户添加到 readers 用户组：

```
sudo usermod -a -G readers nathan

```

用以下命令将 olivia 添加到 editors 用户组：

```
sudo usermod -a -G editors olivia

```

现在我们可以通过用户组来管理用户了。

### 给用户组授予目录的权限

假设你有个目录 `/READERS` 且允许 readers 用户组的所有成员访问这个目录。首先，我们执行以下命令来更改目录所属用户组：

```
sudo chown -R :readers /READERS

```

接下来，执行以下命令收回目录所属用户组的写入权限：

```
sudo chmod -R g-w /READERS

```

然后我们执行下面的命令来收回其他用户对这个目录的访问权限（以防止任何不在 readers 组中的用户访问这个目录里的文件）：

```
sudo chmod -R o-x /READERS

```

这时候，只有目录的所有者（root）和用户组 reader 中的用户可以访问 `/READES` 中的文件。

假设你有个目录 `/EDITORS` ，你需要给用户组 editors 里的成员这个目录的读和写的权限。为了达到这个目的，执行下面的这些命令是必要的：

```
sudo chown -R :editors /EDITORS
sudo chmod -R g+w /EDITORS
sudo chmod -R o-x /EDITORS

```

此时 editors 用户组的所有成员都可以访问和修改其中的文件。除此之外其他用户（除了 root 之外）无法访问 `/EDITORS` 中的任何文件。

使用这个方法的问题在于，你一次只能操作一个组和一个目录而已。这时候访问控制表（ACL）就可以派得上用场了。

### 使用访问控制表（ACL）

现在，让我们把这个问题变得棘手一点。假设你有一个目录 `/DATA` 并且你想给 readers 用户组的成员读取权限，并同时给 editors 用户组的成员读和写的权限。为此，你必须要用到 `setfacl` 命令。`setfacl` 命令可以为文件或文件夹设置一个访问控制表（ACL）。

这个命令的结构如下：

```
setfacl OPTION X:NAME:Y /DIRECTORY

```

其中 OPTION 是可选选项，X 可以是 `u`（用户）或者是 `g` （用户组），NAME 是用户或者用户组的名字，/DIRECTORY 是要用到的目录。我们将使用 `-m` 选项进行修改。因此，我们给 readers 用户组添加读取权限的命令是：

```
sudo setfacl -m g:readers:rx -R /DATA

```

现在 readers 用户组里面的每一个用户都可以读取 `/DATA` 目录里的文件了，但是他们不能修改里面的内容。

为了给 editors 用户组里面的用户读写权限，我们执行了以下命令：

```
sudo setfacl -m g:editors:rwx -R /DATA

```

上述命令将赋予 editors 用户组中的任何成员读取权限，同时保留 readers 用户组的只读权限。

### 更多的权限控制

使用访问控制表（ACL），你可以实现你所需的权限控制。你可以添加用户到用户组，并且灵活地控制这些用户组对每个目录的权限以达到你的需求。如果想了解上述工具的更多信息，可以执行下列的命令：

* `man usradd`
* `man addgroup`
* `man usermod`
* `man sefacl`
* `man chown`
* `man chmod`

---

via: <https://www.linux.com/learn/intro-to-linux/2017/12/how-manage-users-groups-linux>

作者：[Jack Wallen] 译者：[imquanquan](https://github.com/imquanquan) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何自动唤醒和关闭 Linux

![timekeeper](/data/attachment/album/201712/06/100309kocmcg74gmes7zeo.jpg)

>
> 了解如何通过配置 Linux 计算机来根据时间自动唤醒和关闭。
>
>
>

不要成为一个电能浪费者。如果你的电脑不需要开机就请把它们关机。出于方便和计算机宅的考虑，你可以通过配置你的 Linux 计算机实现自动唤醒和关闭。

### 宝贵的系统运行时间

有时候有些电脑需要一直处在开机状态，在不超过电脑运行时间的限制下这种情况是被允许的。有些人为他们的计算机可以长时间的正常运行而感到自豪，且现在我们有内核热补丁能够实现只有在硬件发生故障时才需要机器关机。我认为比较实际可行的是，像减少移动部件磨损一样节省电能，且在不需要机器运行的情况下将其关机。比如，你可以在规定的时间内唤醒备份服务器，执行备份，然后关闭它直到它要进行下一次备份。或者，你可以设置你的互联网网关只在特定的时间运行。任何不需要一直运行的东西都可以将其配置成在其需要工作的时候打开，待其完成工作后将其关闭。

### 系统休眠

对于不需要一直运行的电脑，使用 root 的 cron 定时任务（即 `/etc/crontab`）可以可靠地关闭电脑。这个例子创建一个 root 定时任务实现每天晚上 11 点 15 分定时关机。

```
# crontab -e -u root
# m h  dom mon dow   command
15 23 * * * /sbin/shutdown -h now

```

以下示例仅在周一至周五运行：

```
15 23 * * 1-5 /sbin/shutdown -h now

```

您可以为不同的日期和时间创建多个 cron 作业。 通过命令 `man 5 crontab` 可以了解所有时间和日期的字段。

一个快速、容易的方式是，使用 `/etc/crontab` 文件。但这样你必须指定用户：

```
15 23 * * 1-5 root shutdown -h now

```

### 自动唤醒

实现自动唤醒是一件很酷的事情；我大多数 SUSE （SUSE Linux）的同事都在纽伦堡，因此，因此为了跟同事能有几小时一起工作的时间，我不得不需要在凌晨五点起床。我的计算机早上 5 点半自动开始工作，而我只需要将自己和咖啡拖到我的桌子上就可以开始工作了。按下电源按钮看起来好像并不是什么大事，但是在每天的那个时候每件小事都会变得很大。

唤醒 Linux 计算机可能不如关闭它可靠，因此你可能需要尝试不同的办法。你可以使用远程唤醒（Wake-On-LAN）、RTC 唤醒或者个人电脑的 BIOS 设置预定的唤醒这些方式。这些方式可行的原因是，当你关闭电脑时，这并不是真正关闭了计算机；此时计算机处在极低功耗状态且还可以接受和响应信号。只有在你拔掉电源开关时其才彻底关闭。

### BIOS 唤醒

BIOS 唤醒是最可靠的。我的系统主板 BIOS 有一个易于使用的唤醒调度程序 (图 1)。对你来说也是一样的容易。

![wakeup](/data/attachment/album/201712/06/100310rnn99t4p953ui69m.png)

*图 1：我的系统 BIOS 有个易用的唤醒定时器。*

### 主机远程唤醒（Wake-On-LAN）

远程唤醒是仅次于 BIOS 唤醒的又一种可靠的唤醒方法。这需要你从第二台计算机发送信号到所要打开的计算机。可以使用 Arduino 或<ruby> 树莓派 <rt>  Raspberry Pi </rt></ruby>发送给基于 Linux 的路由器或者任何 Linux 计算机的唤醒信号。首先，查看系统主板 BIOS 是否支持 Wake-On-LAN ，要是支持的话，必须先启动它，因为它被默认为禁用。

然后，需要一个支持 Wake-On-LAN 的网卡；无线网卡并不支持。你需要运行 `ethtool` 命令查看网卡是否支持 Wake-On-LAN ：

```
# ethtool eth0 | grep -i wake-on
        Supports Wake-on: pumbg
        Wake-on: g

```

这条命令输出的 “Supports Wake-on” 字段会告诉你你的网卡现在开启了哪些功能：

* d -- 禁用
* p -- 物理活动唤醒
* u -- 单播消息唤醒
* m -- 多播（组播）消息唤醒
* b -- 广播消息唤醒
* a -- ARP 唤醒
* g -- <ruby> 特定数据包 <rt>  magic packet </rt></ruby>唤醒
* s -- 设有密码的<ruby> 特定数据包 <rt>  magic packet </rt></ruby>唤醒

`ethtool` 命令的 man 手册并没说清楚 `p` 选项的作用；这表明任何信号都会导致唤醒。然而，在我的测试中它并没有这么做。想要实现远程唤醒主机，必须支持的功能是 `g` —— <ruby> 特定数据包 <rt>  magic packet </rt></ruby>唤醒，而且下面的“Wake-on” 行显示这个功能已经在启用了。如果它没有被启用，你可以通过 `ethtool` 命令来启用它。

```
# ethtool -s eth0 wol g

```

这条命令可能会在重启后失效，所以为了确保万无一失，你可以创建个 root 用户的定时任务（cron）在每次重启的时候来执行这条命令。

```
@reboot /usr/bin/ethtool -s eth0 wol g

```

另一个选择是最近的<ruby> 网络管理器 <rt>  Network Manager </rt></ruby>版本有一个很好的小复选框来启用 Wake-On-LAN（图 2）。

![wakeonlan](/data/attachment/album/201712/06/100310w4btt7b44ynlnnyz.png)

*图 2：启用 Wake on LAN*

这里有一个可以用于设置密码的地方，但是如果你的网络接口不支持<ruby> 安全开机 <rt>  Secure On </rt></ruby>密码，它就不起作用。

现在你需要配置第二台计算机来发送唤醒信号。你并不需要 root 权限，所以你可以为你的普通用户创建 cron 任务。你需要用到的是想要唤醒的机器的网络接口和MAC地址信息。

```
30 08 * * * /usr/bin/wakeonlan D0:50:99:82:E7:2B

```

### RTC 唤醒

通过使用实时闹钟来唤醒计算机是最不可靠的方法。对于这个方法，可以参看 [Wake Up Linux With an RTC Alarm Clock](https://www.linux.com/learn/wake-linux-rtc-alarm-clock) ；对于现在的大多数发行版来说这种方法已经有点过时了。

下周继续了解更多关于使用 RTC 唤醒的方法。

通过 Linux 基金会和 edX 可以学习更多关于 Linux 的免费 [Linux 入门](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)教程。

（题图：[The Observatory at Delhi](http://www.columbia.edu/itc/mealac/pritchett/00routesdata/1700_1799/jaipur/delhijantarearly/delhijantarearly.html)）

---

via:<https://www.linux.com/learn/intro-to-linux/2017/11/wake-and-shut-down-linux-automatically>

作者：[Carla Schroder](https://www.linux.com/users/cschroder) 译者：[HardworkFish](https://github.com/HardworkFish) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何判断 Linux 服务器是否被入侵？

Summary: 大多数被攻破的服务器都是被类似自动攻击程序这样的程序或者类似“脚本小子”这样的廉价攻击者，以及蠢蛋罪犯所入侵的。这类攻击者会在访问服务器的同时滥用服务器资源，并且不怎么会采取措施来隐藏他们正在做的事情。

![](/data/attachment/album/201712/06/153011mrmc4foxd70sowxr.jpg)

本指南中所谓的服务器被入侵或者说被黑了的意思，是指未经授权的人或程序为了自己的目的登录到服务器上去并使用其计算资源，通常会产生不好的影响。

免责声明：若你的服务器被类似 NSA 这样的国家机关或者某个犯罪集团入侵，那么你并不会注意到有任何问题，这些技术也无法发觉他们的存在。

然而，大多数被攻破的服务器都是被类似自动攻击程序这样的程序或者类似“脚本小子”这样的廉价攻击者，以及蠢蛋罪犯所入侵的。

这类攻击者会在访问服务器的同时滥用服务器资源，并且不怎么会采取措施来隐藏他们正在做的事情。

### 被入侵服务器的症状

当服务器被没有经验攻击者或者自动攻击程序入侵了的话，他们往往会消耗 100% 的资源。他们可能消耗 CPU 资源来进行数字货币的采矿或者发送垃圾邮件，也可能消耗带宽来发动 DoS 攻击。

因此出现问题的第一个表现就是服务器 “变慢了”。这可能表现在网站的页面打开的很慢，或者电子邮件要花很长时间才能发送出去。

那么你应该查看那些东西呢?

#### 检查 1 - 当前都有谁在登录?

你首先要查看当前都有谁登录在服务器上。发现攻击者登录到服务器上进行操作并不复杂。

其对应的命令是 `w`。运行 `w` 会输出如下结果：

```
 08:32:55 up 98 days,  5:43,  2 users,  load average: 0.05, 0.03, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    113.174.161.1    08:26    0.00s  0.03s  0.02s ssh root@coopeaa12
root     pts/1    78.31.109.1      08:26    0.00s  0.01s  0.00s w

```

第一个 IP 是英国 IP，而第二个 IP 是越南 IP。这个不是个好兆头。

停下来做个深呼吸, 不要恐慌之下只是干掉他们的 SSH 连接。除非你能够防止他们再次进入服务器，否则他们会很快进来并踢掉你，以防你再次回去。

请参阅本文最后的“被入侵之后怎么办”这一章节来看找到了被入侵的证据后应该怎么办。

`whois` 命令可以接一个 IP 地址然后告诉你该 IP 所注册的组织的所有信息，当然就包括所在国家的信息。

#### 检查 2 - 谁曾经登录过?

Linux 服务器会记录下哪些用户，从哪个 IP，在什么时候登录的以及登录了多长时间这些信息。使用 `last` 命令可以查看这些信息。

输出类似这样：

```
root     pts/1        78.31.109.1      Thu Nov 30 08:26   still logged in
root     pts/0        113.174.161.1    Thu Nov 30 08:26   still logged in
root     pts/1        78.31.109.1      Thu Nov 30 08:24 - 08:26  (00:01)
root     pts/0        113.174.161.1    Wed Nov 29 12:34 - 12:52  (00:18)
root     pts/0        14.176.196.1     Mon Nov 27 13:32 - 13:53  (00:21)

```

这里可以看到英国 IP 和越南 IP 交替出现，而且最上面两个 IP 现在还处于登录状态。如果你看到任何未经授权的 IP，那么请参阅最后章节。

登录后的历史记录会记录到二进制的 `/var/log/wtmp` 文件中（LCTT 译注：这里作者应该写错了，根据实际情况修改），因此很容易被删除。通常攻击者会直接把这个文件删掉，以掩盖他们的攻击行为。 因此, 若你运行了 `last` 命令却只看得见你的当前登录，那么这就是个不妙的信号。

如果没有登录历史的话，请一定小心，继续留意入侵的其他线索。

#### 检查 3 - 回顾命令历史

这个层次的攻击者通常不会注意掩盖命令的历史记录，因此运行 `history` 命令会显示出他们曾经做过的所有事情。 一定留意有没有用 `wget` 或 `curl` 命令来下载类似垃圾邮件机器人或者挖矿程序之类的非常规软件。

命令历史存储在 `~/.bash_history` 文件中，因此有些攻击者会删除该文件以掩盖他们的所作所为。跟登录历史一样，若你运行 `history` 命令却没有输出任何东西那就表示历史文件被删掉了。这也是个不妙的信号，你需要很小心地检查一下服务器了。（LCTT 译注，如果没有命令历史，也有可能是你的配置错误。）

#### 检查 4 - 哪些进程在消耗 CPU？

你常遇到的这类攻击者通常不怎么会去掩盖他们做的事情。他们会运行一些特别消耗 CPU 的进程。这就很容易发现这些进程了。只需要运行 `top` 然后看最前的那几个进程就行了。

这也能显示出那些未登录进来的攻击者。比如，可能有人在用未受保护的邮件脚本来发送垃圾邮件。

如果你最上面的进程对不了解，那么你可以 Google 一下进程名称，或者通过 `losf` 和 `strace` 来看看它做的事情是什么。

使用这些工具，第一步从 `top` 中拷贝出进程的 PID，然后运行：

```
strace -p PID

```

这会显示出该进程调用的所有系统调用。它产生的内容会很多，但这些信息能告诉你这个进程在做什么。

```
lsof  -p PID

```

这个程序会列出该进程打开的文件。通过查看它访问的文件可以很好的理解它在做的事情。

#### 检查 5 - 检查所有的系统进程

消耗 CPU 不严重的未授权进程可能不会在 `top` 中显露出来，不过它依然可以通过 `ps` 列出来。命令 `ps auxf` 就能显示足够清晰的信息了。

你需要检查一下每个不认识的进程。经常运行 `ps` （这是个好习惯）能帮助你发现奇怪的进程。

#### 检查 6 - 检查进程的网络使用情况

`iftop` 的功能类似 `top`，它会排列显示收发网络数据的进程以及它们的源地址和目的地址。类似 DoS 攻击或垃圾机器人这样的进程很容易显示在列表的最顶端。

#### 检查 7 - 哪些进程在监听网络连接?

通常攻击者会安装一个后门程序专门监听网络端口接受指令。该进程等待期间是不会消耗 CPU 和带宽的，因此也就不容易通过 `top` 之类的命令发现。

`lsof` 和 `netstat` 命令都会列出所有的联网进程。我通常会让它们带上下面这些参数：

```
lsof -i

```

```
netstat -plunt

```

你需要留意那些处于 `LISTEN` 和 `ESTABLISHED` 状态的进程，这些进程要么正在等待连接（LISTEN），要么已经连接（ESTABLISHED）。如果遇到不认识的进程，使用 `strace` 和 `lsof` 来看看它们在做什么东西。

### 被入侵之后该怎么办呢?

首先，不要紧张，尤其当攻击者正处于登录状态时更不能紧张。**你需要在攻击者警觉到你已经发现他之前夺回机器的控制权。**如果他发现你已经发觉到他了，那么他可能会锁死你不让你登陆服务器，然后开始毁尸灭迹。

如果你技术不太好那么就直接关机吧。你可以在服务器上运行 `shutdown -h now` 或者 `systemctl poweroff` 这两条命令之一。也可以登录主机提供商的控制面板中关闭服务器。关机后，你就可以开始配置防火墙或者咨询一下供应商的意见。

如果你对自己颇有自信，而你的主机提供商也有提供上游防火墙，那么你只需要以此创建并启用下面两条规则就行了：

1. 只允许从你的 IP 地址登录 SSH。
2. 封禁除此之外的任何东西，不仅仅是 SSH，还包括任何端口上的任何协议。

这样会立即关闭攻击者的 SSH 会话，而只留下你可以访问服务器。

如果你无法访问上游防火墙，那么你就需要在服务器本身创建并启用这些防火墙策略，然后在防火墙规则起效后使用 `kill` 命令关闭攻击者的 SSH 会话。（LCTT 译注：本地防火墙规则 有可能不会阻止已经建立的 SSH 会话，所以保险起见，你需要手工杀死该会话。）

最后还有一种方法，如果支持的话，就是通过诸如串行控制台之类的带外连接登录服务器，然后通过 `systemctl stop network.service` 停止网络功能。这会关闭所有服务器上的网络连接，这样你就可以慢慢的配置那些防火墙规则了。

重夺服务器的控制权后，也不要以为就万事大吉了。

不要试着修复这台服务器，然后接着用。你永远不知道攻击者做过什么，因此你也永远无法保证这台服务器还是安全的。

最好的方法就是拷贝出所有的数据，然后重装系统。（LCTT 译注：你的程序这时已经不可信了，但是数据一般来说没问题。）

---

via: <https://bash-prompt.net/guides/server-hacked/>

作者：[Elliot Cooper](https://bash-prompt.net) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


并发服务器（三）：事件驱动

Summary: 另一种常见的实现并发的方法叫做 事件驱动编程，也可以叫做 异步 编程 。这种方法变化万千，因此我们会从最基本的开始，使用一些基本的 API 而非从封装好的高级方法开始。本系列以后的文章会讲高层次抽象，还有各种混合的方法。

![](/data/attachment/album/201712/06/162148e551uz4iyjotimib.jpg)

这是并发服务器系列的第三节。[第一节](/article-8993-1.html) 介绍了阻塞式编程，[第二节：线程](/article-9002-1.html) 探讨了多线程，将其作为一种可行的方法来实现服务器并发编程。

另一种常见的实现并发的方法叫做 *事件驱动编程*，也可以叫做 *异步* 编程  注1 。这种方法变化万千，因此我们会从最基本的开始，使用一些基本的 API 而非从封装好的高级方法开始。本系列以后的文章会讲高层次抽象，还有各种混合的方法。

本系列的所有文章：

* [第一节 - 简介](/article-8993-1.html)
* [第二节 - 线程](/article-9002-1.html)
* [第三节 - 事件驱动](http://eli.thegreenplace.net/2017/concurrent-servers-part-3-event-driven/)

### 阻塞式 vs. 非阻塞式 I/O

作为本篇的介绍，我们先讲讲阻塞和非阻塞 I/O 的区别。阻塞式 I/O 更好理解，因为这是我们使用 I/O 相关 API 时的“标准”方式。从套接字接收数据的时候，调用 `recv` 函数会发生 *阻塞*，直到它从端口上接收到了来自另一端套接字的数据。这恰恰是第一部分讲到的顺序服务器的问题。

因此阻塞式 I/O 存在着固有的性能问题。第二节里我们讲过一种解决方法，就是用多线程。哪怕一个线程的 I/O 阻塞了，别的线程仍然可以使用 CPU 资源。实际上，阻塞 I/O 通常在利用资源方面非常高效，因为线程就等待着 —— 操作系统将线程变成休眠状态，只有满足了线程需要的条件才会被唤醒。

*非阻塞式* I/O 是另一种思路。把套接字设成非阻塞模式时，调用 `recv` 时（还有 `send`，但是我们现在只考虑接收），函数返回的会很快，哪怕没有接收到数据。这时，就会返回一个特殊的错误状态  注2 来通知调用者，此时没有数据传进来。调用者可以去做其他的事情，或者尝试再次调用 `recv` 函数。

示范阻塞式和非阻塞式的 `recv` 区别的最好方式就是贴一段示例代码。这里有个监听套接字的小程序，一直在 `recv` 这里阻塞着；当 `recv` 返回了数据，程序就报告接收到了多少个字节  注3 ：

```
int main(int argc, const char** argv) {
  setvbuf(stdout, NULL, _IONBF, 0);

  int portnum = 9988;
  if (argc >= 2) {
    portnum = atoi(argv[1]);
  }
  printf("Listening on port %d\n", portnum);

  int sockfd = listen_inet_socket(portnum);
  struct sockaddr_in peer_addr;
  socklen_t peer_addr_len = sizeof(peer_addr);

  int newsockfd = accept(sockfd, (struct sockaddr*)&peer_addr, &peer_addr_len);
  if (newsockfd < 0) {
    perror_die("ERROR on accept");
  }
  report_peer_connected(&peer_addr, peer_addr_len);

  while (1) {
    uint8_t buf[1024];
    printf("Calling recv...\n");
    int len = recv(newsockfd, buf, sizeof buf, 0);
    if (len < 0) {
      perror_die("recv");
    } else if (len == 0) {
      printf("Peer disconnected; I'm done.\n");
      break;
    }
    printf("recv returned %d bytes\n", len);
  }

  close(newsockfd);
  close(sockfd);

  return 0;
}

```

主循环重复调用 `recv` 并且报告它返回的字节数（记住 `recv` 返回 0 时，就是客户端断开连接了）。试着运行它，我们会在一个终端里运行这个程序，然后在另一个终端里用 `nc` 进行连接，发送一些字符，每次发送之间间隔几秒钟：

```
$ nc localhost 9988
hello                                   # wait for 2 seconds after typing this
socket world
^D                                      # to end the connection>

```

监听程序会输出以下内容：

```
$ ./blocking-listener 9988
Listening on port 9988
peer (localhost, 37284) connected
Calling recv...
recv returned 6 bytes
Calling recv...
recv returned 13 bytes
Calling recv...
Peer disconnected; I'm done.

```

现在试试非阻塞的监听程序的版本。这是代码：

```
int main(int argc, const char** argv) {
  setvbuf(stdout, NULL, _IONBF, 0);

  int portnum = 9988;
  if (argc >= 2) {
    portnum = atoi(argv[1]);
  }
  printf("Listening on port %d\n", portnum);

  int sockfd = listen_inet_socket(portnum);
  struct sockaddr_in peer_addr;
  socklen_t peer_addr_len = sizeof(peer_addr);

  int newsockfd = accept(sockfd, (struct sockaddr*)&peer_addr, &peer_addr_len);
  if (newsockfd < 0) {
    perror_die("ERROR on accept");
  }
  report_peer_connected(&peer_addr, peer_addr_len);

  // 把套接字设成非阻塞模式
  int flags = fcntl(newsockfd, F_GETFL, 0);
  if (flags == -1) {
    perror_die("fcntl F_GETFL");
  }

  if (fcntl(newsockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
    perror_die("fcntl F_SETFL O_NONBLOCK");
  }

  while (1) {
    uint8_t buf[1024];
    printf("Calling recv...\n");
    int len = recv(newsockfd, buf, sizeof buf, 0);
    if (len < 0) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) {
        usleep(200 * 1000);
        continue;
      }
      perror_die("recv");
    } else if (len == 0) {
      printf("Peer disconnected; I'm done.\n");
      break;
    }
    printf("recv returned %d bytes\n", len);
  }

  close(newsockfd);
  close(sockfd);

  return 0;
}

```

这里与阻塞版本有些差异，值得注意：

1. `accept` 函数返回的 `newsocktfd` 套接字因调用了 `fcntl`， 被设置成非阻塞的模式。
2. 检查 `recv` 的返回状态时，我们对 `errno` 进行了检查，判断它是否被设置成表示没有可供接收的数据的状态。这时，我们仅仅是休眠了 200 毫秒然后进入到下一轮循环。

同样用 `nc` 进行测试，以下是非阻塞监听器的输出：

```
$ ./nonblocking-listener 9988
Listening on port 9988
peer (localhost, 37288) connected
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
recv returned 6 bytes
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
Calling recv...
recv returned 13 bytes
Calling recv...
Calling recv...
Calling recv...
Peer disconnected; I'm done.

```

作为练习，给输出添加一个时间戳，确认调用 `recv` 得到结果之间花费的时间是比输入到 `nc` 中所用的多还是少（每一轮是 200 ms）。

这里就实现了使用非阻塞的 `recv` 让监听者检查套接字变为可能，并且在没有数据的时候重新获得控制权。换句话说，用编程的语言说这就是 <ruby> 轮询 <rt>  polling </rt></ruby> —— 主程序周期性的查询套接字以便读取数据。

对于顺序响应的问题，这似乎是个可行的方法。非阻塞的 `recv` 让同时与多个套接字通信变成可能，轮询这些套接字，仅当有新数据到来时才处理。就是这样，这种方式 *可以* 用来写并发服务器；但实际上一般不这么做，因为轮询的方式很难扩展。

首先，我在代码中引入的 200ms 延迟对于演示非常好（监听器在我输入 `nc` 之间只打印几行 “Calling recv...”，但实际上应该有上千行）。但它也增加了多达 200ms 的服务器响应时间，这无意是不必要的。实际的程序中，延迟会低得多，休眠时间越短，进程占用的 CPU 资源就越多。有些时钟周期只是浪费在等待，这并不好，尤其是在移动设备上，这些设备的电量往往有限。

但是当我们实际这样来使用多个套接字的时候，更严重的问题出现了。想像下监听器正在同时处理 1000 个客户端。这意味着每一个循环迭代里面，它都得为 *这 1000 个套接字中的每一个* 执行一遍非阻塞的 `recv`，找到其中准备好了数据的那一个。这非常低效，并且极大的限制了服务器能够并发处理的客户端数。这里有个准则：每次轮询之间等待的间隔越久，服务器响应性越差；而等待的时间越少，CPU 在无用的轮询上耗费的资源越多。

讲真，所有的轮询都像是无用功。当然操作系统应该是知道哪个套接字是准备好了数据的，因此没必要逐个扫描。事实上，就是这样，接下来就会讲一些 API，让我们可以更优雅地处理多个客户端。

### select

`select` 的系统调用是可移植的（POSIX），是标准 Unix API 中常有的部分。它是为上一节最后一部分描述的问题而设计的 —— 允许一个线程可以监视许多文件描述符  注4 的变化，而不用在轮询中执行不必要的代码。我并不打算在这里引入一个关于 `select` 的全面教程，有很多网站和书籍讲这个，但是在涉及到问题的相关内容时，我会介绍一下它的 API，然后再展示一个非常复杂的例子。

`select` 允许 *多路 I/O*，监视多个文件描述符，查看其中任何一个的 I/O 是否可用。

```
int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

```

`readfds` 指向文件描述符的缓冲区，这个缓冲区被监视是否有读取事件；`fd_set` 是一个特殊的数据结构，用户使用 `FD_*` 宏进行操作。`writefds` 是针对写事件的。`nfds` 是监视的缓冲中最大的文件描述符数字（文件描述符就是整数）。`timeout` 可以让用户指定 `select` 应该阻塞多久，直到某个文件描述符准备好了（`timeout == NULL` 就是说一直阻塞着）。现在先跳过 `exceptfds`。

`select` 的调用过程如下：

1. 在调用之前，用户先要为所有不同种类的要监视的文件描述符创建 `fd_set` 实例。如果想要同时监视读取和写入事件，`readfds` 和 `writefds` 都要被创建并且引用。
2. 用户可以使用 `FD_SET` 来设置集合中想要监视的特殊描述符。例如，如果想要监视描述符 2、7 和 10 的读取事件，在 `readfds` 这里调用三次 `FD_SET`，分别设置 2、7 和 10。
3. `select` 被调用。
4. 当 `select` 返回时（现在先不管超时），就是说集合中有多少个文件描述符已经就绪了。它也修改 `readfds` 和 `writefds` 集合，来标记这些准备好的描述符。其它所有的描述符都会被清空。
5. 这时用户需要遍历 `readfds` 和 `writefds`，找到哪个描述符就绪了（使用 `FD_ISSET`）。

作为完整的例子，我在并发的服务器程序上使用 `select`，重新实现了我们之前的协议。[完整的代码在这里](https://github.com/eliben/code-for-blog/blob/master/2017/async-socket-server/select-server.c)；接下来的是代码中的重点部分及注释。警告：示例代码非常复杂，因此第一次看的时候，如果没有足够的时间，快速浏览也没有关系。

### 使用 select 的并发服务器

使用 I/O 的多发 API 诸如 `select` 会给我们服务器的设计带来一些限制；这不会马上显现出来，但这值得探讨，因为它们是理解事件驱动编程到底是什么的关键。

最重要的是，要记住这种方法本质上是单线程的  注5 。服务器实际上在 *同一时刻只能做一件事*。因为我们想要同时处理多个客户端请求，我们需要换一种方式重构代码。

首先，让我们谈谈主循环。它看起来是什么样的呢？先让我们想象一下服务器有一堆任务，它应该监视哪些东西呢？两种类型的套接字活动：

1. 新客户端尝试连接。这些客户端应该被 `accept`。
2. 已连接的客户端发送数据。这个数据要用 [第一节](/article-8993-1.html) 中所讲到的协议进行传输，有可能会有一些数据要被回送给客户端。

尽管这两种活动在本质上有所区别，我们还是要把它们放在一个循环里，因为只能有一个主循环。循环会包含 `select` 的调用。这个 `select` 的调用会监视上述的两种活动。

这里是部分代码，设置了文件描述符集合，并在主循环里转到被调用的 `select` 部分。

```
// “master” 集合存活在该循环中，跟踪我们想要监视的读取事件或写入事件的文件描述符（FD）。
fd_set readfds_master;
FD_ZERO(&readfds_master);
fd_set writefds_master;
FD_ZERO(&writefds_master);

// 监听的套接字一直被监视，用于读取数据，并监测到来的新的端点连接。
FD_SET(listener_sockfd, &readfds_master);

// 要想更加高效，fdset_max 追踪当前已知最大的 FD；这使得每次调用时对 FD_SETSIZE 的迭代选择不是那么重要了。
int fdset_max = listener_sockfd;

while (1) {
  // select() 会修改传递给它的 fd_sets，因此进行拷贝一下再传值。
  fd_set readfds = readfds_master;
  fd_set writefds = writefds_master;

  int nready = select(fdset_max + 1, &readfds, &writefds, NULL, NULL);
  if (nready < 0) {
    perror_die("select");
  }
  ...

```

这里的一些要点：

1. 由于每次调用 `select` 都会重写传递给函数的集合，调用器就得维护一个 “master” 集合，在循环迭代中，保持对所监视的所有活跃的套接字的追踪。
2. 注意我们所关心的，最开始的唯一那个套接字是怎么变成 `listener_sockfd` 的，这就是最开始的套接字，服务器借此来接收新客户端的连接。
3. `select` 的返回值，是在作为参数传递的集合中，那些已经就绪的描述符的个数。`select` 修改这个集合，用来标记就绪的描述符。下一步是在这些描述符中进行迭代。

```
...
for (int fd = 0; fd <= fdset_max && nready > 0; fd++) {
  // 检查 fd 是否变成可读的
  if (FD_ISSET(fd, &readfds)) {
    nready--;

    if (fd == listener_sockfd) {
      // 监听的套接字就绪了；这意味着有个新的客户端连接正在联系
      ...
    } else {
      fd_status_t status = on_peer_ready_recv(fd);
      if (status.want_read) {
        FD_SET(fd, &readfds_master);
      } else {
        FD_CLR(fd, &readfds_master);
      }
      if (status.want_write) {
        FD_SET(fd, &writefds_master);
      } else {
        FD_CLR(fd, &writefds_master);
      }
      if (!status.want_read && !status.want_write) {
        printf("socket %d closing\n", fd);
        close(fd);
      }
    }

```

这部分循环检查 *可读的* 描述符。让我们跳过监听器套接字（要浏览所有内容，[看这个代码](https://github.com/eliben/code-for-blog/blob/master/2017/async-socket-server/select-server.c)） 然后看看当其中一个客户端准备好了之后会发生什么。出现了这种情况后，我们调用一个叫做 `on_peer_ready_recv` 的 *回调* 函数，传入相应的文件描述符。这个调用意味着客户端连接到套接字上，发送某些数据，并且对套接字上 `recv` 的调用不会被阻塞  注6 。这个回调函数返回结构体 `fd_status_t`。

```
typedef struct {
  bool want_read;
  bool want_write;
} fd_status_t;

```

这个结构体告诉主循环，是否应该监视套接字的读取事件、写入事件，或者两者都监视。上述代码展示了 `FD_SET` 和 `FD_CLR` 是怎么在合适的描述符集合中被调用的。对于主循环中某个准备好了写入数据的描述符，代码是类似的，除了它所调用的回调函数，这个回调函数叫做 `on_peer_ready_send`。

现在来花点时间看看这个回调：

```
typedef enum { INITIAL_ACK, WAIT_FOR_MSG, IN_MSG } ProcessingState;

#define SENDBUF_SIZE 1024

typedef struct {
  ProcessingState state;

  // sendbuf 包含了服务器要返回给客户端的数据。on_peer_ready_recv 句柄填充这个缓冲，
  // on_peer_read_send 进行消耗。sendbuf_end 指向缓冲区的最后一个有效字节，
  // sendptr 指向下个字节
  uint8_t sendbuf[SENDBUF_SIZE];
  int sendbuf_end;
  int sendptr;
} peer_state_t;

// 每一端都是通过它连接的文件描述符（fd）进行区分。只要客户端连接上了，fd 就是唯一的。
// 当客户端断开连接，另一个客户端连接上就会获得相同的 fd。on_peer_connected 应该
// 进行初始化，以便移除旧客户端在同一个 fd 上留下的东西。
peer_state_t global_state[MAXFDS];

fd_status_t on_peer_ready_recv(int sockfd) {
  assert(sockfd < MAXFDs);
  peer_state_t* peerstate = &global_state[sockfd];

  if (peerstate->state == INITIAL_ACK ||
      peerstate->sendptr < peerstate->sendbuf_end) {
    // 在初始的 ACK 被送到了客户端，就没有什么要接收的了。
    // 等所有待发送的数据都被发送之后接收更多的数据。
    return fd_status_W;
  }

  uint8_t buf[1024];
  int nbytes = recv(sockfd, buf, sizeof buf, 0);
  if (nbytes == 0) {
    // 客户端断开连接
    return fd_status_NORW;
  } else if (nbytes < 0) {
    if (errno == EAGAIN || errno == EWOULDBLOCK) {
      // 套接字 *实际* 并没有准备好接收，等到它就绪。
      return fd_status_R;
    } else {
      perror_die("recv");
    }
  }
  bool ready_to_send = false;
  for (int i = 0; i < nbytes; ++i) {
    switch (peerstate->state) {
    case INITIAL_ACK:
      assert(0 && "can't reach here");
      break;
    case WAIT_FOR_MSG:
      if (buf[i] == '^') {
        peerstate->state = IN_MSG;
      }
      break;
    case IN_MSG:
      if (buf[i] == '$') {
        peerstate->state = WAIT_FOR_MSG;
      } else {
        assert(peerstate->sendbuf_end < SENDBUF_SIZE);
        peerstate->sendbuf[peerstate->sendbuf_end++] = buf[i] + 1;
        ready_to_send = true;
      }
      break;
    }
  }
  // 如果没有数据要发送给客户端，报告读取状态作为最后接收的结果。
  return (fd_status_t){.want_read = !ready_to_send,
                       .want_write = ready_to_send};
}

```

`peer_state_t` 是全状态对象，用来表示在主循环中两次回调函数调用之间的客户端的连接。因为回调函数在客户端发送的某些数据时被调用，不能假设它能够不停地与客户端通信，并且它得运行得很快，不能被阻塞。因为套接字被设置成非阻塞模式，`recv` 会快速的返回。除了调用 `recv`， 这个句柄做的是处理状态，没有其它的调用，从而不会发生阻塞。

举个例子，你知道为什么这个代码需要一个额外的状态吗？这个系列中，我们的服务器目前只用到了两个状态，但是这个服务器程序需要三个状态。

来看看 “套接字准备好发送” 的回调函数：

```
fd_status_t on_peer_ready_send(int sockfd) {
  assert(sockfd < MAXFDs);
  peer_state_t* peerstate = &global_state[sockfd];

  if (peerstate->sendptr >= peerstate->sendbuf_end) {
    // 没有要发送的。
    return fd_status_RW;
  }
  int sendlen = peerstate->sendbuf_end - peerstate->sendptr;
  int nsent = send(sockfd, peerstate->sendbuf, sendlen, 0);
  if (nsent == -1) {
    if (errno == EAGAIN || errno == EWOULDBLOCK) {
      return fd_status_W;
    } else {
      perror_die("send");
    }
  }
  if (nsent < sendlen) {
    peerstate->sendptr += nsent;
    return fd_status_W;
  } else {
    // 所有东西都成功发送；重置发送队列。
    peerstate->sendptr = 0;
    peerstate->sendbuf_end = 0;

    // 如果我们现在是处于特殊的 INITIAL_ACK 状态，就转变到其他状态。
    if (peerstate->state == INITIAL_ACK) {
      peerstate->state = WAIT_FOR_MSG;
    }

    return fd_status_R;
  }
}

```

这里也一样，回调函数调用了一个非阻塞的 `send`，演示了状态管理。在异步代码中，回调函数执行的很快是受争议的，任何延迟都会阻塞主循环进行处理，因此也阻塞了整个服务器程序去处理其他的客户端。

用脚步再来运行这个服务器，同时连接 3 个客户端。在一个终端中我们运行下面的命令：

```
$ ./select-server

```

在另一个终端中：

```
$ python3.6 simple-client.py  -n 3 localhost 9090
INFO:2017-09-26 05:29:15,864:conn1 connected...
INFO:2017-09-26 05:29:15,864:conn2 connected...
INFO:2017-09-26 05:29:15,864:conn0 connected...
INFO:2017-09-26 05:29:15,865:conn1 sending b'^abc$de^abte$f'
INFO:2017-09-26 05:29:15,865:conn2 sending b'^abc$de^abte$f'
INFO:2017-09-26 05:29:15,865:conn0 sending b'^abc$de^abte$f'
INFO:2017-09-26 05:29:15,865:conn1 received b'bcdbcuf'
INFO:2017-09-26 05:29:15,865:conn2 received b'bcdbcuf'
INFO:2017-09-26 05:29:15,865:conn0 received b'bcdbcuf'
INFO:2017-09-26 05:29:16,866:conn1 sending b'xyz^123'
INFO:2017-09-26 05:29:16,867:conn0 sending b'xyz^123'
INFO:2017-09-26 05:29:16,867:conn2 sending b'xyz^123'
INFO:2017-09-26 05:29:16,867:conn1 received b'234'
INFO:2017-09-26 05:29:16,868:conn0 received b'234'
INFO:2017-09-26 05:29:16,868:conn2 received b'234'
INFO:2017-09-26 05:29:17,868:conn1 sending b'25$^ab0000$abab'
INFO:2017-09-26 05:29:17,869:conn1 received b'36bc1111'
INFO:2017-09-26 05:29:17,869:conn0 sending b'25$^ab0000$abab'
INFO:2017-09-26 05:29:17,870:conn0 received b'36bc1111'
INFO:2017-09-26 05:29:17,870:conn2 sending b'25$^ab0000$abab'
INFO:2017-09-26 05:29:17,870:conn2 received b'36bc1111'
INFO:2017-09-26 05:29:18,069:conn1 disconnecting
INFO:2017-09-26 05:29:18,070:conn0 disconnecting
INFO:2017-09-26 05:29:18,070:conn2 disconnecting

```

和线程的情况相似，客户端之间没有延迟，它们被同时处理。而且在 `select-server` 也没有用线程！主循环 *多路* 处理所有的客户端，通过高效使用 `select` 轮询多个套接字。回想下 [第二节中](/article-9002-1.html) 顺序的 vs 多线程的客户端处理过程的图片。对于我们的 `select-server`，三个客户端的处理流程像这样：

![多客户端处理流程](/data/attachment/album/201712/06/162203v1rccyreync5zu1u.png)

所有的客户端在同一个线程中同时被处理，通过乘积，做一点这个客户端的任务，然后切换到另一个，再切换到下一个，最后切换回到最开始的那个客户端。注意，这里没有什么循环调度，客户端在它们发送数据的时候被客户端处理，这实际上是受客户端左右的。

### 同步、异步、事件驱动、回调

`select-server` 示例代码为讨论什么是异步编程、它和事件驱动及基于回调的编程有何联系，提供了一个良好的背景。因为这些词汇在并发服务器的（非常矛盾的）讨论中很常见。

让我们从一段 `select` 的手册页面中引用的一句话开始：

>
> select，pselect，FD\_CLR，FD\_ISSET，FD\_SET，FD\_ZERO - 同步 I/O 处理
>
>
>

因此 `select` 是 *同步* 处理。但我刚刚演示了大量代码的例子，使用 `select` 作为 *异步* 处理服务器的例子。有哪些东西？

答案是：这取决于你的观察角度。同步常用作阻塞处理，并且对 `select` 的调用实际上是阻塞的。和第 1、2 节中讲到的顺序的、多线程的服务器中对 `send` 和 `recv` 是一样的。因此说 `select` 是 *同步的* API 是有道理的。可是，服务器的设计却可以是 *异步的*，或是 *基于回调的*，或是 *事件驱动的*，尽管其中有对 `select` 的使用。注意这里的 `on_peer_*` 函数是回调函数；它们永远不会阻塞，并且只有网络事件触发的时候才会被调用。它们可以获得部分数据，并能够在调用过程中保持稳定的状态。

如果你曾经做过一些 GUI 编程，这些东西对你来说应该很亲切。有个 “事件循环”，常常完全隐藏在框架里，应用的 “业务逻辑” 建立在回调上，这些回调会在各种事件触发后被调用，用户点击鼠标、选择菜单、定时器触发、数据到达套接字等等。曾经最常见的编程模型是客户端的 JavaScript，这里面有一堆回调函数，它们在浏览网页时用户的行为被触发。

### select 的局限

使用 `select` 作为第一个异步服务器的例子对于说明这个概念很有用，而且由于 `select` 是很常见、可移植的 API。但是它也有一些严重的缺陷，在监视的文件描述符非常大的时候就会出现。

1. 有限的文件描述符的集合大小。
2. 糟糕的性能。

从文件描述符的大小开始。`FD_SETSIZE` 是一个编译期常数，在如今的操作系统中，它的值通常是 1024。它被硬编码在 `glibc` 的头文件里，并且不容易修改。它把 `select` 能够监视的文件描述符的数量限制在 1024 以内。曾有些人想要写出能够处理上万个并发访问的客户端请求的服务器，所以这个问题很有现实意义。有一些方法，但是不可移植，也很难用。

糟糕的性能问题就好解决的多，但是依然非常严重。注意当 `select` 返回的时候，它向调用者提供的信息是 “就绪的” 描述符的个数，还有被修改过的描述符集合。描述符集映射着描述符“就绪/未就绪”，但是并没有提供什么有效的方法去遍历所有就绪的描述符。如果只有一个描述符是就绪的，最坏的情况是调用者需要遍历 *整个集合* 来找到那个描述符。这在监视的描述符数量比较少的时候还行，但是如果数量变的很大的时候，这种方法弊端就凸显出了  注7 。

由于这些原因，为了写出高性能的并发服务器， `select` 已经不怎么用了。每一个流行的操作系统有独特的不可移植的 API，允许用户写出非常高效的事件循环；像框架这样的高级结构还有高级语言通常在一个可移植的接口中包含这些 API。

### epoll

举个例子，来看看 `epoll`，Linux 上的关于高容量 I/O 事件通知问题的解决方案。`epoll` 高效的关键之处在于它与内核更好的协作。不是使用文件描述符，`epoll_wait` 用当前准备好的事件填满一个缓冲区。只有准备好的事件添加到了缓冲区，因此没有必要遍历客户端中当前 *所有* 监视的文件描述符。这简化了查找就绪的描述符的过程，把空间复杂度从 `select` 中的 O(N) 变为了 O(1)。

关于 `epoll` API 的完整展示不是这里的目的，网上有很多相关资源。虽然你可能猜到了，我还要写一个不同的并发服务器，这次是用 `epool` 而不是 `select`。完整的示例代码 [在这里](https://github.com/eliben/code-for-blog/blob/master/2017/async-socket-server/epoll-server.c)。实际上，由于大部分代码和 `用 select 的服务器`相同，所以我只会讲要点，在主循环里使用 `epoll`：

```
struct epoll_event accept_event;
accept_event.data.fd = listener_sockfd;
accept_event.events = EPOLLIN;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listener_sockfd, &accept_event) < 0) {
  perror_die("epoll_ctl EPOLL_CTL_ADD");
}

struct epoll_event* events = calloc(MAXFDS, sizeof(struct epoll_event));
if (events == NULL) {
  die("Unable to allocate memory for epoll_events");
}

while (1) {
  int nready = epoll_wait(epollfd, events, MAXFDS, -1);
  for (int i = 0; i < nready; i++) {
    if (events[i].events & EPOLLERR) {
      perror_die("epoll_wait returned EPOLLERR");
    }

    if (events[i].data.fd == listener_sockfd) {
      // 监听的套接字就绪了；意味着新客户端正在连接。
      ...
    } else {
      // A peer socket is ready.
      if (events[i].events & EPOLLIN) {
        // 准备好了读取
        ...
      } else if (events[i].events & EPOLLOUT) {
        // 准备好了写入
        ...
      }
    }
  }
}

```

通过调用 `epoll_ctl` 来配置 `epoll`。这时，配置监听的套接字数量，也就是 `epoll` 监听的描述符的数量。然后分配一个缓冲区，把就绪的事件传给 `epoll` 以供修改。在主循环里对 `epoll_wait` 的调用是魅力所在。它阻塞着，直到某个描述符就绪了（或者超时），返回就绪的描述符数量。但这时，不要盲目地迭代所有监视的集合，我们知道 `epoll_write` 会修改传给它的 `events` 缓冲区，缓冲区中有就绪的事件，从 0 到 `nready-1`，因此我们只需迭代必要的次数。

要在 `select` 里面重新遍历，有明显的差异：如果在监视着 1000 个描述符，只有两个就绪， `epoll_waits` 返回的是 `nready=2`，然后修改 `events` 缓冲区最前面的两个元素，因此我们只需要“遍历”两个描述符。用 `select` 我们就需要遍历 1000 个描述符，找出哪个是就绪的。因此，在繁忙的服务器上，有许多活跃的套接字时 `epoll` 比 `select` 更加容易扩展。

剩下的代码很直观，因为我们已经很熟悉 “select 服务器” 了。实际上，“epoll 服务器” 中的所有“业务逻辑”和 “select 服务器” 是一样的，回调构成相同的代码。

这种相似是通过将事件循环抽象分离到一个库/框架中。我将会详述这些内容，因为很多优秀的程序员曾经也是这样做的。相反，下一篇文章里我们会了解 libuv，一个最近出现的更加受欢迎的时间循环抽象层。像 libuv 这样的库让我们能够写出并发的异步服务器，并且不用考虑系统调用下繁琐的细节。

---

* 注1：我试着在做网络浏览和阅读这两件事的实际差别中突显自己，但经常做得头疼。有很多不同的选项，从“它们是一样的东西”到“一个是另一个的子集”，再到“它们是完全不同的东西”。在面临这样主观的观点时，最好是完全放弃这个问题，专注特殊的例子和用例。
* 注2：POSIX 表示这可以是 `EAGAIN`，也可以是 `EWOULDBLOCK`，可移植应用应该对这两个都进行检查。
* 注3：和这个系列所有的 C 示例类似，代码中用到了某些助手工具来设置监听套接字。这些工具的完整代码在这个 [仓库](https://github.com/eliben/code-for-blog/blob/master/2017/async-socket-server/utils.h) 的 `utils` 模块里。
* 注4：`select` 不是网络/套接字专用的函数，它可以监视任意的文件描述符，有可能是硬盘文件、管道、终端、套接字或者 Unix 系统中用到的任何文件描述符。这篇文章里，我们主要关注它在套接字方面的应用。
* 注5：有多种方式用多线程来实现事件驱动，我会把它放在稍后的文章中进行讨论。
* 注6：由于各种非实验因素，它 *仍然* 可以阻塞，即使是在 `select` 说它就绪了之后。因此服务器上打开的所有套接字都被设置成非阻塞模式，如果对 `recv` 或 `send` 的调用返回了 `EAGAIN` 或者 `EWOULDBLOCK`，回调函数就装作没有事件发生。阅读示例代码的注释可以了解更多细节。
* 注7：注意这比该文章前面所讲的异步轮询的例子要稍好一点。轮询需要 *一直* 发生，而 `select` 实际上会阻塞到有一个或多个套接字准备好读取/写入；`select` 会比一直询问浪费少得多的 CPU 时间。

---

via: <https://eli.thegreenplace.net/2017/concurrent-servers-part-3-event-driven/>

作者：[Eli Bendersky](https://eli.thegreenplace.net/pages/about) 译者：[GitFuture](https://github.com/GitFuture) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何使用 GPG 加解密文件

![](/data/attachment/album/201712/06/235030pafawqxu58jl6yn6.jpg)

目标：使用 GPG 加密文件

发行版：适用于任何发行版

要求：安装了 GPG 的 Linux 或者拥有 root 权限来安装它。

难度：简单

约定：

* `#` - 需要使用 root 权限来执行指定命令，可以直接使用 root 用户来执行，也可以使用 `sudo` 命令
* `$` - 可以使用普通用户来执行指定命令

### 介绍

加密非常重要。它对于保护敏感信息来说是必不可少的。你的私人文件应该要被加密，而 GPG 提供了很好的解决方案。

### 安装 GPG

GPG 的使用非常广泛。你在几乎每个发行版的仓库中都能找到它。如果你还没有安装它，那现在就来安装一下吧。

**Debian/Ubuntu**

```
$ sudo apt install gnupg

```

**Fedora**

```
# dnf install gnupg2

```

**Arch**

```
# pacman -S gnupg

```

**Gentoo**

```
# emerge --ask app-crypt/gnupg

```

### 创建密钥

你需要一个密钥对来加解密文件。如果你为 SSH 已经生成过了密钥对，那么你可以直接使用它。如果没有，GPG 包含工具来生成密钥对。

```
$ gpg --full-generate-key

```

GPG 有一个命令行程序可以帮你一步一步的生成密钥。它还有一个简单得多的工具，但是这个工具不能让你设置密钥类型，密钥的长度以及过期时间，因此不推荐使用这个工具。

GPG 首先会询问你密钥的类型。没什么特别的话选择默认值就好。

下一步需要设置密钥长度。`4096` 是一个不错的选择。

之后，可以设置过期的日期。 如果希望密钥永不过期则设置为 `0`。

然后，输入你的名称。

最后，输入电子邮件地址。

如果你需要的话，还能添加一个注释。

所有这些都完成后，GPG 会让你校验一下这些信息。

GPG 还会问你是否需要为密钥设置密码。这一步是可选的， 但是会增加保护的程度。若需要设置密码，则 GPG 会收集你的操作信息来增加密钥的健壮性。 所有这些都完成后， GPG 会显示密钥相关的信息。

### 加密的基本方法

现在你拥有了自己的密钥，加密文件非常简单。 使用下面的命令在 `/tmp` 目录中创建一个空白文本文件。

```
$ touch /tmp/test.txt

```

然后用 GPG 来加密它。这里 `-e` 标志告诉 GPG 你想要加密文件， `-r` 标志指定接收者。

```
$ gpg -e -r "Your Name" /tmp/test.txt

```

GPG 需要知道这个文件的接收者和发送者。由于这个文件给是你的，因此无需指定发送者，而接收者就是你自己。

### 解密的基本方法

你收到加密文件后，就需要对它进行解密。 你无需指定解密用的密钥。 这个信息被编码在文件中。 GPG 会尝试用其中的密钥进行解密。

```
$ gpg -d /tmp/test.txt.gpg

```

### 发送文件

假设你需要发送文件给别人。你需要有接收者的公钥。 具体怎么获得密钥由你自己决定。 你可以让他们直接把公钥发送给你， 也可以通过密钥服务器来获取。

收到对方公钥后，导入公钥到 GPG 中。

```
$ gpg --import yourfriends.key

```

这些公钥与你自己创建的密钥一样，自带了名称和电子邮件地址的信息。 记住，为了让别人能解密你的文件，别人也需要你的公钥。 因此导出公钥并将之发送出去。

```
gpg --export -a "Your Name" > your.key

```

现在可以开始加密要发送的文件了。它跟之前的步骤差不多， 只是需要指定你自己为发送人。

```
$ gpg -e -u "Your Name" -r "Their Name" /tmp/test.txt

```

### 结语

就这样了。GPG 还有一些高级选项， 不过你在 99% 的时间内都不会用到这些高级选项。 GPG 就是这么易于使用。你也可以使用创建的密钥对来发送和接受加密邮件，其步骤跟上面演示的差不多， 不过大多数的电子邮件客户端在拥有密钥的情况下会自动帮你做这个动作。

---

via: <https://linuxconfig.org/how-to-encrypt-and-decrypt-individual-files-with-gpg>

作者：[Nick Congleton](https://linuxconfig.org) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux 中国](https://linux.cn/) 荣誉推出


Mark McIntyre：与 Fedora 的那些事

Summary: 最近我们采访了 Mark McIntyre，谈了他是如何使用 Fedora 系统的。这也是 Fedora 杂志上系列文章的一部分。该系列简要介绍了 Fedora 用户，以及他们是如何用 Fedora 把事情做好的。

![](/data/attachment/album/201712/07/093534f3fs7rbbr5lbu3q5.jpg)

最近我们采访了 Mark McIntyre，谈了他是如何使用 Fedora 系统的。这也是 Fedora 杂志上[系列文章的一部分](https://fedoramagazine.org/tag/how-do-you-fedora/)。该系列简要介绍了 Fedora 用户，以及他们是如何用 Fedora 把事情做好的。如果你想成为采访对象，请通过[反馈表](https://fedoramagazine.org/submit-an-idea-or-tip/)与我们联系。

### Mark McIntyre 是谁?

Mark McIntyre 为极客而生，以 Linux 为乐趣。他说：“我在 13 岁开始编程，当时自学 BASIC 语言，我体会到其中的乐趣，并在乐趣的引导下，一步步成为专业的码农。” Mark 和他的侄女都是披萨饼的死忠粉。“去年秋天，我和我的侄女开始了一个任务，去尝试诺克斯维尔的许多披萨饼连锁店。点击[这里](https://knox-pizza-quest.blogspot.com/)可以了解我们的进展情况。”Mark 也是一名业余的摄影爱好者，并且在 Flickr 上 [发布自己的作品](https://www.flickr.com/photos/mockgeek/)。

![](/data/attachment/album/201712/07/093534jo5455vg0069759u.jpg)

作为一名开发者，Mark 有着丰富的工作背景。他用过 Visual Basic 编写应用程序，用过 LotusScript、 PL/SQL（Oracle）、 Tcl/TK 编写代码，也用过基于 Python 的 Django 框架。他的强项是 Python。这也是目前他作为系统工程师的工作语言。“我经常使用 Python。由于我的工作变得更像是自动化工程师， Python 用得就更频繁了。”

McIntyre 自称是个书呆子，喜欢科幻电影，但他最喜欢的一部电影却不是科幻片。“尽管我是个书呆子，喜欢看《<ruby> 星际迷航 <rt>  Star Trek </rt></ruby>》、《<ruby> 星球大战 <rt>  Star Wars </rt></ruby>》之类的影片，但《<ruby> 光荣战役 <rt>  Glory </rt></ruby>》或许才是我最喜欢的电影。”他还提到，电影《<ruby> 冲出宁静号 <rt>  Serenity </rt></ruby>》是一个著名电视剧的精彩后续（指《萤火虫》）。

Mark 比较看重他人的谦逊、知识与和气。他欣赏能够设身处地为他人着想的人。“如果你决定为另一个人服务，那么你会选择自己愿意亲近的人，而不是让自己备受折磨的人。”

McIntyre 目前在 [Scripps Networks Interactive](http://www.scrippsnetworksinteractive.com/) 工作，这家公司是 HGTV、Food Network、Travel Channel、DIY、GAC 以及其他几个有线电视频道的母公司。“我现在是一名系统工程师，负责非线性视频内容，这是所有媒体要开展线上消费所需要的。”他为一些开发团队提供支持，他们编写应用程序，将线性视频从有线电视发布到线上平台，比如亚马逊、葫芦。这些系统既包含预置系统，也包含云系统。Mark 还开发了一些自动化工具，将这些应用程序主要部署到云基础结构中。

### Fedora 社区

Mark 形容 Fedora 社区是一个富有活力的社区，充满着像 Fedora 用户一样热爱生活的人。“从设计师到封包人，这个团体依然非常活跃，生机勃勃。” 他继续说道：“这使我对该操作系统抱有一种信心。”

2002 年左右，Mark 开始经常使用 IRC 上的 #fedora 频道：“那时候，Wi-Fi 在启用适配器和配置模块功能时，有许多还是靠手工实现的。”为了让他的 Wi-Fi 能够工作，他不得不重新去编译 Fedora 内核。

McIntyre 鼓励他人参与 Fedora 社区。“这里有许多来自不同领域的机会。前端设计、测试部署、开发、应用程序打包以及新技术实现。”他建议选择一个感兴趣的领域，然后向那个团体提出疑问。“这里有许多机会去奉献自己。”

对于帮助他起步的社区成员，Mark 赞道：“Ben Williams 非常乐于助人。在我第一次接触 Fedora 时，他帮我搞定了一些 #fedora 支持频道中的安装补丁。” Ben 也鼓励 Mark 去做 Fedora [大使](https://fedoraproject.org/wiki/Ambassadors)。

### 什么样的硬件和软件?

McIntyre 将 Fedora Linux 系统用在他的笔记本和台式机上。在服务器上他选择了 CentOS，因为它有更长的生命周期支持。他现在的台式机是自己组装的，配有 Intel 酷睿 i5 处理器，32GB 的内存和2TB 的硬盘。“我装了个 4K 的显示屏，有足够大的地方来同时查看所有的应用。”他目前工作用的笔记本是戴尔灵越二合一，配备 13 英寸的屏，16 GB 的内存和 525 GB 的 m.2 固态硬盘。

![](/data/attachment/album/201712/07/093535u7orwbnqwj7oeb66.png)

Mark 现在将 Fedora 26 运行在他过去几个月装配的所有机器中。当一个新版本正式发布的时候，他倾向于避开这个高峰期。“除非在它即将发行的时候，我的工作站中有个正在运行下一代测试版本，通常情况下，一旦它发展成熟，我都会试着去获取最新的版本。”他经常采取就地更新：“这种就地更新方法利用 dnf 系统升级插件，目前表现得非常好。”

为了搞摄影，McIntyre 用上了 [GIMP](https://www.gimp.org/)、[Darktable](http://www.darktable.org/)，以及其他一些照片查看包和快速编辑包。当不用 Web 电子邮件时，Mark 会使用 [Geary](https://wiki.gnome.org/Apps/Geary)，还有[GNOME Calendar](https://wiki.gnome.org/Apps/Calendar)。Mark 选用 HexChat 作为 IRC 客户端，[HexChat](https://hexchat.github.io/) 与在 Fedora 服务器实例上运行的 [ZNC bouncer](https://wiki.znc.in/ZNC) 联机。他的部门通过 Slave 进行沟通交流。

“我从来都不是 IDE 粉，所以大多数的编辑任务都是在 [vim](http://www.vim.org/) 上完成的。”Mark 偶尔也会打开一个简单的文本编辑器，如 [gedit](https://wiki.gnome.org/Apps/Gedit)，或者 [xed](https://github.com/linuxmint/xed)。他用 [GPaste](https://github.com/Keruspe/GPaste) 做复制和粘贴工作。“对于终端的选择，我已经变成 [Tilix](https://fedoramagazine.org/try-tilix-new-terminal-emulator-fedora/) 的忠粉。”McIntyre 通过 [Rhythmbox](https://wiki.gnome.org/Apps/Rhythmbox) 来管理他喜欢的播客，并用 [Epiphany](https://wiki.gnome.org/Apps/Web) 实现快速网络查询。

---

via: <https://fedoramagazine.org/mark-mcintyre-fedora/>

作者：[Charles Profitt](https://fedoramagazine.org/author/cprofitt/) 译者：[zrszrszrs](https://github.com/zrszrszrs) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出