2019年4月

欢迎进入输入课程系列。在本系列,你将会学会如何使用键盘接收输入给树莓派。我们将会从揭示输入开始本课,然后转向更传统的文本提示符。

这是第一堂输入课,会教授一些关于驱动和链接的理论,同样也包含键盘的知识,最后以在屏幕上显示文本结束。

1、开始

希望你已经完成了 OK 系列课程,这会对你完成屏幕系列课程很有帮助。很多 OK 课程上的文件会被使用而不会做解释。如果你没有这些文件,或者希望使用一个正确的实现,可以从该堂课的下载页下载模板。如果你使用你自己的实现,请删除调用了 SetGraphicsAddress 之后全部的代码。

2、USB

如你所知,树莓派 B 型有两个 USB 接口,通常用来连接一个鼠标和一个键盘。这是一个非常好的设计决策,USB 是一个非常通用的接口,很多种设备都可以使用它。这就很容易为它设计新外设,很容易为它编写设备驱动,而且通过 USB 集线器可以非常容易扩展。还能更好吗?当然是不能,实际上对一个操作系统开发者来说,这就是我们的噩梦。USB 标准太大了。我是说真的,在你思考如何连接设备之前,它的文档将近 700 页。

USB 标准的设计目的是通过复杂的软件来简化硬件交互。

我和很多爱好操作系统的开发者谈过这些,而他们全部都说几句话:不要抱怨。“实现这个需要花费很久时间”,“你不可能写出关于 USB 的教程”,“收益太小了”。在很多方面,他们是对的,我不可能写出一个关于 USB 标准的教程,那得花费几周时间。我同样不能教授如何为全部所有的设备编写外设驱动,所以使用自己写的驱动是没什么用的。然而,即便不能做到最好,我仍然可以获取一个正常工作的 USB 驱动,拿一个键盘驱动,然后教授如何在操作系统中使用它们。我开始寻找可以运行在一个甚至不知道文件是什么的操作系统的自由驱动,但是我一个都找不到,它们都太高层了,所以我尝试写一个。大家说的都对,这耗费了我几周时间。然而我可以高兴的说我做的这些工作没有获取操作系统以外的帮助,并且可以和鼠标和键盘通信。这绝不是完整的、高效的,或者正确的,但是它能工作。驱动是以 C 编写的,而且有兴趣的可以在下载页找到全部源代码。

所以,这一个教程不会是 USB 标准的课程(一点也没有)。实际上我们将会看到如何使用其他人的代码。

3、链接

既然我们要引进外部代码到操作系统,我们就需要谈一谈 链接 linking 。链接是一种过程,可以在程序或者操作系统中链接函数。这意味着当一个程序生成之后,我们不必要编写每一个函数(几乎可以肯定,实际上并非如此)。链接就是我们做的用来把我们程序和别人代码中的函数连结在一起。这个实际上已经在我们的操作系统进行了,因为链接器把所有不同的文件链接在一起,每个都是分开编译的。

链接允许我们制作可重用的代码库,所有人都可以在他们的程序中使用。

有两种链接方式:静态和动态。静态链接就像我们在制作自己的操作系统时进行的。链接器找到全部函数的地址,然后在链接结束前,将这些地址都写入代码中。动态链接是在程序“完成”之后。当程序加载后,动态链接器检查程序,然后在操作系统的库找到所有不在程序里的函数。这就是我们的操作系统最终应该能够完成的一项工作,但是现在所有东西都将是静态链接的。

程序经常调用调用库,这些库会调用其它的库,直到最终调用了我们写的操作系统的库。

我编写的 USB 驱动程序适合静态编译。这意味着我给你的是每个文件的编译后的代码,然后链接器找到你的代码中的那些没有实现的函数,就将这些函数链接到我的代码。在本课的 下载页 是一个 makefile 和我的 USB 驱动,这是接下来需要的。下载并使用这个 makefile 替换你的代码中的 makefile, 同事将驱动放在和这个 makefile 相同的文件夹。

4、键盘

为了将输入传给我们的操作系统,我们需要在某种程度上理解键盘是如何实际工作的。键盘有两种按键:普通键和修饰键。普通按键是字母、数字、功能键,等等。它们构成了键盘上几乎全部按键。修饰键是多达 8 个的特殊键。它们是左 shift、右 shift、左 ctrl、右 ctrl、左 alt、右 alt、左 GUI 和右 GUI。键盘可以检测出所有的组合中那个修饰键被按下了,以及最多 6 个普通键。每次一个按钮变化了(例如,是按下了还是释放了),键盘就会报告给电脑。通常,键盘也会有 3 个 LED 灯,分别指示大写锁定,数字键锁定,和滚动锁定,这些都是由电脑控制的,而不是键盘自己。键盘也可能有更多的灯,比如电源、静音,等等。

对于标准 USB 键盘,有一个按键值的表,每个键盘按键都一个唯一的数字,每个可能的 LED 也类似。下面的表格列出了前 126 个值。

表 4.1 USB 键盘值

序号描述序号描述序号描述序号描述
4aA5bB6cC7dD
8eE9fF10gG11hH
12iI13jJ14kK15lL
16mM17nN18oO19pP
20qQ21rR22sS23tT
24uU25vV26wW27xX
28yY29zZ301!312@
323#334$345%356^
367&378*389(390)
40ReturnEnter41Escape42DeleteBackspace43Tab
44Spacebar45-_46=+47[{
48]}49\ 和 ``50#~51;:
52'"53`~54,<55.>
56/?57Caps Lock58F159F2
60F361F462F563F6
64F765F866F967F10
68F1169F1270Print Screen71Scroll Lock
72Pause73Insert74Home75Page Up
76Delete forward77End78Page Down79Right Arrow
80Left Arrow81Down Arrow82Up Arrow83Num Lock
84小键盘 /85小键盘 *86小键盘 -87小键盘 +
88小键盘 Enter89小键盘 1End90小键盘 2Down Arrow91小键盘 3Page Down
92小键盘 4Left Arrow93小键盘 594小键盘 6Right Arrow95小键盘 7Home
96小键盘 8Up Arrow97小键盘 9Page Up98小键盘 0Insert99小键盘 .Delete
100\ 和 ``101Application102Power103小键盘 =
104F13105F14106F15107F16
108F17109F18110F19111F20
112F21113F22114F23115F24
116Execute117Help118Menu119Select
120Stop121Again122Undo123Cut
124Copy125Paste126Find127Mute
128Volume Up129Volume Down

完全列表可以在HID 页表 1.12的 53 页,第 10 节找到。

5、车轮后的螺母

通常,当你使用其他人的代码,他们会提供一份自己代码的总结,描述代码都做了什么,粗略介绍了是如何工作的,以及什么情况下会出错。下面是一个使用我的 USB 驱动的相关步骤要求。

这些总结和代码的描述组成了一个 API - 应用程序产品接口。

表 5.1 CSUD 中和键盘相关的函数

函数参数返回值描述
UsbInitialiser0 是结果码这个方法是一个集多种功能于一身的方法,它加载 USB 驱动程序,枚举所有设备并尝试与它们通信。这种方法通常需要大约一秒钟的时间来执行,但是如果插入几个 USB 集线器,执行时间会明显更长。在此方法完成之后,键盘驱动程序中的方法就可用了,不管是否确实插入了键盘。返回代码如下解释。
UsbCheckForChange本质上提供与 UsbInitialise 相同的效果,但不提供相同的一次初始化。该方法递归地检查每个连接的集线器上的每个端口,如果已经添加了新设备,则添加它们。如果没有更改,这应该是非常快的,但是如果连接了多个设备的集线器,则可能需要几秒钟的时间。
KeyboardCountr0 是计数返回当前连接并检测到的键盘数量。UsbCheckForChange 可能会对此进行更新。默认情况下最多支持 4 个键盘。可以通过这个驱动程序访问多达这么多的键盘。
KeyboardGetAddressr0 是索引r0 是地址检索给定键盘的地址。所有其他函数都需要一个键盘地址,以便知道要访问哪个键盘。因此,要与键盘通信,首先要检查计数,然后检索地址,然后使用其他方法。注意,在调用 UsbCheckForChange 之后,此方法返回的键盘顺序可能会改变。
KeyboardPollr0 是地址r0 是结果码从键盘读取当前键状态。这是通过直接轮询设备来操作的,与最佳实践相反。这意味着,如果没有频繁地调用此方法,可能会错过一个按键。所有读取方法只返回上次轮询时的值。
KeyboardGetModifiersr0 是地址r0 是修饰键状态检索上次轮询时修饰键的状态。这是两边的 shift 键、alt 键和 GUI 键。这回作为一个位字段返回,这样,位 0 中的 1 表示左控件被保留,位 1 表示左 shift,位 2 表示左 alt ,位 3 表示左 GUI,位 4 到 7 表示前面几个键的右版本。如果有问题,r0 包含 0。
KeyboardGetKeyDownCountr0 是地址r0 是计数检索当前按下键盘的键数。这排除了修饰键。这通常不能超过 6。如果有错误,这个方法返回 0。
KeyboardGetKeyDownr0 是地址,r1 键号r0 是扫描码检索特定按下键的扫描码(见表 4.1)。通常,要计算出哪些键是按下的,可以调用 KeyboardGetKeyDownCount,然后多次调用 KeyboardGetKeyDown ,将 r1 的值递增,以确定哪些键是按下的。如果有问题,返回 0。可以(但不建议这样做)在不调用 KeyboardGetKeyDownCount 的情况下调用此方法将 0 解释为没有按下的键。注意,顺序或扫描代码可以随机更改(有些键盘按数字排序,有些键盘按时间排序,没有任何保证)。
KeyboardGetKeyIsDownr0 是地址,r1 扫描码r0 是状态除了 KeyboardGetKeyDown 之外,还可以检查按下的键中是否有特定的扫描码。如果没有,返回 0;如果有,返回一个非零值。当检测特定的扫描码(例如寻找 ctrl+c)时更快。出错时,返回 0。
KeyboardGetLedSupportr0 是地址r0 是 LED检查特定键盘支持哪些 LED。第 0 位代表数字锁定,第 1 位代表大写锁定,第 2 位代表滚动锁定,第 3 位代表合成,第 4 位代表假名,第 5 位代表电源,第 6 位代表 Shift ,第 7 位代表静音。根据 USB 标准,这些 LED 都不是自动更新的(例如,当检测到大写锁定扫描代码时,必须手动设置大写锁定 LED)。
KeyboardSetLedsr0 是地址, r1 是 LEDr0 是结果码试图打开/关闭键盘上指定的 LED 灯。查看下面的结果代码值。参见 KeyboardGetLedSupport 获取 LED 的值。

有几种方法返回“返回值”。这些都是 C 代码的老生常谈了,就是用数字代表函数调用发生了什么。通常情况, 0 总是代表操作成功。下面的是驱动用到的返回值。

返回值是一种处理错误的简单方法,但是通常更优雅的解决途径会出现于更高层次的代码。

表 5.2 - CSUD 返回值

代码描述
0方法成功完成。
-2参数:函数调用了无效参数。
-4设备:设备没有正确响应请求。
-5不匹配:驱动不适用于这个请求或者设备。
-6编译器:驱动没有正确编译,或者被破坏了。
-7内存:驱动用尽了内存。
-8超时:设备没有在预期的时间内响应请求。
-9断开连接:被请求的设备断开连接,或者不能使用。

驱动的通常用法如下:

  1. 调用 UsbInitialise
  2. 调用 UsbCheckForChange
  3. 调用 KeyboardCount
  4. 如果返回 0,重复步骤 2。
  5. 针对你支持的每个键盘:

    1. 调用 KeyboardGetAddress
    2. 调用 KeybordGetKeyDownCount
    3. 针对每个按下的按键:

      1. 检查它是否已经被按下了
      2. 保存按下的按键
    4. 针对每个保存的按键:

      1. 检查按键是否被释放了
      2. 如果释放了就删除
  6. 根据按下/释放的案件执行操作
  7. 重复步骤 2

最后,你可以对键盘做所有你想做的任何事了,而这些方法应该允许你访问键盘的全部功能。在接下来的两节课,我们将会着眼于完成文本终端的输入部分,类似于大部分的命令行电脑,以及命令的解释。为了做这些,我们将需要在更有用的形式下得到一个键盘输入。你可能注意到我的驱动是(故意的)没有太大帮助,因为它并没有方法来判断是否一个按键刚刚按下或释放了,它只有方法来判断当前那个按键是按下的。这就意味着我们需要自己编写这些方法。

6、可用更新

首先,让我们实现一个 KeyboardUpdate 方法,检查第一个键盘,并使用轮询方法来获取当前的输入,以及保存最后一个输入来对比。然后我们可以使用这个数据和其它方法来将扫描码转换成按键。这个方法应该按照下面的说明准确操作:

重复检查更新被称为“轮询”。这是针对驱动 IO 中断而言的,这种情况下设备在准备好后会发一个信号。
  1. 提取一个保存好的键盘地址(初始值为 0)。
  2. 如果不是 0 ,进入步骤 9.
  3. 调用 UsbCheckForChange 检测新键盘。
  4. 调用 KeyboardCount 检测有几个键盘在线。
  5. 如果返回 0,意味着没有键盘可以让我们操作,只能退出了。
  6. 调用 KeyboardGetAddress 参数是 0,获取第一个键盘的地址。
  7. 保存这个地址。
  8. 如果这个值是 0,那么退出,这里应该有些问题。
  9. 调用 KeyboardGetKeyDown 6 次,获取每次按键按下的值并保存。
  10. 调用 KeyboardPoll
  11. 如果返回值非 0,进入步骤 3。这里应该有些问题(比如键盘断开连接)。

要保存上面提到的值,我们将需要下面 .data 段的值。

.section .data
.align 2
KeyboardAddress:
.int 0
KeyboardOldDown:
.rept 6
.hword 0
.endr
.hword num 直接将半字的常数插入文件。
.rept num [commands] .endr 复制 `commands` 命令到输出 num 次。

试着自己实现这个方法。对此,我的实现如下:

1、我们加载键盘的地址。

.section .text
.globl KeyboardUpdate
KeyboardUpdate:
push {r4,r5,lr}

kbd .req r4
ldr r0,=KeyboardAddress
ldr kbd,[r0]

2、如果地址非 0,就说明我们有一个键盘。调用 UsbCheckForChanges 慢,所以如果一切正常,我们要避免调用这个函数。

teq kbd,#0
bne haveKeyboard$

3、如果我们一个键盘都没有,我们就必须检查新设备。

getKeyboard$:
bl UsbCheckForChange

4、如果有新键盘添加,我们就会看到这个。

bl KeyboardCount

5、如果没有键盘,我们就没有键盘地址。

teq r0,#0
ldreq r1,=KeyboardAddress
streq r0,[r1]
beq return$

6、让我们获取第一个键盘的地址。你可能想要支持更多键盘。

mov r0,#0
bl KeyboardGetAddress

7、保存键盘地址。

ldr r1,=KeyboardAddress
str r0,[r1]

8、如果我们没有键盘地址,这里就没有其它活要做了。

teq r0,#0
beq return$
mov kbd,r0

9、循环查询全部按键,在 KeyboardOldDown 保存下来。如果我们询问的太多了,返回 0 也是正确的。

saveKeys$:
  mov r0,kbd
  mov r1,r5
  bl KeyboardGetKeyDown
  
  ldr r1,=KeyboardOldDown
  add r1,r5,lsl #1
  strh r0,[r1]
  add r5,#1
  cmp r5,#6
  blt saveKeys$

10、现在我们得到了新的按键。

mov r0,kbd
bl KeyboardPoll

11、最后我们要检查 KeyboardOldDown 是否工作了。如果没工作,那么我们可能是断开连接了。

teq r0,#0
bne getKeyboard$

return$:
pop {r4,r5,pc}
.unreq kbd

有了我们新的 KeyboardUpdate 方法,检查输入变得简单,固定周期调用这个方法就行,而它甚至可以检查键盘是否断开连接,等等。这是一个有用的方法,因为我们实际的按键处理会根据条件不同而有所差别,所以能够用一个函数调以它的原始方式获取当前的输入是可行的。下一个方法我们希望它是 KeyboardGetChar,简单的返回下一个按下的按钮的 ASCII 字符,或者如果没有按键按下就返回 0。这可以扩展到支持如果它按下一个特定时间当做多次按下按键,也支持锁定键和修饰键。

如果我们有一个 KeyWasDown 方法可以使这个方法有用起来,如果给定的扫描代码不在 KeyboardOldDown 值中,它只返回 0,否则返回一个非零值。你可以自己尝试一下。与往常一样,可以在下载页面找到解决方案。

7、查找表

KeyboardGetChar 方法如果写得不好,可能会非常复杂。有 100 多种扫描码,每种代码都有不同的效果,这取决于 shift 键或其他修饰符的存在与否。并不是所有的键都可以转换成一个字符。对于一些字符,多个键可以生成相同的字符。在有如此多可能性的情况下,一个有用的技巧是查找表。查找表与物理意义上的查找表非常相似,它是一个值及其结果的表。对于一些有限的函数,推导出答案的最简单方法就是预先计算每个答案,然后通过检索返回正确的答案。在这种情况下,我们可以在内存中建立一个序列的值,序列中第 n 个值就是扫描代码 n 的 ASCII 字符代码。这意味着如果一个键被按下,我们的方法只需要检测到,然后从表中检索它的值。此外,我们可以为当按住 shift 键时的值单独创建一个表,这样按下 shift 键就可以简单地换个我们用的表。

在编程的许多领域,程序越大,速度越快。查找表很大,但是速度很快。有些问题可以通过查找表和普通函数的组合来解决。

.section .data 命令之后,复制下面的表:

.align 3
KeysNormal:
    .byte 0x0, 0x0, 0x0, 0x0, 'a', 'b', 'c', 'd'
    .byte 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'
    .byte 'm', 'n', 'o', 'p', 'q', 'r', 's', 't'
    .byte 'u', 'v', 'w', 'x', 'y', 'z', '1', '2'
    .byte '3', '4', '5', '6', '7', '8', '9', '0'
    .byte '\n', 0x0, '\b', '\t', ' ', '-', '=', '['
    .byte ']', '\\\', '#', ';', '\'', '`', ',', '.'
    .byte '/', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
    .byte '\n', '1', '2', '3', '4', '5', '6', '7'
    .byte '8', '9', '0', '.', '\\\', 0x0, 0x0, '='

.align 3
KeysShift:
    .byte 0x0, 0x0, 0x0, 0x0, 'A', 'B', 'C', 'D'
    .byte 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'
    .byte 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'
    .byte 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '"'
    .byte '£', '$', '%', '^', '&', '*', '(', ')'
    .byte '\n', 0x0, '\b', '\t', ' ', '_', '+', '{'
    .byte '}', '|', '~', ':', '@', '¬', '<', '>'
    .byte '?', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    .byte 0x0, 0x0, 0x0, 0x0, '/', '*', '-', '+'
    .byte '\n', '1', '2', '3', '4', '5', '6', '7'
    .byte '8', '9', '0', '.', '|', 0x0, 0x0, '='

这些表直接将前 104 个扫描码映射到 ASCII 字符作为一个字节表。我们还有一个单独的表来描述 shift 键对这些扫描码的影响。我使用 ASCII null 字符(0)表示所有没有直接映射的 ASCII 键(例如功能键)。退格映射到 ASCII 退格字符(8 表示 \b),enter 映射到 ASCII 新行字符(10 表示 \n), tab 映射到 ASCII 水平制表符(9 表示 \t)。

.byte num 直接插入字节常量 num 到文件。

.

大部分的汇编器和编译器识别转义序列;如 \t 这样的字符序列会插入该特殊字符。

KeyboardGetChar 方法需要做以下工作:

  1. 检查 KeyboardAddress 是否返回 0。如果是,则返回 0。
  2. 调用 KeyboardGetKeyDown 最多 6 次。每次:

    1. 如果按键是 0,跳出循环。
    2. 调用 KeyWasDown。 如果返回是,处理下一个按键。
    3. 如果扫描码超过 103,进入下一个按键。
    4. 调用 KeyboardGetModifiers
    5. 如果 shift 是被按着的,就加载 KeysShift 的地址,否则加载 KeysNormal 的地址。
    6. 从表中读出 ASCII 码值。
    7. 如果是 0,进行下一个按键,否则返回 ASCII 码值并退出。
  3. 返回 0。

试着自己实现。我的实现展示在下面:

1、简单的检查我们是否有键盘。

.globl KeyboardGetChar
KeyboardGetChar:
ldr r0,=KeyboardAddress
ldr r1,[r0]
teq r1,#0
moveq r0,#0
moveq pc,lr

2、r5 将会保存按键的索引,r4 保存键盘的地址。

push {r4,r5,r6,lr}
kbd .req r4
key .req r6
mov r4,r1
mov r5,#0
keyLoop$:
  mov r0,kbd
  mov r1,r5
  bl KeyboardGetKeyDown

2.1、 如果扫描码是 0,它要么意味着有错,要么说明没有更多按键了。

teq r0,#0
beq keyLoopBreak$

2.2、如果按键已经按下了,那么他就没意义了,我们只想知道按下的按键。

mov key,r0
bl KeyWasDown
teq r0,#0
bne keyLoopContinue$

2.3、如果一个按键有个超过 104 的扫描码,它将会超出我们的表,所以它是无关的按键。

cmp key,#104
bge keyLoopContinue$

2.4、我们需要知道修饰键来推断字符。

mov r0,kbd
bl KeyboardGetModifiers

2.5、当将字符更改为其 shift 变体时,我们要同时检测左 shift 键和右 shift 键。记住,tst 指令计算的是逻辑和,然后将其与 0 进行比较,所以当且仅当移位位都为 0 时,它才等于 0。

tst r0,#0b00100010
ldreq r0,=KeysNormal
ldrne r0,=KeysShift

2.6、现在我们可以从查找表加载按键了。

ldrb r0,[r0,key]

2.7、如果查找码包含一个 0,我们必须继续。为了继续,我们要增加索引,并检查是否到 6 次了。

teq r0,#0
bne keyboardGetCharReturn$
keyLoopContinue$:
add r5,#1
cmp r5,#6
blt keyLoop$

3、在这里我们返回我们的按键,如果我们到达 keyLoopBreak$ ,然后我们就知道这里没有按键被握住,所以返回 0。

keyLoopBreak$:
mov r0,#0
keyboardGetCharReturn$:
pop {r4,r5,r6,pc}
.unreq kbd
.unreq key

8、记事本操作系统

现在我们有了 KeyboardGetChar 方法,可以创建一个操作系统,只打印出用户对着屏幕所写的内容。为了简单起见,我们将忽略所有非常规的键。在 main.s,删除 bl SetGraphicsAddress 之后的所有代码。调用 UsbInitialise,将 r4r5 设置为 0,然后循环执行以下命令:

  1. 调用 KeyboardUpdate
  2. 调用 KeyboardGetChar
  3. 如果返回 0,跳转到步骤 1
  4. 复制 r4r5r1r2 ,然后调用 DrawCharacter
  5. r0 加到 r4
  6. 如果 r4 是 1024,将 r1 加到 r5,然后设置 r4 为 0。
  7. 如果 r5 是 768,设置 r5 为0
  8. 跳转到步骤 1

现在编译,然后在树莓派上测试。你几乎可以立即开始在屏幕上输入文本。如果没有工作,请参阅我们的故障排除页面。

当它工作时,祝贺你,你已经实现了与计算机的接口。现在你应该开始意识到,你几乎已经拥有了一个原始的操作系统。现在,你可以与计算机交互、发出命令,并在屏幕上接收反馈。在下一篇教程输入02中,我们将研究如何生成一个全文本终端,用户在其中输入命令,然后计算机执行这些命令。


via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input01.html

作者:Alex Chadwick 选题:lujun9972 译者:ezio 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这是一个很重要的话题,不仅对 Linux 管理员而言,对于我们大家而言也非常有帮助。我的意思是说对于工作在 IT 基础设施行业的用户来说,了解这个话题也是非常有用的。他们需要在执行下一步操作前,检查 Linux 服务器上某个端口是否开启。

假如这个端口没有被开启,则他们会直接找 Linux 管理员去开启它。如果这个端口已经开启了,则我们需要和应用团队来商量下一步要做的事。

在本篇文章中,我们将向你展示如何检查某个端口是否开启的 3 种方法。

这个目标可以使用下面的 Linux 命令来达成:

  • nc:netcat 是一个简单的 Unix 工具,它使用 TCP 或 UDP 协议去读写网络连接间的数据。
  • nmap:(“Network Mapper”)是一个用于网络探索和安全审计的开源工具,被设计用来快速地扫描大规模网络。
  • telnet:被用来交互地通过 TELNET 协议与另一台主机通信。

如何使用 nc(netcat)命令来查看远程 Linux 系统中某个端口是否开启?

ncnetcatnetcat 是一个简单的 Unix 工具,它使用 TCP 或 UDP 协议去读写网络连接间的数据。

它被设计成为一个可信赖的后端工具,可被直接使用或者简单地被其他程序或脚本调用。

与此同时,它也是一个富含功能的网络调试和探索工具,因为它可以创建你所需的几乎所有类型的连接,并且还拥有几个内置的有趣功能。

netcat 有三类功能模式,它们分别为连接模式、监听模式和隧道模式。

ncnetcat)命令的一般语法:

$ nc [-options] [HostName or IP] [PortNumber]

在下面的例子中,我们将检查远程 Linux 系统中的 22 端口是否开启。

假如端口是开启的,你将获得类似下面的输出。

# nc -zvw3 192.168.1.8 22
Connection to 192.168.1.8 22 port [tcp/ssh] succeeded!

命令详解:

  • nc:即执行的命令主体;
  • z:零 I/O 模式(被用来扫描);
  • v:显式地输出;
  • w3:设置超时时间为 3 秒;
  • 192.168.1.8:目标系统的 IP 地址;
  • 22:需要验证的端口。

当检测到端口没有开启,你将获得如下输出:

# nc -zvw3 192.168.1.95 22
nc: connect to 192.168.1.95 port 22 (tcp) failed: Connection refused

如何使用 nmap 命令来查看远程 Linux 系统中某个端口是否开启?

nmap(“Network Mapper”)是一个用于网络探索和安全审计的开源工具,被设计用来快速地扫描大规模网络,尽管对于单个主机它也同样能够正常工作。

nmap 以一种新颖的方式,使用裸 IP 包来决定网络中的主机是否可达,这些主机正提供什么服务(应用名和版本号),它们运行的操作系统(系统的版本),它们正在使用的是什么包过滤软件或者防火墙,以及其他额外的特性。

尽管 nmap 通常被用于安全审计,许多系统和网络管理员发现在一些日常任务(例如罗列网络资产、管理服务升级的计划、监视主机或者服务是否正常运行)中,它也同样十分有用。

nmap 的一般语法:

$ nmap [-options] [HostName or IP] [-p] [PortNumber]

假如端口是开启的,你将获得如下的输出:

# nmap 192.168.1.8 -p 22

Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-16 03:37 IST Nmap scan report for 192.168.1.8 Host is up (0.00031s latency).

PORT STATE SERVICE

22/tcp open ssh 

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

假如端口没有开启,你将得到类似下面的结果:

# nmap 192.168.1.8 -p 80
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-16 04:30 IST
Nmap scan report for 192.168.1.8
Host is up (0.00036s latency).

PORT   STATE  SERVICE
80/tcp closed http

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

如何使用 telnet 命令来查看远程 Linux 系统中某个端口是否开启?

telnet 命令被用来交互地通过 TELNET 协议与另一台主机通信。

telnet 命令的一般语法:

$ telnet [HostName or IP] [PortNumber]

假如探测成功,你将看到类似下面的输出:

$ telnet 192.168.1.9 22
Trying 192.168.1.9...
Connected to 192.168.1.9.
Escape character is '^]'.
SSH-2.0-OpenSSH_5.3
^]
Connection closed by foreign host.

假如探测失败,你将看到类似下面的输出:

$ telnet 192.168.1.9 80
Trying 192.168.1.9...
telnet: Unable to connect to remote host: Connection refused

当前,我们只找到上面 3 种方法来查看远程 Linux 系统中某个端口是否开启,假如你发现了其他方法可以达到相同的目的,请在下面的评论框中告知我们。


via: https://www.2daygeek.com/how-to-check-whether-a-port-is-open-on-the-remote-linux-system-server/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:FSSlc 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

如果你输入 dig 命令对 google.com 进行 DNS 查询,你会得到如下答复:

$ dig google.com

; <<>> DiG 9.10.6 <<>> google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27120
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
google.com.     194 IN  A   216.58.192.206

;; Query time: 23 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Sep 21 16:14:48 CDT 2018
;; MSG SIZE rcvd: 55

这个输出一部分描述了你的问题(google.com 的 IP 地址是什么?),另一部分则详细描述了你收到的回答。在 答案区段 ANSWER SECTION 里,dig 为我们找到了一个包含五个字段的记录。从左数第四个字段 A 定义了这个记录的类型 —— 这是一个地址记录。在 A 的右边,第五个字段告知我们 google.com 的 IP 地址是 216.58.192.206。第二个字段,194 则代表这个记录的缓存时间是 194 秒。

那么,IN 字段告诉了我们什么呢?令人尴尬的是,在很长的一段时间里,我都认为这是一个介词。那时候我认为 DNS 记录大概是表达了“在 A 记录里,google.com 的 IP 地址是 216.58.192.206。”后来我才知道 IN 是 “internet” 的简写。IN 这一个部分告诉了我们这个记录分属的 类别 class

那么,除了 “internet” 之外,DNS 记录还会有什么别的类别吗?这究竟意味着什么?你怎么去搜寻一个不位于 internet 上的地址?看起来 IN 是唯一一个可能有意义的值。而且的确,如果你尝试去获得除了 IN 之外的,关于 google.com 的记录的话,DNS 服务器通常不能给出恰当的回应。以下就是我们尝试向 8.8.8.8(谷歌公共 DNS 服务器)询问在 HS 类别里 google.com 的 IP 地址。我们得到了状态为 SERVFAIL 的回复。

$ dig -c HS google.com

; <<>> DiG 9.10.6 <<>> -c HS google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 31517
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;google.com.            HS  A

;; Query time: 34 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Tue Sep 25 14:48:10 CDT 2018
;; MSG SIZE rcvd: 39

所以说,除了 IN 以外的类别没有得到广泛支持,但它们的确是存在的。除了 IN 之外,DNS 记录还有 HS(我们刚刚看到的)和 CH 这两个类别。HS 类是为一个叫做 Hesiod) 的系统预留的,它可以利用 DNS 来存储并让用户访问一些文本资料。它通常在本地环境中作为 LDAP 的替代品使用。而 CH 这个类别,则是为 Chaosnet 预留的。

如今,大家都在使用 TCP/IP 协议族。这两种协议(TCP 及 UDP)是绝大部分电脑远程连接采用的协议。不过我觉得,从互联网的垃圾堆里翻出了一个布满灰尘,绝迹已久,被人们遗忘的系统,也是一件令人愉悦的事情。那么,Chaosnet 是什么?为什么它像恐龙一样,走上了毁灭的道路呢?

在 MIT 的机房里

Chaosnet 是在 1970 年代,由 MIT 人工智能实验室的研究员们研发的。它是一个宏伟目标的一部分 —— 设计并制造一个能比其他通用电脑更高效率运行 Lisp 代码的机器。

Lisp 是 MIT 教授 John McCarthy 的造物,他亦是人工智能领域的先驱者。在 1960 年发布的一篇论文中,他首次描述了 Lisp 这个语言。在 1962 年,Lisp 的编译器和解释器诞生了。Lisp 引入了非常多的新特性,这些特性在现在看来是每一门编程语言不可或缺的一部分。它是第一门拥有垃圾回收器的语言,是第一个有 REPL(Read-eval-print-loop:交互式解析器)的语言,也是第一个支持动态类型的语言。在人工智能领域工作的程序员们都十分喜爱这门语言,比如说,大名鼎鼎的 SHRDLU 就是用它写的。这个程序允许人们使用自然语言,向机器下达挪动玩具方块这样的命令。

Lisp 的缺点是它太慢了。跟其它语言相比,Lisp 需要使用两倍的时间来执行相同的操作。因为 Lisp 在运行中仍会检查变量类型,而不仅是编译过程中。在 MIT 的 IBM 7090 上,它的垃圾回收器也需要长达一秒钟的时间来执行。 1 这个性能问题急需解决,因为 AI 研究者们试图搭建类似 SHRDLU 的应用。他们需要程序与使用者进行实时互动。因此,在 1970 年代的晚期,MIT 人工智能实验室的研究员们决定去建造一个能更高效运行 Lisp 的机器来解决这个问题。这些“Lisp 机器”们拥有更大的存储和更精简的指令集,更加适合 Lisp。类型检查由专门的电路完成,因此在 Lisp 运行速度的提升上达成了质的飞跃。跟那时流行的计算机系统不同,这些机器并不支持分时,整台电脑的资源都用来运行一个单独的 Lisp 程序。每一个用户都会得到他自己单独的 CPU。MIT 的 Lisp 机器小组 Lisp Machine Group 在一个备忘录里提到,这些功能是如何让 Lisp 运行变得更简单的:

Lisp 机器是个人电脑。这意味着处理器和主内存并不是分时复用的,每个人都能得到单独属于自己的处理器和内存。这个个人运算系统由许多处理器组成,每个处理器都有它们自己的内存和虚拟内存。当一个用户登录时,他就会被分配一个处理器,在他的登录期间这个处理器是独属于他的。当他登出,这个处理器就会重新可用,等待被分配给下一个用户。通过采取这种方法,当前用户就不用和其他用户竞争内存的使用,他经常使用的内存页也能保存在处理器核心里,因此页面换出的情况被显著降低了。这个 Lisp 机器解决了分时 Lisp 机器的一个基本问题。 2

这个 Lisp 机器跟我们认知的现代个人电脑有很大的不同。该小组原本希望今后用户不用直接面对 Lisp 机器,而是面对终端。那些终端会与位于别处的 Lisp 机器进行连接。虽然每个用户都有自己专属的处理器,但那些处理器在工作时会发出很大的噪音,因此它们最好是位于机房,而不是放在本应安静的办公室里。 3 这些处理器会通过一个“完全分布式控制”的高速本地网络共享访问一个文件系统和设备,例如打印机。 4 这个网络的名字就是 Chaosnet。

Chaosnet 既是硬件标准也是软件协议。它的硬件标准与以太网类似,事实上 Chaosnet 软件协议是运行在以太网之上的。这个软件协议在网络层和传输层之间交互,它并不像 TCP/IP,而总是控制着本地网络。Lisp 机器小组的一个成员 David Moon 写的另一个备忘录中提到,Chaosnet “目前并不打算为低速链接、高信噪链接、多路径、长距离链接做特别的优化。” 5 他们专注于打造一个在小型网络里表现极佳的协议。

因为 Chaosnet 连接在 Lisp 处理器和文件系统之间,所以速度十分重要。网络延迟会严重拖慢一些像打开文本文档这种简单操作的速度,为了提高速度,Chaosnet 结合了在 Network Control Program网络控制程序中使用的一些改进方法,随后的 Arpanet 项目中也使用了这些方法。据 Moon 所说,“为了突破诸如在 Arpanet 中发现的速率瓶颈,很有必要采纳新的设计。目前来看,瓶颈在于由多个链接分享控制链接,而且在下一个信息发送之前,我们需要知道本次信息已经送达。” 6 Chaosnet 协议族的批量 ACK 包跟当今 TCP 的差不多,它减少了 1/3 到一半的需要传输的包的数量。

因为绝大多数 Lisp 机器使用较短的单线进行连接,所以 Chaosnet 可以使用较为简单的路由算法。Moon 在 Chaosnet 路由方案中写道“预计要适配的网络架构十分简单,很少有多个路径,而且每个节点之间的距离很短。所以我认为没有必要进行复杂的方案设计。” 7 因为 Chaosnet 采用的算法十分简单,所以实现它也很容易。与之对比明显,其实现程序据说只有 Arpanet 网络控制程序的一半。 8

Chaosnet 的另一个特性是,它的地址只有 16 位,是 IPv4 地址的一半。所以这也意味着 Chaosnet 只能在局域网里工作。Chaosnet 也不会去使用端口号;当一个进程试图连接另一个机器上的另外一个进程时,需要首先初始化连接,获取一个特定的目标“ 联系名称 contact name ”。这个联系名称一般是某个特定服务的名字。比方说,一个主机试图使用 TELNET 作为联系名称,连接另一个主机。我认为它的工作方式在实践中有点类似于 TCP,因为有些非常著名的服务也会拥有联系名称,比如运行在 80 端口上的 HTTP 服务。

在 1986 年,RFC 973 通过了将 Chaosnet DNS 类别加入域名解析系统的决议。它替代了一个早先出现的类别 CSNETCSNET 是为了支持一个名叫 计算机科学网络 Computer Science Network 而被制造出来的协议。我并不知道为什么 Chaosnet 能被域名解析系统另眼相待。很多别的协议族也有资格加入 DNS,但是却被忽略了。比如 DNS 的主要架构师之一 Paul Mockapetris 提到说在他原本的构想里, 施乐 Xerox 的网络协议应该被包括在 DNS 里。 9 但是它并没有被加入。Chaosnet 被加入的原因大概是因为 Arpanet 项目和互联网的早期工作,有很多都在麻省剑桥的博尔特·贝拉尼克—纽曼公司,他们的雇员和 MIT 大多有紧密的联系。在这一小撮致力于发展计算机网络人中,Chaosnet 这个协议应该较为有名。

Chaosnet 随着 Lisp 机器的衰落渐渐变得不那么流行。尽管在一小段时间内 Lisp 机器有实际的商业产品 —— Symbolics 和 Lisp Machines Inc 在 80 年代售卖了这些机器。但它们很快被更便宜的微型计算机替代。这些计算机没有特殊制造的回路,但也可以快速运行 Lisp。Chaosnet 被制造出来的目的之一是解决一些 Apernet 协议的原始设计缺陷,但现在 TCP/IP 协议族同样能够解决这些问题了。

壳中幽灵

非常不幸的是,在互联网中留存的关于 Chaosnet 的资料不多。RFC 675 —— TCP/IP 的初稿于 1974 年发布,而 Chasnet 于 1975 年开始开发。 10 但 TCP/IP 最终征服了整个互联网世界,Chaosnet 则被宣布技术性死亡。尽管 Chaosnet 有可能影响了接下来 TCP/IP 的发展,可我并没有找到能够支持这个猜测的证据。

唯一一个可见的 Chaosnet 残留就是 DNS 的 CH 类。这个事实让我着迷。CH 类别是那被遗忘的幽魂 —— 在 TCP/IP 广泛部署中存在的一个替代协议 Chaosnet 的最后栖身之地。至少对于我来说,这件事情是十分让人激动。它告诉我关于 Chaosnet 的最后一丝痕迹,仍然藏在我们日常使用的网络基础架构之中。DNS 的 CH 类别是有趣的数码考古学遗迹。但它同时也是活生生的标识,提醒着我们互联网并非天生完整成型的,TCP/IP 不是唯一一个能够让计算机们交流的协议。“万维网”也远远不是我们这全球交流系统所能有的,最酷的名字。


  1. LISP 1.5 Programmer’s Manual, The Computation Center and Research Laboratory of Electronics, 90, accessed September 30, 2018, http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf
  2. Lisp Machine Progress Report (Artificial Intelligence Memo 444), MIT Artificial Intelligence Laboratory, August, 1977, 3, accessed September 30, 2018, https://dspace.mit.edu/bitstream/handle/1721.1/5751/AIM-444.pdf.
  3. Lisp Machine Progress Report (Artificial Intelligence Memo 444), 4.
  4. 同上
  5. Chaosnet (Artificial Intelligence Memo 628), MIT Artificial Intelligence Laboratory, June, 1981, 1, accessed September 30, 2018, https://dspace.mit.edu/bitstream/handle/1721.1/6353/AIM-628.pdf.
  6. 同上
  7. Chaosnet (Artificial Intelligence Memo 628), 16.
  8. Chaosnet (Artificial Intelligence Memo 628), 9.
  9. Paul Mockapetris and Kevin Dunlap, “The Design of the Domain Name System,” Computer Communication Review 18, no. 4 (August 1988): 3, accessed September 30, 2018, http://www.cs.cornell.edu/people/egs/615/mockapetris.pdf.
  10. Chaosnet (Artificial Intelligence Memo 628), 1.

via: https://twobithistory.org/2018/09/30/chaosnet.html

作者:Two-Bit History 选题:lujun9972 译者:acyanbird 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

众所周知,如果没有 cd 命令,我们无法 Linux 中切换目录。这个没错,但我们有一个名为 shopt 的 Linux 内置命令能帮助我们解决这个问题。

shopt 是一个 shell 内置命令,用于设置和取消设置各种 bash shell 选项,由于它已安装,因此我们不需要再次安装它。

是的,我们可以在启用此选项后,可以不使用 cd 命令切换目录。

我们将在本文中向你展示如何操作。这是一个小的调整,但对于那些从 Windows 迁移到 Linux 的新手来说非常有用。

这对 Linux 管理员没用,因为我们不会在没有 cd 命令的情况下切换到该目录,因为我们对此有经验。

如果你尝试在没有 cd 命令的情况下切换 Linux 的目录/文件夹,你将看到以下错误消息。这在 Linux 中很常见。

$ Documents/
bash: Documents/: Is a directory

为此,我们需要在用户 .bashrc 中追加以下值。

什么是 .bashrc ?

.bashrc 是一个 shell 脚本,每次用户以交互模式打开新 shell 时都会运行该脚本。

你可以在该文件中添加要在命令提示符下输入的任何命令。

.bashrc 文件本身包含终端会话的一系列配置。包括设置和启用:着色、补全,shell 历史,命令别名等。

$ vi ~/.bashrc

加入这一行:

shopt -s autocd

运行以下命令使更改生效。

$ source ~/.bashrc

我们已完成所有配置。简单地对此进行测试以确认这是否有效。

$ Documents/
cd -- Documents/

$ daygeek/
cd -- daygeek/

$ /home/daygeek/Documents/daygeek
cd -- /home/daygeek/Documents/daygeek

$ pwd
/home/daygeek/Documents/daygeek

是的,它正如预期的那样正常工作。

而且,它在 fish shell 中工作正常,而无需对 .bashrc 进行任何更改。

如果要暂时执行此操作,请使用以下命令(设置或取消设置)。重启系统时,它将消失。

# shopt -s autocd

# shopt | grep autocd
autocd  on

# shopt -u autocd

# shopt | grep autocd
autocd  off

shopt 命令提供了许多其他选项,如果要验证这些选项,请运行以下命令。

$ shopt
autocd  on
assoc_expand_once   off
cdable_vars     off
cdspell     on
checkhash   off
checkjobs   off
checkwinsize    on
cmdhist     on
compat31    off
compat32    off
compat40    off
compat41    off
compat42    off
compat43    off
compat44    off
complete_fullquote  on
direxpand   off
dirspell    off
dotglob     off
execfail    off
expand_aliases  on
extdebug    off
extglob     off
extquote    on
failglob    off
force_fignore   on
globasciiranges on
globstar    off
gnu_errfmt  off
histappend  on
histreedit  off
histverify  off
hostcomplete    on
huponexit   off
inherit_errexit off
interactive_comments    on
lastpipe    off
lithist     off
localvar_inherit    off
localvar_unset  off
login_shell     off
mailwarn    off
no_empty_cmd_completion off
nocaseglob  off
nocasematch     off
nullglob    off
progcomp    on
progcomp_alias  off
promptvars  on
restricted_shell    off
shift_verbose   off
sourcepath  on
xpg_echo    off

此外,我找到了一些其他程序,它们可以帮助我们在 Linux 中比 cd 命令更快地切换目录。

它们是 pushdpopdup shell 脚本和 bd 工具。我们将在接下来的文章中介绍这些主题。


via: https://www.2daygeek.com/navigate-switch-directory-without-using-cd-command-in-linux/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

6 位专家为你解析 DevOps 及其实现、实践和哲学的关键。

如果你问 10 个人关于 DevOps 的问题,你会得到 12 个答案。这是对于 DevOps 的意见和期望的多样性的结果,更不用说它在实践中的差异。

为了解读 DevOps 的悖论,我们找到了最了解它的人 —— 这个行业的顶尖从业者。这些人熟悉 DevOps,了解技术的来龙去脉,并且已经有了多年 DevOps 实践。他们的观点应该能鼓励、刺激和激发你对 DevOps 的想法。

DevOps 对你意味着什么?

让我们从基本原理开始。我们不能只在教科书上寻找答案,而应该需要知道专家们怎么说。

简而言之,专家们说的是关于 DevOps 的原则、实践和工具。

IBM 数字企业集团 DevOps 商业平台领导者 Ann Marie Fred,说,“对于我来说,DevOps 是一套实践和原则,旨在使团队在设计、开发、交付和操作软件方面有更好的效率。”

据红帽资深 DevOps 布道者 Daniel Oh,“通常来说,DevOps 促使企业基于当前的 IT 发展与应用开发、IT 运维和安全协议的流程和工具。”

Tactec 战略解决方案的创始人 Brent Reed,谈及了利益相关者的持续改进,“DevOps 对我来说意味着包括了一种思维方式的工作方式,它允许持续改进运维绩效,进而提升组织绩效,从而让利益相关者受益。”

许多专家也强调 DevOps 文化。Ann Marie 说,“这也是持续改进和学习的问题。它涉及的是人和文化,以及工具和技术。”

美国保监会 (NAIC) 首席架构师兼 DevOps 领导者 Dan Barker,“DevOps 主要是关于文化…它将几个独立的领域聚集在一起,如精益生产、公正文化 和持续的学习。我认为文化是最关键和最难执行的。”

Atos 的 DevOps 负责人 Chris Baynham-Hughes,说,“[DevOps] 实践是通过组织内的文化、流程和工具的发展而被采用的。重点是文化变革,DevOps 文化借鉴的关键是协作、试验、快速反馈和持续改进。”

云架构师 Geoff Purdy,谈及敏捷和反馈,“缩短和放大反馈回路。我们希望团队在几分钟内而不是几周内获得反馈。”

但在最后,Daniel 通过解释开源和开源文化是如何让他以简单快捷的方式实现目标来强调这点,“在推动 DevOps 中,最重要的事情应该是开源文化而不是具体的工具或复杂的解决方案。”

你认为哪些 DevOps 实践有效?

专家列举的那些最佳实践是普遍存在的,但又各不相同。

Ann Marie 表示:“一些十分强大灵活的项目管理[实践],能在职能、独立的小组之间打破壁垒;全自动化持续部署,蓝/绿部署实现零时间停机状态;开发人员设置自己的监控和警告,无缝自我修复,自动化的安全性与合规性。”

Chris 说,“特别的突破是倾情合作、持续改进、开放领导、缩短业务距离、从垂直孤岛转向横向/跨功能的产品团队、工作透明化、相互影响、Mobius 循环、缩短反馈回路、自动化(从环境到 CI/CD)。”

Brent 支持“发展学习文化,包括 TTD [测试驱动开发] 和 BDD [行为驱动开发]捕获事件,并通过持续集成和持续交付从设计、构建和测试到实施在生产环境上一系列事件的自动化。测试采用故障优先的方法,能够自动化集成和交付流程,并在整个生命周期中包含快速反馈。”

Geoff 强调自动化配置。“选择一个自动化配置,对我的团队来说非常有效。更具体地说从版本控制代码库中自动配置。”

Dan 则玩的开心,“ 我们做了很多不同的事情来建立 DevOps 文化。我们举办 ‘午餐 & 学习’ 活动,提供免费的食物来鼓励大家一起学习。我们买书,分组学习。”

你如何激励你的团队实现 DevOps 这个目标?

Daniel 强调“自动化的问题就是为了减少 DevOps 计划中来自多个团队的异议,你应该鼓励你的团队提高开发、测试与 IT 运营的自动化能力,以及新的流程和程序。例如,Linux 容器是实现 DevOps 自动化功能的关键工具。”

Geoff 很是赞同,“机械化的劳作,你有讨厌现在做的任务吗?很棒。如果可能的话,让它们消失。不行,那就让它们自动化。它能使工作不会变得太枯燥,因为工作总是在变化。”

Dan、Ann Marie 和 Brent 强调团队的执行力。

Dan 说,“在 NAIC,我们有个很好的奖励系统来鼓励特定的行为。我们有多个级别的奖项,其中两个奖项可以由任何人颁布给某人。我们也会颁奖给完成重要任务的团队,但我们通常只奖励给个人贡献者。”

Ann Marie 表示,“我所在地区的团队最大的动力是看见其他人成功。我们每周都会彼此回放一次,其中一部分是分享我们从尝试新工具或实践中学到的东西。团队热衷于他们现在做的事情,并愿意帮助其他人开始,相信更多的团队很快也会加入进来。”

Brent 表示赞同。“让每个人学习,并掌握同样的基础知识至关重要……我喜欢从评估什么能帮助团队实现目标[以及]产品负责人和用户需要提供的内容入手。”

Chris 推荐采用双管齐下的方法。“运行可以每周可以实现的小目标,并且[在这]可以看到他们正在运做的功能工作之外的进展,庆祝你所取得的进步。”

DevOps 和敏捷开发如何协同工作?

这是一个重要的问题,因为 DevOps 和敏捷开发都是现代软件开发的基石。

DevOps 是一个软件开发的过程,专注与沟通与协作,以促进快速部署应用程序和产品。而敏捷开发是一种开发方法,涉及持续开发、连续迭代和连续测试,以实现可预测和可交付的成果质量。

那么,它们又有怎样的联系?让我们去问问专家吧。

在 Brent 来看,“DevOps != 敏捷。其次 敏捷 != Scrum 流程……敏捷工具和工作方式支撑着 DevOps 策略和目标,它们是如此融合在一起的。”

Chris 说,“对我而言敏捷是 DevOps 的一个基本组件。当然,我们可以讨论如何在非敏捷开发环境中采用 DevOps 文化,但最终表明,提高软件设计方式的灵活性是采用 DevOps 成熟读的一个关键指标。”

Dan 将 DevOps 与更伟大的 敏捷宣言 联系起来。“我在谈到敏捷时总会引用敏捷宣言来设置基准,而有许多实现中并不关注该宣言。当你阅读这份宣言时,你会发现它确实从开发的角度描述了 DevOps。因此,将敏捷融入 DevOps 文化非常容易,因为敏捷关注于沟通、协作、变化的灵活性以及快速地投入生产。”

Geoff 认为 “DevOps 是敏捷实施的众多实现之一。敏捷本质上是一套原则,而 DevOps 则是体现这些原则的文化、流程和工具链。”

Ann Marie 简洁说明,“敏捷是 DevOps 的先决条件。DevOps 使敏捷变得更加有效。”

DevOps 是否受益于开源?

这个问题得到了所有参与者的热烈肯定,然后解释了他们看到的好处。

Ann Marie 说,“我们站在巨人的肩膀上,在已有的基础之上发展。拉取请求和代码评审的开源模式,对 DevOps 团队维护软件很有效果。”

Chris 赞同 DevOps “毫无疑问”受益于开源。“从设计和工具方面(例如,Ansible),到流程和人员方面,通分享行业内的故事和开源社区的领导。”

Geoff 提到一个好处是“基层的采纳”。免费的软件不需要签署购买申请。团队发现了满足他们需求的工具,可以自行进行修改。[然后]在它之上构建,并为更大的社区提供更好的功能。如此往复。

开源已经向 DevOps 展示着“就像开源软件开发者正在做的那样,采用更好的方式来克服新的变化”,Daniel 说。

Brent 同意道 “DevOps 从开源中获益良多。一种方法是使用这些工具来理解它们是如何加速 DevOps 的目标和策略;在自动化、自动伸缩、虚拟化和容器化等关键方面对开发人员和操作人员进行培训,如果不引入使 DevOps 更加容易的技术支持,就很难实现这些特性。”

Dan 指出了 DevOps 和开源之间的双向共生关系,“做好开源需要 DevOps 文化。大多数开源项目都具有非常开放的沟通结构,很少有不透明的地方。对于 Devops 实践者来说,这实际上是一个很好的学习机会,可以让他们了解到可能需要将什么引入自己的组织中。此外能够使用来自社区与组织类似的工具来鼓励自己的文化成长。我喜欢用 GitLab 作为这种共生关系的一个例子。当我把 GitLab 带入一家公司时,我们得到了一个很棒的工具,但我们真正购买的是他们独特的文化,通过我们与他们的互动以及我们的贡献带来了巨大价值。他们的工具也可以为 DevOps 组织提供更多东西,而他们的文化已经在我引入它的公司中引起了他们的敬畏。”

现在我们的 DevOps 专家已经参与进来了,请在评论中分享你对 DevOps 的理解,以及向我们提出其他问题。


via: https://opensource.com/article/19/1/what-does-devops-mean-you

作者:Girish Managoli 选题:lujun9972 译者:MZqk 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出