Python Web 应用程序 Tornado  框架简介

>
> 在比较 Python 框架的系列文章的第三部分中，我们来了解 Tornado，它是为处理异步进程而构建的。
>
>
>

![](/data/attachment/album/201902/09/180056b6yyzfwvvaanavrw.jpg)

在这个由四部分组成的系列文章的前两篇中，我们介绍了 [Pyramid](https://opensource.com/article/18/5/pyramid-framework) 和 [Flask](https://opensource.com/article/18/4/flask) Web 框架。我们已经构建了两次相同的应用程序，看到了一个完整的 DIY 框架和包含了更多功能的框架之间的异同。

现在让我们来看看另一个稍微不同的选择：[Tornado 框架](https://tornado.readthedocs.io/en/stable/)。Tornado 在很大程度上与 Flask 一样简单，但有一个主要区别：Tornado 是专门为处理异步进程而构建的。在我们本系列所构建的应用程序中，这种特殊的酱料（LCTT 译注：这里意思是 Tornado 的异步功能）在我们构建的 app 中并不是非常有用，但我们将看到在哪里可以使用它，以及它在更一般的情况下是如何工作的。

让我们继续前两篇文章中模式，首先从处理设置和配置开始。

### Tornado 启动和配置

如果你一直关注这个系列，那么第一步应该对你来说习以为常。

```
$ mkdir tornado_todo
$ cd tornado_todo
$ pipenv install --python 3.6
$ pipenv shell
(tornado-someHash) $ pipenv install tornado
```

创建一个 `setup.py` 文件来安装我们的应用程序相关的东西：

```
(tornado-someHash) $ touch setup.py
# setup.py
from setuptools import setup, find_packages

requires = [
    'tornado',
    'tornado-sqlalchemy',
    'psycopg2',
]

setup(
    name='tornado_todo',
    version='0.0',
    description='A To-Do List built with Tornado',
    author='<Your name>',
    author_email='<Your email>',
    keywords='web tornado',
    packages=find_packages(),
    install_requires=requires,
    entry_points={
        'console_scripts': [
            'serve_app = todo:main',
        ],
    },
)
```

因为 Tornado 不需要任何外部配置，所以我们可以直接编写 Python 代码来让程序运行。让我们创建 `todo` 目录，并用需要的前几个文件填充它。

```
todo/
    __init__.py
    models.py
    views.py
```

就像 Flask 和 Pyramid 一样，Tornado 也有一些基本配置，放在 `__init__.py` 中。从 `tornado.web` 中，我们将导入 `Application` 对象，它将处理路由和视图的连接，包括数据库（当我们谈到那里时再说）以及运行 Tornado 应用程序所需的其它额外设置。

```
# __init__.py
from tornado.web import Application

def main():
    """Construct and serve the tornado application."""
    app = Application()
```

像 Flask 一样，Tornado 主要是一个 DIY 框架。当构建我们的 app 时，我们必须设置该应用实例。因为 Tornado 用它自己的 HTTP 服务器来提供该应用，我们必须设置如何提供该应用。首先，在 `tornado.options.define` 中定义要监听的端口。然后我们实例化 Tornado 的 `HTTPServer`，将该 `Application` 对象的实例作为参数传递给它。

```
# __init__.py
from tornado.httpserver import HTTPServer
from tornado.options import define, options
from tornado.web import Application

define('port', default=8888, help='port to listen on')

def main():
    """Construct and serve the tornado application."""
    app = Application()
    http_server = HTTPServer(app)
    http_server.listen(options.port)
```

当我们使用 `define` 函数时，我们最终会在 `options` 对象上创建属性。第一个参数位置的任何内容都将是属性的名称，分配给 `default` 关键字参数的内容将是该属性的值。

例如，如果我们将属性命名为 `potato` 而不是 `port`，我们可以通过 `options.potato` 访问它的值。

在 `HTTPServer` 上调用 `listen` 并不会启动服务器。我们必须再做一步，找一个可以监听请求并返回响应的工作应用程序，我们需要一个输入输出循环。幸运的是，Tornado 以 `tornado.ioloop.IOLoop` 的形式提供了开箱即用的功能。

```
# __init__.py
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.options import define, options
from tornado.web import Application

define('port', default=8888, help='port to listen on')

def main():
    """Construct and serve the tornado application."""
    app = Application()
    http_server = HTTPServer(app)
    http_server.listen(options.port)
    print('Listening on http://localhost:%i' % options.port)
    IOLoop.current().start()
```

我喜欢某种形式的 `print` 语句，来告诉我什么时候应用程序正在提供服务，这是我的习惯。如果你愿意，可以不使用 `print`。

我们以 `IOLoop.current().start()` 开始我们的 I/O 循环。让我们进一步讨论输入，输出和异步性。

### Python 中的异步和 I/O 循环的基础知识

请允许我提前说明，我绝对，肯定，一定并且放心地说不是异步编程方面的专家。就像我写的所有内容一样，接下来的内容源于我对这个概念的理解的局限性。因为我是人，可能有很深很深的缺陷。

异步程序的主要问题是：

```
* 数据如何进来？
* 数据如何出去？
* 什么时候可以在不占用我全部注意力情况下运行某个过程？
```

由于[全局解释器锁](https://realpython.com/python-gil/)（GIL），Python 被设计为一种[单线程](https://en.wikipedia.org/wiki/Thread_(computing))语言。对于 Python 程序必须执行的每个任务，其线程执行的全部注意力都集中在该任务的持续时间内。我们的 HTTP 服务器是用 Python 编写的，因此，当接收到数据（如 HTTP 请求）时，服务器的唯一关心的是传入的数据。这意味着，在大多数情况下，无论是程序需要运行还是处理数据，程序都将完全消耗服务器的执行线程，阻止接收其它可能的数据，直到服务器完成它需要做的事情。

在许多情况下，这不是太成问题。典型的 Web 请求，响应周期只需要几分之一秒。除此之外，构建 HTTP 服务器的套接字可以维护待处理的传入请求的积压。因此，如果请求在该套接字处理其它内容时进入，则它很可能只是在处理之前稍微排队等待一会。对于低到中等流量的站点，几分之一秒的时间并不是什么大问题，你可以使用多个部署的实例以及 [NGINX](https://www.nginx.com/) 等负载均衡器来为更大的请求负载分配流量。

但是，如果你的平均响应时间超过一秒钟，该怎么办？如果你使用来自传入请求的数据来启动一些长时间的过程（如机器学习算法或某些海量数据库查询），该怎么办？现在，你的单线程 Web 服务器开始累积一个无法寻址的积压请求，其中一些请求会因为超时而被丢弃。这不是一种选择，特别是如果你希望你的服务在一段时间内是可靠的。

异步 Python 程序登场。重要的是要记住因为它是用 Python 编写的，所以程序仍然是一个单线程进程。除非特别标记，否则在异步程序中仍然会阻塞执行。

但是，当异步程序结构正确时，只要你指定某个函数应该具有这样的能力，你的异步 Python 程序就可以“搁置”长时间运行的任务。然后，当搁置的任务完成并准备好恢复时，异步控制器会收到报告，只要在需要时管理它们的执行，而不会完全阻塞对新输入的处理。

这有点夸张，所以让我们用一个人类的例子来证明。

### 带回家吧

我经常发现自己在家里试图完成很多家务，但没有多少时间来做它们。在某一天，积压的家务可能看起来像：

```
* 做饭（20 分钟准备，40 分钟烹饪）
* 洗碗（60 分钟）
* 洗涤并擦干衣物（30 分钟洗涤，每次干燥 90 分钟）
* 真空清洗地板（30 分钟）
```

如果我是一个传统的同步程序，我会亲自完成每项任务。在我考虑处理任何其他事情之前，每项任务都需要我全神贯注地完成。因为如果没有我的全力关注，什么事情都完成不了。所以我的执行顺序可能如下：

```
1. 完全专注于准备和烹饪食物，包括等待食物烹饪（60 分钟）
2. 将脏盘子移到水槽中（65 分钟过去了）
3. 清洗所有盘子（125 分钟过去了）
4. 开始完全专注于洗衣服，包括等待洗衣机洗完，然后将衣物转移到烘干机，再等烘干机完成（ 250 分钟过去了）
5. 对地板进行真空吸尘（280 分钟了）
```

从头到尾完成所有事情花费了 4 小时 40 分钟。

我应该像异步程序一样聪明地工作，而不是努力工作。我的家里到处都是可以为我工作的机器，而不用我一直努力工作。同时，现在我可以将注意力转移真正需要的东西上。

我的执行顺序可能看起来像：

```
1. 将衣物放入洗衣机并启动它（5 分钟）
2. 在洗衣机运行时，准备食物（25 分钟过去了）
3. 准备好食物后，开始烹饪食物（30 分钟过去了）
4. 在烹饪食物时，将衣物从洗衣机移到烘干机机中开始烘干（35 分钟过去了）
5. 当烘干机运行中，且食物仍在烹饪时，对地板进行真空吸尘（65 分钟过去了）
6. 吸尘后，将食物从炉子中取出并装盘子入洗碗机（70 分钟过去了）
7. 运行洗碗机（130 分钟完成）
```

现在花费的时间下降到 2 小时 10 分钟。即使我允许在作业之间切换花费更多时间（总共 10-20 分钟）。如果我等待着按顺序执行每项任务，我花费的时间仍然只有一半左右。这就是将程序构造为异步的强大功能。

#### 那么 I/O 循环在哪里？

一个异步 Python 程序的工作方式是从某个外部源（输入）获取数据，如果某个进程需要，则将该数据转移到某个外部工作者（输出）进行处理。当外部进程完成时，Python 主程序会收到提醒，然后程序获取外部处理（输入）的结果，并继续这样其乐融融的方式。

当数据不在 Python 主程序手中时，主程序就会被释放来处理其它任何事情。包括等待全新的输入（如 HTTP 请求）和处理长时间运行的进程的结果（如机器学习算法的结果，长时间运行的数据库查询）。主程序虽仍然是单线程的，但成了事件驱动的，它对程序处理的特定事件会触发动作。监听这些事件并指示应如何处理它们的主要是 I/O 循环在工作。

我知道，我们走了很长的路才得到这个重要的解释，但我希望在这里传达的是，它不是魔术，也不是某种复杂的并行处理或多线程工作。全局解释器锁仍然存在，主程序中任何长时间运行的进程仍然会阻塞其它任何事情的进行，该程序仍然是单线程的。然而，通过将繁琐的工作外部化，我们可以将线程的注意力集中在它需要注意的地方。

这有点像我上面的异步任务。当我的注意力完全集中在准备食物上时，它就是我所能做的一切。然而，当我能让炉子帮我做饭，洗碗机帮我洗碗，洗衣机和烘干机帮我洗衣服时，我的注意力就会被释放出来，去做其它事情。当我被提醒，我的一个长时间运行的任务已经完成并准备再次处理时，如果我的注意力是空闲的，我可以获取该任务的结果，并对其做下一步需要做的任何事情。

### Tornado 路由和视图

尽管经历了在 Python 中讨论异步的所有麻烦，我们还是决定暂不使用它。先来编写一个基本的 Tornado 视图。

与我们在 Flask 和 Pyramid 实现中看到的基于函数的视图不同，Tornado 的视图都是基于类的。这意味着我们将不在使用单独的、独立的函数来规定如何处理请求。相反，传入的 HTTP 请求将被捕获并将其分配为我们定义的类的一个属性。然后，它的方法将处理相应的请求类型。

让我们从一个基本的视图开始，即在屏幕上打印 “Hello, World”。我们为 Tornado 应用程序构造的每个基于类的视图都必须继承 `tornado.web` 中的 `RequestHandler` 对象。这将设置我们需要（但不想写）的所有底层逻辑来接收请求，同时构造正确格式的 HTTP 响应。

```
from tornado.web import RequestHandler

class HelloWorld(RequestHandler):
    """Print 'Hello, world!' as the response body."""

    def get(self):
        """Handle a GET request for saying Hello World!."""
        self.write("Hello, world!")
```

因为我们要处理 `GET` 请求，所以我们声明（实际上是重写）了 `get` 方法。我们提供文本或 JSON 可序列化对象，用 `self.write` 写入响应体。之后，我们让 `RequestHandler` 来做在发送响应之前必须完成的其它工作。

就目前而言，此视图与 Tornado 应用程序本身并没有实际连接。我们必须回到 `__init__.py`，并稍微更新 `main` 函数。以下是新的内容：

```
# __init__.py
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.options import define, options
from tornado.web import Application
from todo.views import HelloWorld

define('port', default=8888, help='port to listen on')

def main():
    """Construct and serve the tornado application."""
    app = Application([
        ('/', HelloWorld)
    ])
    http_server = HTTPServer(app)
    http_server.listen(options.port)
    print('Listening on http://localhost:%i' % options.port)
    IOLoop.current().start()
```

#### 我们做了什么

我们将 `views.py` 文件中的 `HelloWorld` 视图导入到脚本 `__init__.py` 的顶部。然后我们添加了一个路由-视图对应的列表，作为 `Application` 实例化的第一个参数。每当我们想要在应用程序中声明一个路由时，它必须绑定到一个视图。如果需要，可以对多个路由使用相同的视图，但每个路由必须有一个视图。

我们可以通过在 `setup.py` 中启用的 `serve_app` 命令来运行应用程序，从而确保这一切都能正常工作。查看 `http://localhost:8888/` 并看到它显示 “Hello, world!”。

当然，在这个领域中我们还能做更多，也将做更多，但现在让我们来讨论模型吧。

### 连接数据库

如果我们想要保留数据，就需要连接数据库。与 Flask 一样，我们将使用一个特定于框架的 SQLAchemy 变体，名为 [tornado-sqlalchemy](https://tornado-sqlalchemy.readthedocs.io/en/latest/)。

为什么要使用它而不是 [SQLAlchemy](https://www.sqlalchemy.org/) 呢？好吧，其实 `tornado-sqlalchemy` 具有简单 SQLAlchemy 的所有优点，因此我们仍然可以使用通用的 `Base` 声明模型，并使用我们习以为常的所有列数据类型和关系。除了我们已经惯常了解到的，`tornado-sqlalchemy` 还为其数据库查询功能提供了一种可访问的异步模式，专门用于与 Tornado 现有的 I/O 循环一起工作。

我们通过将 `tornado-sqlalchemy` 和 `psycopg2` 添加到 `setup.py` 到所需包的列表并重新安装包来创建环境。在 `models.py` 中，我们声明了模型。这一步看起来与我们在 Flask 和 Pyramid 中已经看到的完全一样，所以我将跳过全部声明，只列出了 `Task` 模型的必要部分。

```
# 这不是完整的 models.py, 但是足够看到不同点
from tornado_sqlalchemy import declarative_base

Base = declarative_base

class Task(Base):
    # 等等，因为剩下的几乎所有的东西都一样 ...
```

我们仍然需要将 `tornado-sqlalchemy` 连接到实际应用程序。在 `__init__.py` 中，我们将定义数据库并将其集成到应用程序中。

```
# __init__.py
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.options import define, options
from tornado.web import Application
from todo.views import HelloWorld

# add these
import os
from tornado_sqlalchemy import make_session_factory

define('port', default=8888, help='port to listen on')
factory = make_session_factory(os.environ.get('DATABASE_URL', ''))

def main():
    """Construct and serve the tornado application."""
    app = Application([
        ('/', HelloWorld)
    ],
        session_factory=factory
    )
    http_server = HTTPServer(app)
    http_server.listen(options.port)
    print('Listening on http://localhost:%i' % options.port)
    IOLoop.current().start()
```

就像我们在 Pyramid 中传递的会话工厂一样，我们可以使用 `make_session_factory` 来接收数据库 URL 并生成一个对象，这个对象的唯一目的是为视图提供到数据库的连接。然后我们将新创建的 `factory` 传递给 `Application` 对象，并使用 `session_factory` 关键字参数将它绑定到应用程序中。

最后，初始化和管理数据库与 Flask 和 Pyramid 相同（即，单独的 DB 管理脚本，与 `Base` 对象一起工作等）。它看起来很相似，所以在这里我就不介绍了。

### 回顾视图

Hello，World 总是适合学习基础知识，但我们需要一些真实的，特定应用程序的视图。

让我们从 info 视图开始。

```
# views.py
import json
from tornado.web import RequestHandler

class InfoView(RequestHandler):
    """只允许 GET 请求"""
    SUPPORTED_METHODS = ["GET"]

    def set_default_headers(self):
        """设置默认响应头为 json 格式的"""
        self.set_header("Content-Type", 'application/json; charset="utf-8"')

    def get(self):
        """列出这个 API 的路由"""
        routes = {
            'info': 'GET /api/v1',
            'register': 'POST /api/v1/accounts',
            'single profile detail': 'GET /api/v1/accounts/<username>',
            'edit profile': 'PUT /api/v1/accounts/<username>',
            'delete profile': 'DELETE /api/v1/accounts/<username>',
            'login': 'POST /api/v1/accounts/login',
            'logout': 'GET /api/v1/accounts/logout',
            "user's tasks": 'GET /api/v1/accounts/<username>/tasks',
            "create task": 'POST /api/v1/accounts/<username>/tasks',
            "task detail": 'GET /api/v1/accounts/<username>/tasks/<id>',
            "task update": 'PUT /api/v1/accounts/<username>/tasks/<id>',
            "delete task": 'DELETE /api/v1/accounts/<username>/tasks/<id>'
        }
        self.write(json.dumps(routes))
```

有什么改变吗？让我们从上往下看。

我们添加了 `SUPPORTED_METHODS` 类属性，它是一个可迭代对象，代表这个视图所接受的请求方法，其他任何方法都将返回一个 [405](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors) 状态码。当我们创建 `HelloWorld` 视图时，我们没有指定它，主要是当时有点懒。如果没有这个类属性，此视图将响应任何试图绑定到该视图的路由的请求。

我们声明了 `set_default_headers` 方法，它设置 HTTP 响应的默认头。我们在这里声明它，以确保我们返回的任何响应都有一个 `"Content-Type"` 是 `"application/json"` 类型。

我们将 `json.dumps(some_object)` 添加到 `self.write` 的参数中，因为它可以很容易地构建响应主体的内容。

现在已经完成了，我们可以继续将它连接到 `__init__.py` 中的主路由。

```
# __init__.py
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.options import define, options
from tornado.web import Application
from todo.views import InfoView

# 添加这些
import os
from tornado_sqlalchemy import make_session_factory

define('port', default=8888, help='port to listen on')
factory = make_session_factory(os.environ.get('DATABASE_URL', ''))

def main():
    """Construct and serve the tornado application."""
    app = Application([
        ('/', InfoView)
    ],
        session_factory=factory
    )
    http_server = HTTPServer(app)
    http_server.listen(options.port)
    print('Listening on http://localhost:%i' % options.port)
    IOLoop.current().start()
```

我们知道，还需要编写更多的视图和路由。每个都会根据需要放入 `Application` 路由列表中，每个视图还需要一个 `set_default_headers` 方法。在此基础上，我们还将创建 `send_response` 方法，它的作用是将响应与我们想要给响应设置的任何自定义状态码打包在一起。由于每个视图都需要这两个方法，因此我们可以创建一个包含它们的基类，这样每个视图都可以继承基类。这样，我们只需要编写一次。

```
# views.py
import json
from tornado.web import RequestHandler

class BaseView(RequestHandler):
    """Base view for this application."""

    def set_default_headers(self):
        """Set the default response header to be JSON."""
        self.set_header("Content-Type", 'application/json; charset="utf-8"')

    def send_response(self, data, status=200):
        """Construct and send a JSON response with appropriate status code."""
        self.set_status(status)
        self.write(json.dumps(data))
```

对于我们即将编写的 `TaskListView` 这样的视图，我们还需要一个到数据库的连接。我们需要 `tornado_sqlalchemy` 中的 `SessionMixin` 在每个视图类中添加一个数据库会话。我们可以将它放在 `BaseView` 中，这样，默认情况下，从它继承的每个视图都可以访问数据库会话。

```
# views.py
import json
from tornado_sqlalchemy import SessionMixin
from tornado.web import RequestHandler

class BaseView(RequestHandler, SessionMixin):
    """Base view for this application."""

    def set_default_headers(self):
        """Set the default response header to be JSON."""
        self.set_header("Content-Type", 'application/json; charset="utf-8"')

    def send_response(self, data, status=200):
        """Construct and send a JSON response with appropriate status code."""
        self.set_status(status)
        self.write(json.dumps(data))
```

只要我们修改 `BaseView` 对象，在将数据发布到这个 API 时，我们就应该定位到这里。

当 Tornado（从 v.4.5 开始）使用来自客户端的数据并将其组织起来到应用程序中使用时，它会将所有传入数据视为字节串。但是，这里的所有代码都假设使用 Python 3，因此我们希望使用的唯一字符串是 Unicode 字符串。我们可以为这个 `BaseView` 类添加另一个方法，它的工作是将输入数据转换为 Unicode，然后再在视图的其他地方使用。

如果我们想要在正确的视图方法中使用它之前转换这些数据，我们可以重写视图类的原生 `prepare` 方法。它的工作是在视图方法运行前运行。如果我们重写 `prepare` 方法，我们可以设置一些逻辑来运行，每当收到请求时，这些逻辑就会执行字节串到 Unicode 的转换。

```
# views.py
import json
from tornado_sqlalchemy import SessionMixin
from tornado.web import RequestHandler

class BaseView(RequestHandler, SessionMixin):
    """Base view for this application."""

    def prepare(self):
        self.form_data = {
            key: [val.decode('utf8') for val in val_list]
            for key, val_list in self.request.arguments.items()
        }

    def set_default_headers(self):
        """Set the default response header to be JSON."""
        self.set_header("Content-Type", 'application/json; charset="utf-8"')

    def send_response(self, data, status=200):
        """Construct and send a JSON response with appropriate status code."""
        self.set_status(status)
        self.write(json.dumps(data))
```

如果有任何数据进入，它将在 `self.request.arguments` 字典中找到。我们可以通过键访问该数据库，并将其内容（始终是列表）转换为 Unicode。因为这是基于类的视图而不是基于函数的，所以我们可以将修改后的数据存储为一个实例属性，以便以后使用。我在这里称它为 `form_data`，但它也可以被称为 `potato`。关键是我们可以存储提交给应用程序的数据。

### 异步视图方法

现在我们已经构建了 `BaseaView`，我们可以构建 `TaskListView` 了，它会继承 `BaseaView`。

正如你可以从章节标题中看到的那样，以下是所有关于异步性的讨论。`TaskListView` 将处理返回任务列表的 `GET` 请求和用户给定一些表单数据来创建新任务的 `POST` 请求。让我们首先来看看处理 `GET` 请求的代码。

```
# all the previous imports
import datetime
from tornado.gen import coroutine
from tornado_sqlalchemy import as_future
from todo.models import Profile, Task

# the BaseView is above here
class TaskListView(BaseView):
    """View for reading and adding new tasks."""
    SUPPORTED_METHODS = ("GET", "POST",)

    @coroutine
    def get(self, username):
        """Get all tasks for an existing user."""
        with self.make_session() as session:
            profile = yield as_future(session.query(Profile).filter(Profile.username == username).first)
            if profile:
                tasks = [task.to_dict() for task in profile.tasks]
                self.send_response({
                    'username': profile.username,
                    'tasks': tasks
                })
```

这里的第一个主要部分是 `@coroutine` 装饰器，它从 `tornado.gen` 导入。任何具有与调用堆栈的正常流程不同步的 Python 可调用部分实际上是“协程”，即一个可以与其它协程一起运行的协程。在我的家务劳动的例子中，几乎所有的家务活都是一个共同的例行协程。有些阻止了例行协程（例如，给地板吸尘），但这种例行协程只会阻碍我开始或关心其它任何事情的能力。它没有阻止已经启动的任何其他协程继续进行。

Tornado 提供了许多方法来构建一个利用协程的应用程序，包括允许我们设置函数调用锁，同步异步协程的条件，以及手动修改控制 I/O 循环的事件系统。

这里使用 `@coroutine` 装饰器的唯一条件是允许 `get` 方法将 SQL 查询作为后台进程，并在查询完成后恢复，同时不阻止 Tornado I/O 循环去处理其他传入的数据源。这就是关于此实现的所有“异步”：带外数据库查询。显然，如果我们想要展示异步 Web 应用程序的魔力和神奇，那么一个任务列表就不是好的展示方式。

但是，这就是我们正在构建的，所以让我们来看看方法如何利用 `@coroutine` 装饰器。`SessionMixin` 混合到 `BaseView` 声明中，为我们的视图类添加了两个方便的，支持数据库的属性：`session` 和 `make_session`。它们的名字相似，实现的目标也相当相似。

`self.session` 属性是一个关注数据库的会话。在请求-响应周期结束时，在视图将响应发送回客户端之前，任何对数据库的更改都被提交，并关闭会话。

`self.make_session` 是一个上下文管理器和生成器，可以动态构建和返回一个全新的会话对象。第一个 `self.session` 对象仍然存在。无论如何，反正 `make_session` 会创建一个新的。`make_session` 生成器还为其自身提供了一个功能，用于在其上下文（即缩进级别）结束时提交和关闭它创建的会话。

如果你查看源代码，则赋值给 `self.session` 的对象类型与 `self.make_session` 生成的对象类型之间没有区别，不同之处在于它们是如何被管理的。

使用 `make_session` 上下文管理器，生成的会话仅属于上下文，在该上下文中开始和结束。你可以使用 `make_session` 上下文管理器在同一个视图中打开，修改，提交以及关闭多个数据库会话。

`self.session` 要简单得多，当你进入视图方法时会话已经打开，在响应被发送回客户端之前会话就已提交。

虽然[读取文档片段](https://tornado-sqlalchemy.readthedocs.io/en/latest/#usage)和 [PyPI 示例](https://pypi.org/project/tornado-sqlalchemy/#description)都说明了上下文管理器的使用，但是没有说明 `self.session` 对象或由 `self.make_session` 生成的 `session` 本质上是不是异步的。当我们启动查询时，我们开始考虑内置于 `tornado-sqlalchemy` 中的异步行为。

`tornado-sqlalchemy` 包为我们提供了 `as_future` 函数。它的工作是装饰 `tornado-sqlalchemy` 会话构造的查询并 yield 其返回值。如果视图方法用 `@coroutine` 装饰，那么使用 `yield as_future(query)` 模式将使封装的查询成为一个异步后台进程。I/O 循环会接管等待查询的返回值和 `as_future` 创建的 `future` 对象的解析。

要访问 `as_future（query）` 的结果，你必须从它 `yield`。否则，你只能获得一个未解析的生成器对象，并且无法对查询执行任何操作。

这个视图方法中的其他所有内容都与之前课堂上的类似，与我们在 Flask 和 Pyramid 中看到的内容类似。

`post` 方法看起来非常相似。为了保持一致性，让我们看一下 `post` 方法以及它如何处理用 `BaseView` 构造的 `self.form_data`。

```
@coroutine
def post(self, username):
    """Create a new task."""
    with self.make_session() as session:
        profile = yield as_future(session.query(Profile).filter(Profile.username == username).first)
        if profile:
            due_date = self.form_data['due_date'][0]
            task = Task(
                name=self.form_data['name'][0],
                note=self.form_data['note'][0],
                creation_date=datetime.now(),
                due_date=datetime.strptime(due_date, '%d/%m/%Y %H:%M:%S') if due_date else None,
                completed=self.form_data['completed'][0],
                profile_id=profile.id,
                profile=profile
            )
            session.add(task)
            self.send_response({'msg': 'posted'}, status=201)
```

正如我所说，这是我们所期望的：

 \* 与我们在 `get` 方法中看到的查询模式相同 \* 构造一个新的 `Task` 对象的实例，用 `form_data` 的数据填充 \* 添加新的 `Task` 对象（但不提交，因为它由上下文管理器处理！）到数据库会话 \* 将响应发送给客户端

这样我们就有了 Tornado web 应用程序的基础。其他内容（例如，数据库管理和更多完整应用程序的视图）实际上与我们在 Flask 和 Pyramid 应用程序中看到的相同。

### 关于使用合适的工具完成合适的工作的一点想法

在我们继续浏览这些 Web 框架时，我们开始看到它们都可以有效地处理相同的问题。对于像这样的待办事项列表，任何框架都可以完成这项任务。但是，有些 Web 框架比其它框架更适合某些工作，这具体取决于对你来说什么“更合适”和你的需求。

虽然 Tornado 显然和 Pyramid 或 Flask 一样可以处理相同工作，但将它用于这样的应用程序实际上是一种浪费，这就像开车从家走一个街区（LCTT 译注：这里意思应该是从家开始走一个街区只需步行即可）。是的，它可以完成“旅行”的工作，但短途旅行不是你选择汽车而不是自行车或者使用双脚的原因。

根据文档，Tornado 被称为 “Python Web 框架和异步网络库”。在 Python Web 框架生态系统中很少有人喜欢它。如果你尝试完成的工作需要（或将从中获益）以任何方式、形状或形式的异步性，使用 Tornado。如果你的应用程序需要处理多个长期连接，同时又不想牺牲太多性能，选择 Tornado。如果你的应用程序是多个应用程序，并且需要线程感知以准确处理数据，使用 Tornado。这是它最有效的地方。

用你的汽车做“汽车的事情”，使用其他交通工具做其他事情。

### 向前看，进行一些深度检查

谈到使用合适的工具来完成合适的工作，在选择框架时，请记住应用程序的范围和规模，包括现在和未来。到目前为止，我们只研究了适用于中小型 Web 应用程序的框架。本系列的下一篇也是最后一篇将介绍最受欢迎的 Python 框架之一 Django，它适用于可能会变得更大的大型应用程序。同样，尽管它在技术上能够并且将会处理待办事项列表问题，但请记住，这不是它的真正用途。我们仍然会通过它来展示如何使用它来构建应用程序，但我们必须牢记框架的意图以及它是如何反映在架构中的：

* **Flask**： 适用于小型，简单的项目。它可以使我们轻松地构建视图并将它们快速连接到路由，它可以简单地封装在一个文件中。
* **Pyramid**： 适用于可能增长的项目。它包含一些配置来启动和运行。应用程序组件的独立领域可以很容易地划分并构建到任意深度，而不会忽略中央应用程序。
* **Tornado**： 适用于受益于精确和有意识的 I/O 控制的项目。它允许协程，并轻松公开可以控制如何接收请求或发送响应以及何时发生这些操作的方法。
* **Django**：（我们将会看到）意味着可能会变得更大的东西。它有着非常庞大的生态系统，包括大量插件和模块。它非常有主见的配置和管理，以保持所有不同部分在同一条线上。

无论你是从本系列的第一篇文章开始阅读，还是稍后才加入的，都要感谢阅读！请随意留下问题或意见。下次再见时，我手里会拿着 Django。

### 感谢 Python BDFL

我必须把功劳归于它应得的地方，非常感谢 [Guido van Rossum](https://www.twitter.com/gvanrossum)，不仅仅是因为他创造了我最喜欢的编程语言。

在 [PyCascades 2018](https://www.pycascades.com) 期间，我很幸运的不仅做了基于这个文章系列的演讲，而且还被邀请参加了演讲者的晚宴。整个晚上我都坐在 Guido 旁边，不停地问他问题。其中一个问题是，在 Python 中异步到底是如何工作的，但他没有一点大惊小怪，而是花时间向我解释，让我开始理解这个概念。他后来[推特给我](https://twitter.com/gvanrossum/status/956186585493458944)发了一条消息：是用于学习异步 Python 的广阔资源。我随后在三个月内阅读了三次，然后写了这篇文章。你真是一个非常棒的人，Guido！

---

via: <https://opensource.com/article/18/6/tornado-framework>

作者：[Nicholas Hunt-Walker](https://opensource.com/users/nhuntwalker) 选题：[lujun9972](https://github.com/lujun9972) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

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


Linux 上最好的五款音乐播放器

Summary: Jack Wallen 盘点他最爱的五款 Linux 音乐播放器。

>
> Jack Wallen 盘点他最爱的五款 Linux 音乐播放器。
>
>
>

![](/data/attachment/album/201902/09/232031rtjn0tiwwjxjjjgg.jpg)

不管你做什么，你都有时会来一点背景音乐。不管你是开发、运维或是一个典型的电脑用户，享受美妙的音乐都可能是你在电脑上最想做的事情之一。同时随着即将到来的假期，你可能收到一些能让你买几首新歌的礼物卡。如果你所选的音乐是数字形式（我的恰好是唱片形式）而且你的平台是 Linux 的话，你会想要一个好的图形用户界面播放器来享受音乐。

幸运的是，Linux 不缺好的数字音乐播放器。事实上，Linux 上有不少播放器，大部分是开源并且可以免费获得的。让我们看看其中的几款，看哪个能满足你的需要。

### Clementine

我想从我用来许多年的默认选项的播放器开始。[Clementine](https://www.clementine-player.org/) 可能是最好的平衡了易用性与灵活性的播放器。Clementine 是新停摆的 [Amarok](https://en.wikipedia.org/wiki/Amarok_(software)) 音乐播放器的复刻，但它不仅限于 Linux； Clementine 在 Mac OS 和 Windows 平台上也可以获得。它的一系列特性十分惊艳，包括：

* 內建的均衡器
* 可定制的界面（将现在的专辑封面显示成背景，见图一）
* 播放本地音乐或者从 Spotify、Last.fm 等播放音乐
* 便于库导航的侧边栏
* 內建的音频转码（转成 MP3、OGG、Flac 等）
* 通过 [安卓应用](https://play.google.com/store/apps/details?id=de.qspool.clementineremote) 远程控制
* 便利的搜索功能
* 选项卡式播放列表
* 简单创建常规和智能化的播放列表
* 支持 CUE 文件
* 支持标签

![Clementine](/data/attachment/album/201902/09/232045h4rxs4rruk5yu4ze.jpg "Clementine")

*图一：Clementine 界面可能有一点老派，但是它不可思议得灵活好用。*

在所有我用过的音乐播放器中，Clementine 是目前为止功能最多也是最容易使用的。它同时也包含了你能在 Linux 音乐播放器中找到的最好的均衡器（有十个频带可以调）。尽管它的界面不够时髦，但它创建、操控播放列表的能力是无与伦比的。如果你的音乐集很大，同时你想完全操控你的音乐集的话，这就是你想要的播放器。

Clementine 可以在标准仓库中找到。它可以从你的发行版的软件中心或通过命令行来安装。

### Rhythmbox

[Rhythmbox](https://wiki.gnome.org/Apps/Rhythmbox) 是 GNOME 桌面的默认播放器，但是它在其它桌面工作得也很好。Rhythmbox 的界面比 Clementine 的界面稍微时尚一点，它的设计遵循极简的理念。这并不意味着它缺乏特性，相反 Rhythmbox 提供无间隔回放、支持 Soundcloud、专辑封面显示、从 Last.fm 和 Libre.fm 导入音频、支持 Jamendo、播客订阅（从 [Apple iTunes](https://www.apple.com/itunes/)）、从网页远程控制等特性。

在 Rhythmbox 中发现的一个很好的特性是支持插件，这使得你可以使用像 DAAP 音乐分享、FM 电台、封面查找、通知、ReplayGain、歌词等特性。

Rhythmbox 播放列表特性不像 Clementine 的那么强大，但是将你的音乐整理进任何形式的快速播放列表还是很简单的。尽管 Rhythmbox 的界面（图二）比 Clementine 要时髦一点，但是它不像 Clementine 那样灵活。

![Rhythmbox](/data/attachment/album/201902/09/232052ce3tcebcmgbtpzgt.jpg "Rhythmbox")

*图二：Rhythmbox 界面简单直接。*

### VLC Media Player

对于部分人来说，[VLC](https://www.videolan.org/vlc/index.html) 在视频播放方面是无懈可击的。然而 VLC 不仅限于视频播放。事实上，VLC在播放音频文件方面做得也很好。对于 [KDE Neon](https://neon.kde.org/) 用户来说，VLC 既是音乐也是视频的默认播放器。尽管 VLC 是 Linux 市场最好的视频播放器的之一（它是我的默认播放器），它在音频方面确实略有瑕疵 —— 缺少播放列表以及不能够连接到你网络中的远程仓库。但如果你是在寻找一种播放本地文件或者网络 mms/rtsp 的简单可靠的方式，VLC 是上佳之选。VLC 包括一个均衡器（图三）、一个压缩器以及一个空间音响。它同样也能够从捕捉到的设备录音。

![VLC](/data/attachment/album/201902/09/232101u2d2vss8qvva3mv2.jpg "VLC")

*图三：运转中的 VLC 均衡器。*

### Audacious

如果你在寻找一个轻量级的音乐播放器，Audacious 完美地满足要求。这个音乐播放器相当的专一，但是它包括了一个均衡器和一小部分能够改善许多音频的声效（比如回声、消除默音、调节速度和音调、去除人声等，见图四）。

![Audacious](/data/attachment/album/201902/09/232104s939zjr903e3r9ps.jpg "Audacious ")

*图四：Audacious 均衡器和插件。*

Audacious 也包括了一个十分简便的闹铃功能。它允许你设置一个能在用户选定的时间点和持续的时间段内播放选定乐段的闹铃。

### Spotify

我必须承认，我每天都用 Spotify。我是一个 Spotify 的订阅者并用它去发现、购买新的音乐 —— 这意味着我在不停地探索发现。幸运的是，Spotify 有一个我能按照 [Spotify官方 Linux 平台安装指导](https://www.spotify.com/us/download/linux/) 轻松安装的桌面客户端。在桌面客户端与 [安卓应用](https://play.google.com/store/apps/details?id=com.spotify.music) 间无缝转换对我来说也大有帮助，这样我就永远不会错过我喜欢的音乐了。

![Spotify](/data/attachment/album/201902/12/165519aib06x1t6h4f6cfj.jpg "Audacious ")

*图五：Linux 上的 Spotify 官方客户端。*

Spotify 界面十分易于使用，事实上它完胜网页端的播放器。不要在 Linux 上装 [Spotify 网页播放器](https://open.spotify.com/browse/featured) 因为桌面客户端在创建管理你的播放列表方面简便得多。如果你是 Spotify 重度用户，甚至没必要用其他桌面应用的內建流传输客户端支持 —— 一旦你用过 Spotify 桌面客户端，其它应用就根本没可比性。

### 选择在你

其它选择也是有的（查看你的桌面软件中心），但这五款客户端（在我看来）是最好的了。对我来说，Clementine 和 Spotify 的组合拳就已经让我美好得唱赞歌了。尝试它们看看哪个能更好地满足你的需要。

### 额外奖品

虽然这篇文章翻译于国外作者，但作为给中国的 Linux 用户看的文章，如果在一篇分享音乐播放器的文章中**不提及**网易云音乐，那一定会被猛烈吐槽（事实上，我们曾经被吐槽过好多次了，哈哈）。

网易云音乐是我见过的最好的音乐播放器之一，不只是在 Linux 上，它甚至还支持包括 Windows、Mac、 iOS、安卓等在内的 8 个操作系统平台。当前的 Linux 版本是 1.1.0 版，支持 64 位的深度 Linux 15 和 Ubuntu 16.04 及之后的版本。下载地址和截图就不在这里安利了，大家想必自己能找到的。

通过 edX 和 Linux Foundation 上免费的 [Introduction to Linux](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)  课程学习更多有关 Linux 的知识。

---

via: <https://www.linux.com/learn/intro-to-linux/2017/12/top-5-linux-music-players>

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

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


极客漫画：增强现实（AR） 2.0

Summary: 增强现实技术（Augmented Reality），简称 AR，是一种实时地计算摄影机影像的位置及角度并加上相应图像、视频、3D 模型的技术，这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动。

完美的

来自重庆的 Microsoft Edge 18.18363|Windows 10 用户

![](/data/attachment/album/201902/10/092756llwc5ivckzcuzkyy.png)

最近这几年我们一直听到虚拟现实（VR）和增强现实（AR），可很多人并不了解它们是什么。<ruby> 增强现实技术 <rt>  Augmented Reality </rt></ruby>，简称 AR，是一种实时地计算摄影机影像的位置及角度并加上相应图像、视频、3D 模型的技术，这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动。

这种技术可以让你将现实世界和虚拟世界结合起来，从而创造非常有趣的互动效果。可是，有一天 AR 里面的小鬼们真的出来了！

---

via: <http://turnoff.us/geek/augmented-reality-2/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者 & 点评：[wxy](https://github.com/wxy) 校对 & 合成：[wxy](https://github.com/wxy)

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


开始使用 eDEX-UI 吧，一款受《电子世界争霸战》影响的终端程序

译者翻译这块可能有点不妥，eDEX-UI is a cross-platform terminal program designed for tablets and desktops

此处的tablets and desktops  应该是便携电脑和桌面电脑， 译者翻译tablets为平板电脑可能有误导，因为至少我没有找到该软件针对平板电脑的版本。谢谢

谢谢。我以为这里的平板电脑就是便携电脑，而不是类似 iPad 这样的？

好东西。酷！谢谢啦，谢谢啦！

>
> 使用 eDEX-UI 让你的工作更有趣，这是我们开源工具系列中的第 15 个工具，它将使你在 2019 年更高效。
>
>
>

![](/data/attachment/album/201902/10/222740fe2q0dh50999c024.jpg)

每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心，渴望开启新的一年，当然，“抛弃旧的，拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件，但事实上并不用这样。

这是我挑选出的 19 个新的（或者对你而言新的）开源工具中的第 15 个工具来帮助你在 2019 年更有效率。

### eDEX-UI

当[《电子世界争霸战》](https://en.wikipedia.org/wiki/Tron)上映时我才 11 岁。我不能否认，尽管这部电影充满幻想，但它对我后来的职业选择产生了影响。

![](/data/attachment/album/201902/10/222822wb2kc18kkkckoeod.png)

[eDEX-UI](https://github.com/GitSquared/edex-ui) 是一款专为平板电脑和台式机设计的跨平台终端程序，它的用户界面受到《电子世界争霸战》的启发。它在选项卡式界面中有五个终端，因此可以轻松地在任务之间切换，以及显示有用的系统信息。

在启动时，eDEX-UI 会启动一系列的东西，其中包含它所基于的 ElectronJS 系统的信息。启动后，eDEX-UI 会显示系统信息、文件浏览器、键盘（用于平板电脑）和主终端选项卡。其他四个选项卡（被标记为 EMPTY）没有加载任何内容，并且当你单击它时将启动一个 shell。eDEX-UI 中的默认 shell 是 Bash（如果在 Windows 上，则可能需要将其更改为 PowerShell 或 cmd.exe）。

![](/data/attachment/album/201902/10/222831y37psi3u3pozoool.png)

更改文件浏览器中的目录也将更改活动终端中的目录，反之亦然。文件浏览器可以执行你期望的所有操作，包括在单击文件时打开关联的应用。唯一的例外是 eDEX-UI 的 `settings.json` 文件（默认在 `.config/eDEX-UI`），它会打开配置编辑器。这允许你为终端设置 shell 命令、更改主题以及修改用户界面的其他几个设置。主题也保存在配置目录中，因为它们也是 JSON 文件，所以创建自定义主题非常简单。

![](/data/attachment/album/201902/10/222835ghtdlg9rn4gmi4go.png)

eDEX-UI 允许你使用完全仿真运行五个终端。默认终端类型是 xterm-color，这意味着它支持全色彩。需要注意的一点是，输入时键会亮起，因此如果你在平板电脑上使用 eDEX-UI，键盘可能会在人们看见屏幕的环境中带来安全风险。因此最好在这些设备上使用没有键盘的主题，尽管在打字时看起来确实很酷。

![](/data/attachment/album/201902/10/222840jnvod22gg80c8enj.png)

虽然 eDEX-UI 仅支持五个终端窗口，但这对我来说已经足够了。在平板电脑上，eDEX-UI 给了我网络空间感而不会影响我的效率。在桌面上，eDEX-UI 支持所有功能，并让我在我的同事面前显得很酷。

---

via: <https://opensource.com/article/19/1/productivity-tool-edex-ui>

作者：[Kevin Sonney](https://opensource.com/users/ksonney "Kevin Sonney") 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


计算机实验室之树莓派：课程 4 OK04

![](/data/attachment/album/201902/10/234202zj838rljquf9zy52.jpg)

OK04 课程在 OK03 的基础上进行构建，它教你如何使用定时器让 OK 或 ACT LED 灯按精确的时间间隔来闪烁。假设你已经有了 [课程 3：OK03](/article-10519-1.html) 的操作系统，我们将以它为基础来构建。

### 1、一个新设备

>
> 定时器是树莓派保持时间的唯一方法。大多数计算机都有一个电池供电的时钟，这样当计算机关机后仍然能保持时间。
>
>
>

到目前为止，我们仅看了树莓派硬件的一小部分，即 GPIO 控制器。我只是简单地告诉你做什么，然后它会发生什么事情。现在，我们继续看定时器，并继续带你去了解它的工作原理。

和 GPIO 控制器一样，定时器也有地址。在本案例中，定时器的基地址在 20003000 16。阅读手册我们可以找到下面的表：

表 1.1 GPIO 控制器寄存器

| 地址 | 大小 / 字节 | 名字 | 描述 | 读或写 |
| --- | --- | --- | --- | --- |
| 20003000 | 4 | Control / Status | 用于控制和清除定时器通道比较器匹配的寄存器 | RW |
| 20003004 | 8 | Counter | 按 1 MHz 的频率递增的计数器 | R |
| 2000300C | 4 | Compare 0 | 0 号比较器寄存器 | RW |
| 20003010 | 4 | Compare 1 | 1 号比较器寄存器 | RW |
| 20003014 | 4 | Compare 2 | 2 号比较器寄存器 | RW |
| 20003018 | 4 | Compare 3 | 3 号比较器寄存器 | RW |

![Flowchart of the system timer's operation](/data/attachment/album/201902/10/234424z0ded7vccy4zz8y2.png)

这个表只告诉我们一部分内容，在手册中描述了更多的字段。手册上解释说，定时器本质上是按每微秒将计数器递增 1 的方式来运行。每次它是这样做的，它将计数器的低 32 位（4 字节）与 4 个比较器寄存器进行比较，如果匹配它们中的任何一个，它更新 `Control/Status` 以反映出其中有一个是匹配的。

关于<ruby> 位 <rt>  bit </rt></ruby>、<ruby> 字节 <rt>  byte </rt></ruby>、<ruby> 位字段 <rt>  bit field </rt></ruby>、以及数据大小的更多内容如下：

>
> 一个位是一个单个的二进制数的名称。你可能还记得，一个单个的二进制数既可能是一个 1，也可能是一个 0。
>
>
> 一个字节是一个 8 位集合的名称。由于每个位可能是 1 或 0 这两个值的其中之一，因此，一个字节有 2 8 = 256 个不同的可能值。我们一般解释一个字节为一个介于 0 到 255（含）之间的二进制数。
>
>
> ![Diagram of GPIO function select controller register 0.](/data/attachment/album/201902/10/234240m932lb2ajbbgb8zj.png)
>
>
> 一个位字段是解释二进制的另一种方式。二进制可以解释为许多不同的东西，而不仅仅是一个数字。一个位字段可以将二进制看做为一系列的 1（开） 或 0（关）的开关。对于每个小开关，我们都有一个意义，我们可以使用它们去控制一些东西。我们已经遇到了 GPIO 控制器使用的位字段，使用它设置一个针脚的开或关。位为 1 时 GPIO 针脚将准确地打开或关闭。有时我们需要更多的选项，而不仅仅是开或关，因此我们将几个开关组合到一起，比如 GPIO 控制器的函数设置（如上图），每 3 位为一组控制一个 GPIO 针脚的函数。
>
>
>

我们的目标是实现一个函数，这个函数能够以一个时间数量为输入来调用它，这个输入的时间数量将作为等待的时间，然后返回。想一想如何去做，想想我们都拥有什么。

我认为这将有两个选择：

1. 从计数器中读取一个值，然后保持分支返回到相同的代码，直到计数器的等待时间数量大于它。
2. 从计数器中读取一个值，加上要等待的时间数量，将它保存到比较器寄存器，然后保持分支返回到相同的代码处，直到 `Control / Status` 寄存器更新。

这两种策略都工作的很好，但在本教程中，我们将只实现第一个。原因是比较器寄存器更容易出错，因为在增加等待时间并保存它到比较器的寄存器期间，计数器可能已经增加了，并因此可能会不匹配。如果请求的是 1 微秒（或更糟糕的情况是 0 微秒）的等待，这样可能导致非常长的意外延迟。

>
> 像这样存在被称为“并发问题”的问题，并且几乎无法解决。
>
>
>

### 2、实现

我将把这个创建完美的等待方法的挑战基本留给你。我建议你将所有与定时器相关的代码都放在一个名为 `systemTimer.s` 的文件中（理由很明显）。关于这个方法的复杂部分是，计数器是一个 8 字节值，而每个寄存器仅能保存 4 字节。所以，计数器值将分到 2 个寄存器中。

>
> 大型的操作系统通常使用等待函数来抓住机会在后台执行任务。
>
>
>

下列的代码块是一个示例。

```
ldrd r0,r1,[r2,#4]
```

>
> `ldrd regLow,regHigh,[src,#val]` 从 `src` 中的数加上 `val` 之和的地址加载 8 字节到寄存器 `regLow` 和 `regHigh` 中。
>
>
>

上面的代码中你可以发现一个很有用的指令是 `ldrd`。它加载 8 字节的内存到两个寄存器中。在本案例中，这 8 字节内存从寄存器 `r2` 中的地址 + 4 开始，将被复制进寄存器 `r0` 和 `r1`。这种安排的稍微复杂之处在于 `r1` 实际上只持有了高位 4 字节。换句话说就是，如果如果计数器的值是 999,999,999,999 10 = 1110100011010100101001010000111111111111 2 ，那么寄存器 `r1` 中只有 11101000 2，而寄存器 `r0` 中则是 11010100101001010000111111111111 2。

实现它的更明智的方式应该是，去计算当前计数器值与来自方法启动后的那一个值的差，然后将它与要求的等待时间数量进行比较。除非恰好你希望的等待时间是占用 8 字节的，否则上面示例中寄存器 `r1` 中的值将会丢弃，而计数器仅需要使用低位 4 字节。

当等待开始时，你应该总是确保使用大于比较，而不是使用等于比较，因为如果你尝试去等待一个时间，而这个时间正好等于方法开始的时间与结束的时间之差，那么你就错过这个值而永远等待下去。

如果你不明白如何编写等待函数的代码，可以参考下面的指南。

>
> 借鉴 GPIO 控制器的创意，第一个函数我们应该去写如何取得系统定时器的地址。示例如下：
>
>
>
> ```
> .globl GetSystemTimerBase
> GetSystemTimerBase:
> ldr r0,=0x20003000
> mov pc,lr
> ```
>
> 另一个被证明非常有用的函数是返回在寄存器 `r0` 和 `r1` 中的当前计数器值：
>
>
>
> ```
> .globl GetTimeStamp
> GetTimeStamp:
> push {lr}
> bl GetSystemTimerBase
> ldrd r0,r1,[r0,#4]
> pop {pc}
> ```
>
> 这个函数简单地使用了 `GetSystemTimerBase` 函数，并像我们前面学过的那样，使用 `ldrd` 去加载当前计数器值。
>
>
> 现在，我们可以去写我们的等待方法的代码了。首先，在该方法启动后，我们需要知道计数器值，我们可以使用 `GetTimeStamp` 来取得。
>
>
>
> ```
> delay .req r2
> mov delay,r0
> push {lr}
> bl GetTimeStamp
> start .req r3
> mov start,r0
> ```
>
> 这个代码复制了我们的方法的输入，将延迟时间的数量放到寄存器 `r2` 中，然后调用 `GetTimeStamp`，这个函数将会返回寄存器 `r0` 和 `r1` 中的当前计数器值。接着复制计数器值的低位 4 字节到寄存器 `r3` 中。
>
>
> 接下来，我们需要计算当前计数器值与读入的值的差，然后持续这样做，直到它们的差至少是 `delay` 的大小为止。
>
>
>
> ```
> loop$:
>
> bl GetTimeStamp
> elapsed .req r1
> sub elapsed,r0,start
> cmp elapsed,delay
> .unreq elapsed
> bls loop$
> ```
>
> 这个代码将一直等待，一直到等待到传递给它的时间数量为止。它从计数器中读取数值，减去最初从计数器中读取的值，然后与要求的延迟时间进行比较。如果过去的时间数量小于要求的延迟，它切换回 `loop$`。
>
>
>
> ```
> .unreq delay
> .unreq start
> pop {pc}
> ```
>
> 代码完成后，函数返回。
>
>
>

### 3、另一个闪灯程序

你一旦明白了等待函数的工作原理，修改 `main.s` 去使用它。修改各处 `r0` 的等待设置值为某个很大的数量（记住它的单位是微秒），然后在树莓派上测试。如果函数不能正常工作，请查看我们的排错页面。

如果正常工作，恭喜你学会控制另一个设备了，会使用它，则时间由你控制。在下一节课程中，我们将完成 OK 系列课程的最后一节 [课程 5：OK05](https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok05.html)，我们将使用我们已经学习过的知识让 LED 按我们的模式进行闪烁。

---

via: <https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok04.html>

作者：[Robert Mullins](http://www.cl.cam.ac.uk/%7Erdm34) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


将 Python 结合到数学教育中

>
> 身兼教师、开发者、作家数职的 Peter Farrell 来讲述为什么使用 Python 来讲数学课会比传统方法更加好。
>
>
>

![](/data/attachment/album/201902/11/151256px4rqt4maadgft2a.png)

数学课一直都是很讨厌的一件事情，尤其对于在传统教学方法上吃过苦头的人（例如我）来说。传统教学方法强调的是死记硬背和理论知识，这种形式与学生们的现实世界似乎相去甚远。

[Peter Farrell](https://twitter.com/hackingmath) 作为一位 Python 开发者和数学教师，发现学生在数学课程中遇到了困难，于是决定尝试使用 Python 来帮助介绍数学概念。

Peter 的灵感来源于 Logo 语言之父 [Seymour Papert](https://en.wikipedia.org/wiki/Seymour_Papert)，他的 Logo 语言现在还存在于 Python 的 [Turtle 模块](https://en.wikipedia.org/wiki/Turtle_graphics)中。Logo 语言中的海龟形象让 Peter 喜欢上了 Python，并且进一步将 Python 应用到数学教学中。

Peter 在他的新书《<ruby>   Python 数学奇遇记  <rt>  Math Adventures with Python </rt></ruby>》中分享了他的方法：“图文并茂地指导如何用代码探索数学”。因此我最近对他进行了一次采访，向他了解更多这方面的情况。

**Don Watkins（LCTT 译注：本文作者）：** 你的教学背景是什么？

**Peter Farrell：** 我曾经当过八年的数学老师，之后又做了十年的数学私教。我还在当老师的时候，就阅读过 Papert 的 《<ruby>   头脑风暴  <rt>  Mindstorms </rt></ruby>》并从中受到了启发，将 Logo 语言和海龟引入到了我所有的数学课上。

**DW：** 你为什么开始使用 Python 呢？

**PF：** 在我当家教的时候，需要教学一门枯燥刻板的数学课程，这是一个痛苦的过程。后来我引入了 Logo 语言和海龟，我的学生刚好是一个编程爱好者，他非常喜欢这样的方式。在接触到函数和实际的编程之后，他还提议改用 Python。尽管当时我还不了解 Python，但看起来好像和 Logo 语言差别不大，我就同意了。后来我甚至坚持在 Python 上一条道走到黑了！

我还曾经寻找过 3D 图形方面的软件包，用来模拟太阳系行星的运动轨迹，让学生们理解行星是如何在牛顿的万有引力定律作用下运动的。很多图形软件包都需要用到 C 语言编程或者其它一些很复杂的内容，后来我发现了一个叫做 VisualPython 的软件包，它非常方便使用。于是在那之后的几年里，我就一直在用 [Vpython](http://vpython.org/) 这个软件包。

所以，我是在和学生一起学习数学的时候被介绍使用 Python 的。在那段时间里，他是我的编程老师，而我则是他的数学老师。

**DW：** 是什么让你对数学感兴趣？

**PF：** 我是通过传统的方法学习数学的，那时候都是用手写、用纸记、在黑板上计算。我擅长代数和几何，在大学的时候也接触过 Basic 和 Fortran 编程，但那个时候也没有从中获取到灵感。直到后来在从编程中收到了启发，编程可以让你将数学课上一些晦涩难懂的内容变得简单直观，也能让你轻松地绘图、调整、探索，进而发现更多乐趣。

**DW：** 是什么启发了你使用 Python 教学？

**PF：** 还是在我当家教的时候，我惊奇地发现可以通过循环来计算对同一个函数输入不同参数的结果。如果用人手计算，可能要花半个小时的时间，但计算机瞬间就完成了。在这样的基础上，我们只要将一些计算的过程抽象成一个函数，再对其进行一些适当的扩展，就可以让计算机来计算了。

**DW：** 你的教学方法如何帮助学生，特别是在数学上感觉吃力的学生？如何将 Python 编程和数学结合起来

**PF：** 很多学生，尤其是高中生，都认为通过手工计算和画图来解决问题的方式在当今已经没有必要了，我并不反对这样的观点。例如，使用 Excel 来处理数据确实应该算是办公室工作的基本技能。学习任何一种编程语言，对公司来说都是一项非常有价值的技能。因此，使用计算机计算确实是有实际意义的。

而使用代码来为数学课创造艺术，则是一项革命性的改变。例如，仅仅是把某个形状显示到屏幕上，就需要使用到数学，因为位置需要用 x-y 坐标去表示，而尺寸、颜色等等都是数字。如果想要移动或者更改某些内容，会需要用到变量。更特殊地，如果需要改变位置，就需要更有效的向量来实现。这样的最终结果是，类似向量、矩阵这些难以捉摸的空洞概念会转变成实打实有意义的数学工具。

那些看起来在数学上吃力的学生，或许只是不太容易接受“书本上的数学”。因为“书本上的数学”过分强调了死记硬背和循规蹈矩，而有些忽视了创造力和实际应用能力。有些学生其实擅长数学，但并不适应学校的教学方式。我的方法会让父母们看到他们的孩子通过代码画出了很多有趣的图形，然后说：“我从来不知道正弦和余弦还能这样用！”

**DW：** 你的教学方法是如何在学校里促进 STEM 教育的呢？

**PF：** 我喜欢将这几个学科统称为 STEM（<ruby> 科学、技术、工程、数学 <rt>  Science, Technology, Engineering and Mathematics </rt></ruby>） 或 STEAM（<ruby> 科学、技术、工程、艺术、数学 <rt>  Science, Technology, Engineering, Art and Mathematics </rt></ruby>）。但作为数学工作者，我很不希望其中的 M 被忽视。我经常看到很多很小的孩子在 STEM 实验室里参与一些有趣的项目，这表明他们已经在接受科学、技术和工程方面的教育。与此同时，我发现数学方面的材料和项目却很少。因此，我和[机电一体化](https://en.wikipedia.org/wiki/Mechatronics)领域的优秀教师 Ken Hawthorn 正在着手解决这个问题。

希望我的书能够帮助鼓励学生们在技术上有所创新，无论在形式上是切实的还是虚拟的。同时书中还有很多漂亮的图形，希望能够激励大家去体验编程的过程，并且应用到实际中来。我使用的软件（[Python Processing](https://processing.org/)）是免费的，在树莓派等系统上都可以轻松安装。因为我认为，个人或者学校的成本问题不应该成为学生进入 STEM 世界的门槛。

**DW：** 你有什么想要跟其他的数学老师分享？

**PF：** 如果数学教学机构决定要向学生教导数字推理、逻辑、分析、建模、几何、数据解释这些内容，那么它们应该承认，可以通过编程来实现这些目标。正如我上面所说的，我的教学方法是在尝试使传统枯燥的方法变得直观，我认为任何一位老师都可以做到这一点。他们只需要知道其中的本质做法，就可以使用代码来完成大量重复的工作了。

我的教学方法依赖于一些免费的图形软件，因此只需要知道在哪里找到这些软件包，以及如何使用这些软件包，就可以开始引导学生使用 21 世纪的技术来解决实际问题，将整个过程和结果可视化，并找到更多可以以此实现的模式。

---

via: <https://opensource.com/article/19/1/hacking-math>

作者：[Don Watkins](https://opensource.com/users/don-watkins) 选题：[lujun9972](https://github.com/lujun9972) 译者：[HankChow](https://github.com/HankChow) 校对：[wxy](https://github.com/wxy)

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


推荐一款社区驱动的 Linux 命令速查小程序

非常感谢。

请问怎么获得邀请码？

请在我们的微信公众号里面获得

挺不错的，赞一个

挺不错的，赞一个

挺不错的，赞一个

挺不错的，赞一个

不明白这东西做个 小程序出来有什么应用场景？

不明白这东西做个 小程序出来有什么应用场景？

不明白这东西做个 小程序 出来有什么应用场景？

不明白这东西做个 小程序 出来有什么应用场景？

为什么不做一个web网页出来，这样开发才方便使用啊

![](/data/attachment/album/201902/12/114740l7q5zq0l79b3qq9k.jpg)

学习和使用 Linux 时，你是否觉得 Linux 命令的 man 手册过于冗长，不能及时告诉你所需要的命令该怎么写？其实，遇到这种苦恼的不是你一个人，往往在你突然想不起某个命令参数时，你需要的就是一个简单的命令提示。所以，针对这种情况，有人开发出了 `info` 命令来补充丰富的命令案例，也有人觉得 man 手册实在太长了，开发出了 `tldr` （太长不看）命令来提供更简洁的最常用命令用法。

就如我们之前[介绍](/article-10355-1.html)过的，`tldr` 有很多客户端，支持命令行、Web、iOS、安卓等等。

经过一个春节的开发，在“编码使我快乐”的 Bestony 同学的努力下，我们基于 tldr 的数据推出了一款小程序版的 tldr，并且考虑到现有 tldr 数据以英文为主，还提供了由社区驱动的开放式翻译模式来改进内容。

下面我来介绍一下。

### Linux 命令速查小程序

请用微信识别如下小程序码，找到小程序 “Linux” ——没错，这个名字就是这么直指人心 :D，你也可以在本公众号的菜单中找到它。此外，以后我们也会在推送的文章中，对出现的 Linux 命令直接链接其这个小程序。

![](/data/attachment/album/201902/12/114758bm05oquu813rmwrq.jpg)

*扫描或长按识别*

首页就是一个简洁的输入框，显然，输入你要查找的命令就行。目前我们已经收录了 TLDR 数据库中上千条命令的数据。

![](/data/attachment/album/201902/12/114904kky626sskk172zkl.jpeg)

*Linux 命令速查小程序 首页*

![](/data/attachment/album/201902/12/114947f90mhz59t999nn8u.jpeg)

*Linux 命令速查 ls 页面*

### 开放式翻译贡献

你可以看到，命令页面的下方，列出了对该页面做出了翻译贡献的贡献者头像。

这其中大部分命令还没有进行翻译。你可以长按待翻译的文本，跳到翻译输入页面。在输入框中，可以输入新的翻译。第一次提交会请求你的微信授权，只是为了显示你的名字和头像。

![](/data/attachment/album/201902/12/115037x24xusz5rt5wd4vt.jpeg)

*提交翻译贡献*

下方还列出了历次翻译的历史，所以你的贡献是所有人都看得到的 —— 切勿胡乱提交。输入翻译提交之后，会返回该命令页面，你可以下拉该页面强制刷新，即可看到翻译效果。

为什么采用开放式翻译贡献模式呢？我们希望社区的项目，由社区来驱动，通过社区的自我进化能力来完善。这也是我们为之后的社区驱动项目做一个尝试。

希望这个触手可及的小程序可以帮到你。好了，这篇 TLDR 的文章就这么短吧~

最后，致谢 [TLDR 项目](https://tldr.sh/)，感谢 Bestony。另外，能够快速开发此小程序也要感谢腾讯云开发所提供的快捷开发支持。


Bash 中尖括号的更多用法

Summary: 在这篇文章，我们继续来深入探讨尖括号的更多其它用法。

在这篇文章，我们继续来深入探讨尖括号的更多其它用法。

>
> 在这篇文章，我们继续来深入探讨尖括号的更多其它用法。
>
>
>

![](/data/attachment/album/201902/12/115848wemcebuym6mlsuwm.png)

在[上一篇文章](/article-10502-1.html)当中，我们介绍了尖括号（`<>`）以及它们的一些用法。在这篇文章，我们继续来深入探讨尖括号的更多其它用法。

通过使用 `<`，可以实现“欺骗”的效果，让其它命令认为某个命令的输出是一个文件。

例如，在进行备份文件的时候不确定备份是否完整，就需要去确认某个目录是否已经包含从原目录中复制过去的所有文件。你可以试一下这样操作：

```
diff <(ls /original/dir/) <(ls /backup/dir/)
```

[diff](https://linux.die.net/man/1/diff) 命令是一个逐行比较两个文件之间差异的工具。在上面的例子中，就使用了 `<` 让 `diff` 认为两个 `ls` 命令输出的结果都是文件，从而能够比较它们之间的差异。

要注意，在 `<` 和 `(...)` 之间是没有空格的。

我尝试在我的图片目录和它的备份目录执行上面的命令，输出的是以下结果：

```
diff <(ls /My/Pictures/) <(ls /My/backup/Pictures/)
5d4 < Dv7bIIeUUAAD1Fc.jpg:large.jpg
```

输出结果中的 `<` 表示 `Dv7bIIeUUAAD1Fc.jpg:large.jpg` 这个文件存在于左边的目录（`/My/Pictures`）但不存在于右边的目录（`/My/backup/Pictures`）中。也就是说，在备份过程中可能发生了问题，导致这个文件没有被成功备份。如果 `diff` 没有显示出任何输出结果，就表明两个目录中的文件是一致的。

看到这里你可能会想到，既然可以通过 `<` 将一些命令行的输出内容作为一个文件提供给一个需要接受文件格式的命令，那么在上一篇文章的“最喜欢的演员排序”例子中，就可以省去中间的一些步骤，直接对输出内容执行 `sort` 操作了。

确实如此，这个例子可以简化成这样：

```
sort -r <(while read -r name surname films;do echo $films $name $surname ; done < CBactors)
```

### Here 字符串

除此以外，尖括号的重定向功能还有另一种使用方式。

使用 `echo` 和管道（`|`）来传递变量的用法，相信大家都不陌生。假如想要把一个字符串变量转换为全大写形式，你可以这样做：

```
myvar="Hello World" echo $myvar | tr '[:lower:]' '[:upper:]' HELLO WORLD
```

[tr](https://linux.die.net/man/1/tr) 命令可以将一个字符串转换为某种格式。在上面的例子中，就使用了 `tr` 将字符串中的所有小写字母都转换为大写字母。

要理解的是，这个传递过程的重点不是变量，而是变量的值，也就是字符串 `Hello World`。这样的字符串叫做 HERE 字符串，含义是“这就是我们要处理的字符串”。但对于上面的例子，还可以用更直观的方式的处理，就像下面这样：

```
tr '[:lower:]' '[:upper:]' <<< $myvar
```

这种简便方式并不需要使用到 `echo` 或者管道，而是使用了我们一直在说的尖括号。

### 总结

使用 `<` 和 `>` 这两个简单的符号，原来可以实现这么多功能，Bash 又一次为工作的灵活性提供了很多选择。

当然，我们的介绍还远远没有完结，因为还有很多别的符号可以为 Bash 命令带来更多便利。不过如果没有充分理解它们，充满符号的 Bash 命令看起来只会像是一堆乱码。接下来我会解读更多类似的 Bash 符号，下次见！

---

via: <https://www.linux.com/blog/learn/2019/1/more-about-angle-brackets-bash>

作者：[Paul Brown](https://www.linux.com/users/bro66) 选题：[lujun9972](https://github.com/lujun9972) 译者：[HankChow](https://github.com/HankChow) 校对：[wxy](https://github.com/wxy)

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


计算机实验室之树莓派：课程 5 OK05

cool

来自山东临沂的 Opera Mobile 48.2|Android 7.1 用户

![](/data/attachment/album/201902/12/122809f73x8z1xl73xhhm7.jpg)

OK05 课程构建于课程 OK04 的基础，使用它来闪烁摩尔斯电码的 SOS 序列（`...---...`）。这里假设你已经有了 [课程 4：OK04](/article-10526-1.html) 操作系统的代码作为基础。

### 1、数据

到目前为止，我们与操作系统有关的所有内容提供的都是指令。然而有时候，指令只是完成了一半的工作。我们的操作系统可能还需要数据。

>
> 一些早期的操作系统确实只允许特定文件中的特定类型的数据，但是这通常被认为限制太多了。现代方法确实可以使程序变得复杂的多。
>
>
>

通常，数据就是些很重要的值。你可能接受过培训，认为数据就是某种类型的，比如，文本文件包含文本，图像文件包含图片，等等。说实话，这只是你的想法而已。计算机上的全部数据都是二进制数字，重要的是我们选择用什么来解释这些数据。在这个例子中，我们会用一个闪灯序列作为数据保存下来。

在 `main.s` 结束处复制下面的代码：

```
.section .data %定义 .data 段
.align 2 %对齐
pattern: %定义整形变量
.int 0b11111111101010100010001000101010
```

>
> `.align num` 确保下一行代码的地址是 2 num 的整数倍。
>
>
> `.int val` 输出数值 `val`。
>
>
>

要区分数据和代码，我们将数据都放在 `.data` 区域。我已经将该区域包含在操作系统的内存布局图。我选择将数据放到代码后面。将我们的指令和数据分开保存的原因是，如果最后我们在自己的操作系统上实现一些安全措施，我们就需要知道代码的那些部分是可以执行的，而那些部分是不行的。

我在这里使用了两个新命令 `.align` 和 `.int`。`.align` 保证接下来的数据是按照 2 的乘方对齐的。在这个里，我使用 `.align 2` ，意味着数据最终存放的地址是 2 2=4 的整数倍。这个操作是很重要的，因为我们用来读取内存的指令 `ldr` 要求内存地址是 4 的倍数。

命令 `.int` 直接复制它后面的常量到输出。这意味着 11111111101010100010001000101010 2 将会被存放到输出，所以该标签模式实际是将这段数据标识为模式。

>
> 关于数据的一个挑战是寻找一个高效和有用的展示形式。这种保存一个开、关的时间单元的序列的方式，运行起来很容易，但是将很难编辑，因为摩尔斯电码的 `-` 或 `.` 样式丢失了。
>
>
>

如我提到的，数据可以代表你想要的所有东西。在这里我编码了摩尔斯电码的 SOS 序列，对于不熟悉的人，就是 `...---...`。我使用 0 表示一个时间单元的 LED 灭灯，而 1 表示一个时间单元的 LED 亮。这样，我们可以像这样编写一些代码在数据中显示一个序列，然后要显示不同序列，我们所有需要做的就是修改这段数据。下面是一个非常简单的例子，操作系统必须一直执行这段程序，解释和展示数据。

复制下面几行到 `main.s` 中的标记 `loop$` 之前。

```
ptrn .req r4 %重命名 r4 为 ptrn
ldr ptrn,=pattern %加载 pattern 的地址到 ptrn
ldr ptrn,[ptrn] %加载地址 ptrn 所在内存的值
seq .req r5 %重命名 r5 为 seq
mov seq,#0 %seq 赋值为 0
```

这段代码加载 `pattrern` 到寄存器 `r4`，并加载 0 到寄存器 `r5`。`r5` 将是我们的序列位置，所以我们可以追踪我们已经展示了多少个 `pattern`。

如果 `pattern` 的当前位置是 1 且仅有一个 1，下面的代码将非零值放入 `r1`。

```
mov r1,#1 %加载1到 r1
lsl r1,seq %对r1 的值逻辑左移 seq 次
and r1,ptrn %按位与
```

这段代码对你调用 `SetGpio` 很有用，它必须有一个非零值来关掉 LED，而一个 0 值会打开 LED。

现在修改 `main.s` 中你的全部代码，这样代码中每次循环会根据当前的序列数设置 LED，等待 250000 毫秒（或者其他合适的延时），然后增加序列数。当这个序列数到达 32 就需要返回 0。看看你是否能实现这个功能，作为额外的挑战，也可以试着只使用一条指令。

### 2、当你玩得开心时，时间过得很快

你现在准备好在树莓派上实验。应该闪烁一串包含 3 个短脉冲，3 个长脉冲，然后 3 个短脉冲的序列。在一次延时之后，这种模式应该重复。如果这不工作，请查看我们的问题页。

一旦它工作，祝贺你已经抵达 OK 系列教程的结束点。

在这个系列我们学习了汇编代码，GPIO 控制器和系统定时器。我们已经学习了函数和 ABI，以及几个基础的操作系统原理，已经关于数据的知识。

你现在已经可以准备学习下面几个更高级的课程的某一个。

* [Screen](https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html) 系列是接下来的，会教你如何通过汇编代码使用屏幕。
* [Input](https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input01.html) 系列教授你如何使用键盘和鼠标。

到现在，你已经有了足够的信息来制作操作系统，用其它方法和 GPIO 交互。如果你有任何机器人工具，你可能会想尝试编写一个通过 GPIO 管脚控制的机器人操作系统。

---

via: <https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok05.html>

作者：[Robert Mullins](http://www.cl.cam.ac.uk/%7Erdm34) 选题：[lujun9972](https://github.com/lujun9972) 译者：[ezio](https://github.com/oska874) 校对：[wxy](https://github.com/wxy)

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


在 Linux 命令行使用 more 查看文本文件

>
> 文本文件和 Linux 一直是携手并进的。或者说看起来如此。那你又是依靠哪些让你使用起来很舒服的工具来查看这些文本文件的呢？
>
>
>

![](/data/attachment/album/201902/12/200602ci4sw6jj5r6vvo7j.jpg)

Linux 下有很多实用工具可以让你在终端界面查看文本文件。其中一个就是 [more](https://en.wikipedia.org/wiki/More_(command))。

`more` 跟我之前另一篇文章里写到的工具 —— [less](https://opensource.com/article/18/4/using-less-view-text-files-command-line) 很相似。它们之间的主要不同点在于 `more` 只允许你向前查看文件。

尽管它能提供的功能看起来很有限，不过它依旧有很多有用的特性值得你去了解。下面让我们来快速浏览一下 `more` 可以做什么，以及如何使用它吧。

### 基础使用

假设你现在想在终端查看一个文本文件。只需打开一个终端，进入对应的目录，然后输入以下命令：

```
$ more <filename>
```

例如，

```
$ more jekyll-article.md
```

![](/data/attachment/album/201902/12/200605qhljjl1t0yfavy44.png)

使用空格键可以向下翻页，输入 `q` 可以退出。

如果你想在这个文件中搜索一些文本，输入 `/` 字符并在其后加上你想要查找的文字。例如你要查看的字段是 “terminal”，只需输入：

```
/terminal
```

![](/data/attachment/album/201902/12/200609pu62gjq2j928j7h7.png)

搜索的内容是区分大小写的，所以输入 `/terminal` 跟 `/Terminal` 会出现不同的结果。

### 和其他实用工具组合使用

你可以通过管道将其他命令行工具得到的文本传输到 `more`。你问为什么这样做？因为有时这些工具获取的文本会超过终端一页可以显示的限度。

想要做到这个，先输入你想要使用的完整命令，后面跟上管道符（`|`），管道符后跟 `more`。假设现在有一个有很多文件的目录。你就可以组合 `more` 跟 `ls` 命令完整查看这个目录当中的内容。

```
$ ls | more
```

![](/data/attachment/album/201902/12/200613o1hxn0ih00c10ld1.png)

你可以组合 `more` 和 `grep` 命令，从而实现在多个文件中找到指定的文本。下面是我在多篇文章的源文件中查找 “productivity” 的例子。

```
$ grep ‘productivity’ core.md Dict.md lctt2014.md lctt2016.md lctt2018.md README.md | more
```

![](/data/attachment/album/201902/12/200627svpwypo4e0w5w1hl.png)

另外一个可以和 `more` 组合的实用工具是 `ps`（列出你系统上正在运行的进程）。当你的系统上运行了很多的进程，你现在想要查看他们的时候，这个组合将会派上用场。例如你想找到一个你需要杀死的进程，只需输入下面的命令：

```
$ ps -u scott | more
```

注意用你的用户名替换掉 “scott”。

![](/data/attachment/album/201902/12/200635ur462km0gk3pfpt7.png)

就像我文章开篇提到的， `more` 很容易使用。尽管不如它的双胞胎兄弟 `less` 那般灵活，但是仍然值得了解一下。

---

via: <https://opensource.com/article/19/1/more-text-files-linux>

作者：[Scott Nesbitt](https://opensource.com/users/scottnesbitt) 选题：[lujun9972](https://github.com/lujun9972) 译者：[dianbanjiu](https://github.com/dianbanjiu) 校对：[wxy](https://github.com/wxy)

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


PyGame Zero: 无需模板的游戏开发

Summary: 在你的游戏开发过程中有了 PyGame Zero，和枯燥的模板说再见吧。

在你的游戏开发过程中有了 PyGame Zero，和枯燥的模板说再见吧。

>
> 在你的游戏开发过程中有了 PyGame Zero，和枯燥的模板说再见吧。
>
>
>

![](/data/attachment/album/201902/12/225929m2fnq02x2yvyyhiq.png)

Python 是一个很好的入门级编程语言。并且，游戏是一个很好的入门项目：它们是可视化的，自驱动的，并且可以很愉快的与朋友和家人分享。虽然，绝大多数的 Python 写就的库，比如 [PyGame](https://www.pygame.org/news) ，会让初学者因为忘记微小的细节很容易导致什么都没渲染而感到困扰。

在理解所有部分的作用之前，他们会将其中的许多部分都视为“无意识的模板文件”——需要复制和粘贴到程序中才能使其工作的神奇段落。

[PyGame Zero](https://pygame-zero.readthedocs.io/en/stable/) 试图通过在 PyGame 上放置一个抽象层来弥合这一差距，因此它字面上并不需要模板。

我们在说的“字面”，就是在指字面。

这是一个合格的 PyGame Zero 文件：

```
# This comment is here for clarity reasons
```

我们可以将它放在一个 `game.py` 文件里，并运行：

```
$ pgzrun game.py
```

这将会展示一个窗口，并运行一个可以通过关闭窗口或按下 `CTRL-C` 中断的游戏循环。

遗憾的是，这将是一场无聊的游戏。什么都没发生。

为了让它更有趣一点，我们可以画一个不同的背景：

```
def draw():
    screen.fill((255, 0, 0))
```

这将会把背景色从黑色换为红色。但是这仍是一个很无聊的游戏，什么都没发生。我们可以让它变的更有意思一点：

```
colors = [0, 0, 0]

def draw():
    screen.fill(tuple(colors))

def update():
    colors[0] = (colors[0] + 1) % 256
```

这将会让窗口从黑色开始，逐渐变亮，直到变为亮红色，再返回黑色，一遍一遍循环。

`update` 函数更新了参数的值，而 `draw` 基于这些参数渲染这个游戏。

即使是这样，这里也没有任何方式给玩家与这个游戏的交互的方式。让我们试试其他一些事情：

```
colors = [0, 0, 0]

def draw():
    screen.fill(tuple(colors))

def update():
    colors[0] = (colors[0] + 1) % 256

def on_key_down(key, mod, unicode):
    colors[1] = (colors[1] + 1) % 256
```

现在，按下按键来提升亮度。

这些包括游戏循环的三个重要部分：响应用户输入，更新参数和重新渲染屏幕。

PyGame Zero 提供了更多功能，包括绘制精灵图和播放声音片段的功能。

试一试，看看你能想出什么类型的游戏！

---

via: <https://opensource.com/article/19/1/pygame-zero>

作者：[Moshe Zadka](https://opensource.com/users/moshez) 选题：[lujun9972](https://github.com/lujun9972) 译者：[bestony](https://github.com/bestony) 校对：[wxy](https://github.com/wxy)

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


DNS 和根证书

Summary: 关于 DNS 和根证书你需要了解的内容。

关于 DNS 和根证书你需要了解的内容。

>
> 关于 DNS 和根证书你需要了解的内容。
>
>
>

![](/data/attachment/album/201902/13/130526ey8rimkhhqoht6or.jpg)

由于最近发生的一些事件，我们（Privacy Today 组织）感到有必要写一篇关于此事的短文。它适用于所有读者，因此它将保持简单 —— 技术细节可能会在稍后的文章发布。

### 什么是 DNS，为什么它与你有关？

DNS 的意思是<ruby> 域名系统 <rt>  Domain Name System </rt></ruby>，你每天都会接触到它。每当你的 Web 浏览器或任何其他应用程序连接到互联网时，它就很可能会使用域名。简单来说，域名就是你键入的地址：例如 [duckduckgo.com](https://duckduckgo.com)。你的计算机需要知道它所导向的地方，会向 DNS 解析器寻求帮助。而它将返回类似 [176.34.155.23](http://176.34.155.23) 这样的 IP —— 这就是连接时所需要知道的公开网络地址。 此过程称为 DNS 查找。

这对你的隐私、安全以及你的自由都有一定的影响：

#### 隐私

由于你要求解析器获取域名的 IP，因此它会确切地知道你正在访问哪些站点，并且由于“物联网”（通常缩写为 IoT），甚至它还知道你在家中使用的是哪个设备。

#### 安全

你可以相信解析器返回的 IP 是正确的。有一些检查措施可以确保如此，在正常情况下这一般不是问题。但这些可能措施会被破坏，这就是写作本文的原因。如果返回的 IP 不正确，你可能会被欺骗引向了恶意的第三方 —— 甚至你都不会注意到任何差异。在这种情况下，你的隐私会受到更大的危害，因为不仅会被跟踪你访问了什么网站，甚至你访问的内容也会被跟踪。第三方可以准确地看到你正在查看的内容，收集你输入的个人信息（例如密码）等等。你的整个身份可以轻松接管。

#### 自由

审查通常是通过 DNS 实施的。这不是最有效的方法，但它非常普遍。即使在西方国家，它也经常被公司和政府使用。他们使用与潜在攻击者相同的方法；当你查询 IP 地址时，他们不会返回正确的 IP。他们可以表现得就好像某个域名不存在，或完全将访问指向别处。

### DNS 查询的方式

#### 由你的 ISP 提供的第三方 DNS 解析器

大多数人都在使用由其互联网接入提供商（ISP）提供的第三方解析器。当你连接调制解调器时（LCTT 译注：或宽带路由器），这些 DNS 解析器就会被自动取出，而你可能从来没注意过它。

#### 你自己选择的第三方 DNS 解析器

如果你已经知道 DNS 意味着什么，那么你可能会决定使用你选择的另一个 DNS 解析器。这可能会改善这种情况，因为它使你的 ISP 更难以跟踪你，并且你可以避免某些形式的审查。尽管追踪和审查仍然是可能的，但这种方法并没有被广泛使用。

#### 你自己（本地）的 DNS 解析器

你可以自己动手，避免使用别人的 DNS 解析器的一些危险。如果你对此感兴趣，请告诉我们。

### 根证书

#### 什么是根证书？

每当你访问以 https 开头的网站时，你都会使用它发送的证书与之通信。它使你的浏览器能够加密通信并确保没有人可以窥探。这就是为什么每个人都被告知在登录网站时要注意 https（而不是 http）。证书本身仅用于验证是否为某个域所生成。以及：

这就是根证书的来源。可以其视为一个更高的级别，用来确保其下的级别是正确的。它验证发送给你的证书是否已由证书颁发机构授权。此权限确保创建证书的人实际上是真正的运营者。

这也被称为信任链。默认情况下，你的操作系统包含一组这些根证书，以确保该信任链的存在。

#### 滥用

我们现在知道：

* DNS 解析器在你发送域名时向你发送 IP 地址
* 证书允许加密你的通信，并验证它们是否为你访问的域生成
* 根证书验证该证书是否合法，并且是由真实站点运营者创建的

**怎么会被滥用呢？**

* 如前所述，恶意 DNS 解析器可能会向你发送错误的 IP 以进行审查。它们还可以将你导向完全不同的网站。
* 这个网站可以向你发送假的证书。
* 恶意的根证书可以“验证”此假证书。

对你来说，这个网站看起来绝对没问题；它在网址中有 https，如果你点击它，它会说已经通过验证。就像你了解到的一样，对吗？**不对！**

它现在可以接收你要发送给原站点的所有通信。这会绕过想要避免被滥用而创建的检查。你不会收到错误消息，你的浏览器也不会发觉。

**而你所有的数据都会受到损害！**

### 结论

#### 风险

* 使用恶意 DNS 解析器总是会损害你的隐私，但只要你注意 https，你的安全性就不会受到损害。
* 使用恶意 DNS 解析程序和恶意根证书，你的隐私和安全性将完全受到损害。

#### 可以采取的动作

**不要安装第三方根证书！**只有非常少的例外情况才需要这样做，并且它们都不适用于一般最终用户。

**不要被那些“广告拦截”、“军事级安全”或类似的东西营销噱头所吸引**。有一些方法可以自行使用 DNS 解析器来增强你的隐私，但安装第三方根证书永远不会有意义。你正在将自己置身于陷阱之中。

### 实际看看

**警告**

有位友好的系统管理员提供了一个现场演示，你可以实时看到自己。这是真事。

**千万不要输入私人数据！之后务必删除证书和该 DNS！**

如果你不知道如何操作，那就不要安装它。虽然我们相信我们的朋友，但你不要随便安装随机和未知的第三方根证书。

#### 实际演示

链接在这里：<http://https-interception.info.tm/>

* 设置所提供的 DNS 解析器
* 安装所提供的根证书
* 访问 <https://paypal.com> 并输入随机登录数据
* 你的数据将显示在该网站上

### 延伸信息

如果你对更多技术细节感兴趣，请告诉我们。如果有足够多感兴趣的人，我们可能会写一篇文章，但是目前最重要的部分是分享基础知识，这样你就可以做出明智的决定，而不会因为营销和欺诈而陷入陷阱。请随时提出对你很关注的其他主题。

这篇文章来自 [Privacy Today 频道](https://t.me/privacytoday)。[Privacy Today](https://t.me/joinchat/Awg5A0UW-tzOLX7zMoTDog) 是一个关于隐私、开源、自由哲学等所有事物的组织！

所有内容均根据 CC BY-NC-SA 4.0 获得许可。（[署名 - 非商业性使用 - 共享 4.0 国际](https://creativecommons.org/licenses/by-nc-sa/4.0/)）。

---

via: <https://lushka.al/dns-and-certificates/>

作者：[Anxhelo Lushka](https://lushka.al/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


5 个用于开发工作的 Linux 发行版

Summary: 这五个发行版用于开发工作将不会让你失望。

这五个发行版用于开发工作将不会让你失望。

>
> 这五个发行版用于开发工作将不会让你失望。
>
>
>

![](/data/attachment/album/201902/13/231359c5z9gw9vszdfz5gz.jpg)

Linux 上最受欢迎的任务之一肯定是开发。理由很充分：业务依赖于 Linux。没有 Linux，技术根本无法满足当今不断发展的世界的需求。因此，开发人员不断努力改善他们的工作环境。而进行此类改善的一种方法就是拥有合适的平台。值得庆幸的是，这就是 Linux，所以你总是有很多选择。

但有时候，太多的选择本身就是一个问题。哪种发行版适合你的开发需求？当然，这取决于你正在开发的工作，但某些发行版更适合作为你的工作任务的基础。我将重点介绍我认为 2019 年最适合开发人员的五个发行版。

### Ubuntu

无需赘言。虽然 Linux Mint 的忠实用户无疑是一个非常忠诚的群体（这是有充分的理由的，他们选择的发行版很棒），但 Ubuntu Linux 在这里更被认可。为什么？因为有像 [AWS](https://aws.amazon.com/) 这样的云服务商存在，Ubuntu 成了部署最多的服务器操作系统之一。这意味着在 Ubuntu 桌面发行版上进行开发可以更轻松地转换为 Ubuntu Server。而且因为 Ubuntu 使得开发、使用和部署容器非常容易，所以你想要使用这个平台是完全合理的。而 Ubuntu 与其包含的 Snap 软件包相结合，使得这个 Canonical（Ubuntu 发行版背后的公司）的操作系统如虎添翼。

但这不仅是你可以用 Ubuntu 做什么，而是你可以轻松做到。几乎对于所有的任务，Ubuntu 都是一个非常易用的发行版。而且因为 Ubuntu 如此受欢迎，所以你可以从 Ubuntu “软件” 应用的图形界面里轻松安装你想要使用的每个工具和 IDE（图 1）。

![Ubuntu](/data/attachment/album/201902/13/231408d91ld1zy76d4dp9y.jpg "Ubuntu")

*图 1：可以在 Ubuntu “软件”工具里面找到开发者工具。*

如果你正在寻求易用、易于迁移，以及大量的工具，那么将 Ubuntu 作为开发平台就不会有错。

### openSUSE

我将 openSUSE 添加到此列表中有一个非常具体的原因。它不仅是一个出色的桌面发行版，它还是市场上最好的滚动发行版之一。因此，如果你希望用最新的软件开发、发布最新的软件，[openSUSE Tumbleweed](https://en.opensuse.org/Portal:Tumbleweed) 应该是你的首选之一。如果你想使用最喜欢的 IDE 的最新版本，如果你总是希望确保使用最新的库和工具包进行开发，那么 Tumbleweed 就是你的平台。

但 openSUSE 不仅提供滚动发布版本。如果你更愿意使用标准发行版，那么 [openSUSE Leap](https://en.opensuse.org/Portal:Leap) 就是你想要的。

当然，它不仅有标准版或滚动版，openSUSE 平台还有一个名为 [Kubic](https://software.opensuse.org/distributions/tumbleweed) 的 Kubernetes 特定版本，该版本基于 openSUSE MicroOS 上的 Kubernetes。但即使你没有为 Kubernetes 进行开发，你也会发现许多软件和工具可供使用。

openSUSE 还提供了选择桌面环境的能力，或者你也可以选择通用桌面或服务器（图 2）。

![openSUSE](/data/attachment/album/201902/13/231417fi2xhcc72hchz7oh.jpg "openSUSE")

*图 2： 正在安装 openSUSE Tumbleweed。*

### Fedora

使用 Fedora 作为开发平台才有意义。为什么？这个发行版本身似乎是面向开发人员的。通过定期的六个月发布周期，开发人员可以确保他们不会一直使用过时的软件。当你需要最新的工具和库时，这很重要。如果你正在开发企业级业务，Fedora 是一个理想的平台，因为它是红帽企业 Linux（RHEL）的上游。这意味着向 RHEL 的过渡应该是无痛的。这一点很重要，特别是如果你希望将你的项目带到一个更大的市场（一个比以桌面为中心的目标更深的领域）。

Fedora 还提供了你将体验到的最佳 GNOME 体验之一（图 3）。换言之，这是非常稳定和快速的桌面。

![GNOME](/data/attachment/album/201902/13/231430opgj7cpz941a9pyw.jpg "GNOME")

*图 3：Fedora 上的 GNOME 桌面。*

但是如果 GNOME 不是你的菜，你还可以选择安装一个 [Fedora 花样版](https://spins.fedoraproject.org/)（包括 KDE、XFCE、LXQT、Mate-Compiz、Cinnamon、LXDE 和 SOAS 等桌面环境）。

### Pop!\_OS

如果这个列表中我没有包括 [System76](https://system76.com/) 平台专门为他们的硬件定制的操作系统（虽然它也在其他硬件上运行良好），那我算是失职了。为什么我要包含这样的发行版，尤其是它还并未远离其所基于的 Ubuntu 平台？主要是因为如果你计划从 System76 购买台式机或笔记本电脑，那它就是你想要的发行版。但是你为什么要这样做呢（特别是考虑到 Linux 几乎适用于所有现成的硬件）？因为 System76 销售的出色硬件。随着他们的 Thelio 桌面的发布，这是你可以使用的市场上最强大的台式计算机之一。如果你正在努力开发大型应用程序（特别是那些非常依赖于非常大的数据库或需要大量处理能力进行编译的应用程序），为什么不用最好的计算机呢？而且由于 Pop!\_OS 完全适用于 System76 硬件，因此这是一个明智的选择。

由于 Pop!\_OS 基于 Ubuntu，因此你可以轻松获得其所基于的 Ubuntu 可用的所有工具（图 4）。

![Pop!_OS](/data/attachment/album/201902/13/231432ah5tuv56xtdpu883.jpg "Pop!_OS")

*图 4：运行在 Pop!\_OS 上的 Anjunta IDE*

Pop!\_OS 也会默认加密驱动器，因此你可以放心你的工作可以避免窥探（如果你的硬件落入坏人之手）。

### Manjaro

对于那些喜欢在 Arch Linux 上开发，但不想经历安装和使用 Arch Linux 的所有环节的人来说，那选择就是 Manjaro。Manjaro 可以轻松地启动和运行一个基于 Arch Linux 的发行版（就像安装和使用 Ubuntu 一样简单）。

但是 Manjaro 对开发人员友好的原因（除了享受 Arch 式好处）是你可以下载好多种不同口味的桌面。从[Manjaro 下载页面](https://manjaro.org/download/) 中，你可以获得以下口味：

* GNOME
* XFCE
* KDE
* OpenBox
* Cinnamon
* I3
* Awesome
* Budgie
* Mate
* Xfce 开发者预览版
* KDE 开发者预览版
* GNOME 开发者预览版
* Architect
* Deepin

值得注意的是它的开发者版本（面向测试人员和开发人员），Architect 版本（适用于想要从头开始构建 Manjaro 的用户）和 Awesome 版本（图 5，适用于开发人员处理日常工作的版本）。使用 Manjaro 的一个警告是，与任何滚动版本一样，你今天开发的代码可能明天无法运行。因此，你需要具备一定程度的敏捷性。当然，如果你没有为 Manjaro（或 Arch）做开发，并且你正在进行工作更多是通用的（或 Web）开发，那么只有当你使用的工具被更新了且不再适合你时，才会影响你。然而，这种情况发生的可能性很小。和大多数 Linux 发行版一样，你会发现 Manjaro 有大量的开发工具。

![Manjaro](/data/attachment/album/201902/13/231434kuvt4tsapnv4z37j.jpg "Manjaro")

*图 5：Manjaro Awesome 版对于开发者来说很棒。*

Manjaro 还支持 AUR（Arch User Repository —— Arch 用户的社区驱动软件库），其中包括最先进的软件和库，以及 [Unity Editor](https://unity3d.com/unity/editor) 或 yEd 等专有应用程序。但是，有个关于 AUR 的警告：AUR 包含的软件中被怀疑发现了恶意软件。因此，如果你选择使用 AUR，请谨慎操作，风险自负。

### 其实任何 Linux 都可以

说实话，如果你是开发人员，几乎任何 Linux 发行版都可以工作。如果从命令行执行大部分开发，则尤其如此。但是如果你喜欢在可靠的桌面上运行一个好的图形界面程序，试试这些发行版中的一个，它们不会令人失望。

通过 Linux 基金会和 edX 的免费[“Linux 简介”](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)课程了解有关 Linux 的更多信息。

---

via: <https://www.linux.com/blog/2019/1/top-5-linux-distributions-development-2019>

作者：[Jack Wallen](https://www.linux.com/users/jlwallen) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


开始使用 Sandstorm 吧，一个开源 Web 应用平台

>
> 了解 Sandstorm，这是我们在开源工具系列中的第三篇，它将在 2019 年提高你的工作效率。
>
>
>

![](/data/attachment/album/201902/13/232928h12p655pgucpj411.jpg)

每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心，渴望开启新的一年，当然，“抛弃旧的，拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件，但事实上并不用这样。

这是我挑选出的 19 个新的（或者对你而言新的）开源工具中的第三个工具来帮助你在 2019 年更有效率。

### Sandstorm

保持高效不仅仅需要待办事项以及让事情有组织。通常它需要一组工具以使工作流程顺利进行。

![](/data/attachment/album/201902/13/232836wzmm5nzpz2jorm2l.png)

[Sandstorm](https://sandstorm.io/) 是打包的开源应用集合，它们都可从一个 Web 界面访问，也可在中央控制台进行管理。你可以自己托管或使用 [Sandstorm Oasis](https://oasis.sandstorm.io) 服务。它按用户收费。

![](/data/attachment/album/201902/13/232845k660zyzjupa6arvk.png)

Sandstorm 有一个市场，在这里可以轻松安装应用。应用包括效率类、财务、笔记、任务跟踪、聊天、游戏等等。你还可以按照[开发人员文档](https://docs.sandstorm.io/en/latest/developing/)中的应用打包指南打包自己的应用并上传它们。

![](/data/attachment/album/201902/13/232852yexaaizz5k5ev9e2.png)

安装后，用户可以创建 [grain](https://sandstorm.io/how-it-works) - 容器化后的应用数据实例。默认情况下，grain 是私有的，它可以与其他 Sandstorm 用户共享。这意味着它们默认是安全的，用户可以选择与他人共享的内容。

![](/data/attachment/album/201902/13/232857yf6lrfd0ovl9g9lv.png)

Sandstorm 可以从几个不同的外部源进行身份验证，也可以使用无需密码的基于电子邮件的身份验证。使用外部服务意味着如果你已使用其中一种受支持的服务，那么就无需管理另一组凭据。

最后，Sandstorm 使安装和使用支持的协作应用变得快速，简单和安全。

---

via: <https://opensource.com/article/19/1/productivity-tool-sandstorm>

作者：[Kevin Sonney](https://opensource.com/users/ksonney "Kevin Sonney") 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


3 个简单实用的 GNOME Shell 扩展

Summary: 这三个扩展为你的桌面提供了更多的行为，可以完成你可能每天都会做的简单任务。

gnome好惨啊，自己自宫只能靠别人写插件来补（

来自福建福州的 Chrome Mobile 71.0|Android 8.0 用户

我倒是更喜欢这样自己定制。

这三个扩展为你的桌面提供了更多的行为，可以完成你可能每天都会做的简单任务。

![](/data/attachment/album/201902/13/234738ugdr1h1zg1zyrzia.png)

Fedora 工作站的默认桌面 GNOME Shell，因其极简、整洁的用户界面而闻名，并深受许多用户的喜爱。它还以可使用扩展添加到 stock 界面的能力而闻名。在本文中，我们将介绍 GNOME Shell 的 3 个简单且有用的扩展。这三个扩展为你的桌面提供了更多的行为，可以完成你可能每天都会做的简单任务。

### 安装扩展程序

安装 GNOME Shell 扩展的最快捷、最简单的方法是使用“软件”应用。有关详细信息，请查看 Magazine [以前的文章](https://fedoramagazine.org/install-extensions-via-software-application/)：

![](/data/attachment/album/201902/13/234739guapco7aop2d8p5w.jpg)

### 可移动驱动器菜单

![](/data/attachment/album/201902/13/234739opzjotgnczehjen9.jpg)

*Fedora 29 中的 Removable Drive Menu 扩展*

首先是 [Removable Drive Menu](https://extensions.gnome.org/extension/7/removable-drive-menu/) 扩展。如果你的计算机中有可移动驱动器，它是一个可在系统托盘中添加一个 widget 的简单工具。它可以使你轻松打开可移动驱动器中的文件，或者快速方便地弹出驱动器以安全移除设备。

![](/data/attachment/album/201902/13/234740ziqit8j2jiyygy23.png)

*软件应用中的 Removable Drive Menu*

### 扩展之扩展

![](/data/attachment/album/201902/13/234741l5syuzzz5ztuu2h5.jpg)

如果你一直在安装和尝试新扩展，那么 [Extensions](https://extensions.gnome.org/extension/1036/extensions/) 扩展非常有用。它提供了所有已安装扩展的列表，允许你启用或禁用它们。此外，如果该扩展有设置，那么可以快速打开每个扩展的设置对话框。

![](/data/attachment/album/201902/13/234741nbodtbggvxtszibm.png)

*软件中的 Extensions 扩展*

### 无用的时钟移动

![](/data/attachment/album/201902/13/234742ibeh8jtftncnbmcb.jpg)

最后的是列表中最简单的扩展。[Frippery Move Clock](https://extensions.gnome.org/extension/2/move-clock/)，只是将时钟位置从顶部栏的中心向右移动，位于状态区旁边。

![](/data/attachment/album/201902/13/234743jx9x5ay30xz90fj6.png)

---

via: <https://fedoramagazine.org/3-simple-and-useful-gnome-shell-extensions/>

作者：[Ryan Lerch](https://fedoramagazine.org/introducing-flatpak/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


在 Linux 终端上进行冒险

Summary: 我们的 Linux 命令行玩具日历的最后一天以一场盛大冒险结束。

我们的 Linux 命令行玩具日历的最后一天以一场盛大冒险结束。

>
> 我们的 Linux 命令行玩具日历的最后一天以一场盛大冒险结束。
>
>
>

![](/data/attachment/album/201902/14/233617qj2bsxvnl0lnaxlr.png)

今天是我们为期 24 天的 Linux 命令行玩具日历的最后一天。希望你一直有在看，但如果没有，请[从头开始](https://opensource.com/article/18/12/linux-toy-boxes)，继续努力。你会发现 Linux 终端有很多游戏、消遣和奇怪之处。

虽然你之前可能已经看过我们日历中的一些玩具，但我们希望对每个人而言至少有一件新东西。

今天的玩具是由 Opensource.com 管理员 [Joshua Allen Holm](https://opensource.com/users/holmja) 提出的：

>
> “如果你的冒险日历的最后一天不是 ESR（Eric S. Raymond）的[开源版的 Adventure 游戏](https://gitlab.com/esr/open-adventure "https://gitlab.com/esr/open-adventure") —— 它仍然使用经典的 `advent` 命令（在 BSD 游戏包中的 `adventure`） ，我会非常非常非常失望 ;-)“
>
>
>

这是结束我们这个系列的完美方式。

<ruby> 巨洞冒险 <rt>  Colossal Cave Adventure </rt></ruby>（通常简称 Adventure），是一款来自 20 世纪 70 年代的基于文本的游戏，它引领产生了冒险游戏这个类型的游戏。尽管它很古老，但是当探索幻想世界时，Adventure 仍然是一种轻松消耗时间的方式，就像龙与地下城那样，地下城主可能会引导你穿过一个充满想象的地方。

与其带你了解 Adventure 的历史，我鼓励你去阅读 Joshua 的[该游戏的历史](https://opensource.com/article/17/6/revisit-colossal-cave-adventure-open-adventure)这篇文章，以及为什么它几年前会重新复活，并且被重新移植。接着，[克隆它的源码](https://gitlab.com/esr/open-adventure)并按照[安装说明](https://gitlab.com/esr/open-adventure/blob/master/INSTALL.adoc)在你的系统上使用 `advent` 启动游戏。或者，像 Joshua 提到的那样，可以从 bsd-games 包中获取该游戏的另一个版本，该软件包可能存在于你的发行版中的默认仓库。

你有喜欢的命令行玩具认为我们应该介绍么？今天我们的系列结束了，但我们仍然乐于在新的一年中介绍一些很酷的命令行玩具。请在下面的评论中告诉我，我会查看一下。让我知道你对今天玩具的看法。

一定要看看昨天的玩具，[能从远程获得乐趣的 Linux 命令](https://opensource.com/article/18/12/linux-toy-remote)，明年再见！

---

via: <https://opensource.com/article/18/12/linux-toy-adventure>

作者：[Jason Baker](https://opensource.com/users/jason-baker) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


如何在终端显示图像缩略图

Summary: lsix 是一个简单的命令行实用程序，旨在使用 Sixel 图形格式在终端中显示缩略图。

Cool

来自山东临沂的 Opera Mobile 48.2|Android 8.1 用户

![](/data/attachment/album/201902/15/100523ear82xl1yoolxe2r.png)

不久前，我们讨论了 [Fim](https://www.ostechnix.com/how-to-display-images-in-the-terminal/)，这是一个轻量级的命令行图像查看器应用程序，用于从命令行显示各种类型的图像，如 bmp、gif、jpeg 和 png 等。今天，我偶然发现了一个名为 `lsix` 的类似工具。它类似于类 Unix 系统中的 `ls` 命令，但仅适用于图像。`lsix` 是一个简单的命令行实用程序，旨在使用 Sixel 图形格式在终端中显示缩略图。对于那些想知道的人来说，Sixel 是<ruby> 六像素 <rt>  six pixels </rt></ruby>的缩写，是一种位图图形格式。它使用 ImageMagick，因此几乎所有 imagemagick 支持的文件格式都可以正常工作。

### 功能

关于 `lsix` 的功能，我们可以列出如下：

* 自动检测你的终端是否支持 Sixel 图形格式。如果你的终端不支持 Sixel，它会通知你启用它。
* 自动检测终端背景颜色。它使用终端转义序列来试图找出终端应用程序的前景色和背景色，并清楚地显示缩略图。
* 如果目录中有更多图像（通常大于 21 个），`lsix` 将一次显示这些图像，因此你无需等待创建整个蒙太奇图像（LCTT 译注：拼贴图）。
* 可以通过 SSH 工作，因此你可以轻松操作存储在远程 Web 服务器上的图像。
* 它支持非位图图形，例如 .svg、.eps、.pdf、.xcf 等。
* 用 Bash 编写，适用于几乎所有 Linux 发行版。

### 安装 lsix

由于 `lsix` 使用 ImageMagick，请确保已安装它。它在大多数 Linux 发行版的默认软件库中都可用。 例如，在 Arch Linux 及其变体如 Antergos、Manjaro Linux 上，可以使用以下命令安装ImageMagick：

```
$ sudo pacman -S imagemagick
```

在 Debian、Ubuntu、Linux Mint：

```
$ sudo apt-get install imagemagick
```

`lsix` 并不需要安装，因为它只是一个 Bash 脚本。只需要下载它并移动到你的 `$PATH` 中。就这么简单。

从该项目的 GitHub 主页下载最新的 `lsix` 版本。我使用如下命令下载 `lsix` 归档包：

```
$ wget https://github.com/hackerb9/lsix/archive/master.zip
```

提取下载的 zip 文件：

```
$ unzip master.zip
```

此命令将所有内容提取到名为 `lsix-master` 的文件夹中。将 `lsix` 二进制文件从此目录复制到 `$PATH` 中，例如 `/usr/local/bin/`。

```
$ sudo cp lsix-master/lsix /usr/local/bin/
```

最后，使 `lsix` 二进制文件可执行：

```
$ sudo chmod +x /usr/local/bin/lsix
```

如此，现在是在终端本身显示缩略图的时候了。

在开始使用 `lsix` 之前，请确保你的终端支持 Sixel 图形格式。

开发人员在 vt340 仿真模式下的 Xterm 上开发了 `lsix`。 然而，他声称 `lsix` 应该适用于任何Sixel 兼容终端。

Xterm 支持 Sixel 图形格式，但默认情况下不启用。

你可以从另外一个终端使用命令来启动一个启用了 Sixel 模式的 Xterm：

```
$ xterm -ti vt340
```

或者，你可以使 vt340 成为 Xterm 的默认终端类型，如下所述。

编辑 `.Xresources` 文件（如果它不可用，只需创建它）：

```
$ vi .Xresources
```

添加如下行：

```
xterm*decTerminalID    :   vt340
```

按下 `ESC` 并键入 `:wq` 以保存并关闭该文件。

最后，运行如下命令来应用改变：

```
$ xrdb -merge .Xresources
```

现在，每次启动 Xterm 就会默认启用 Sixel 图形支持。

### 在终端中显示缩略图

启动 Xterm（不要忘记以 vt340 模式启动它）。以下是 Xterm 在我的系统中的样子。

![](/data/attachment/album/201902/15/100524vto46pbshmy191u0.png)

就像我已经说过的那样，`lsix` 非常简单实用。它没有任何命令行选项或配置文件。你所要做的就是将文件的路径作为参数传递，如下所示。

```
$ lsix ostechnix/logo.png
```

![](/data/attachment/album/201902/15/100525z9m9438lbmtnhm73.png)

如果在没有路径的情况下运行它，它将显示在当前工作目录中的缩略图图像。我在名为 `ostechnix` 的目录中有几个文件。

要显示此目录中的缩略图，只需运行：

```
$ lsix
```

![](/data/attachment/album/201902/15/100526evvw8sn88vdjjqst.png)

看到了吗？所有文件的缩略图都显示在终端里。

如果使用 `ls` 命令，则只能看到文件名，而不是缩略图。

![](/data/attachment/album/201902/15/100527klbh0zdlem5d5a0e.png)

你还可以使用通配符显示特定类型的指定图像或一组图像。

例如，要显示单个图像，只需提及图像的完整路径，如下所示。

```
$ lsix girl.jpg
```

![](/data/attachment/album/201902/15/100528uecowkopkv5800kx.png)

要显示特定类型的所有图像，例如 PNG，请使用如下所示的通配符。

```
$ lsix *.png
```

![](/data/attachment/album/201902/15/100530s2k9rck919m9zmmt.png)

对于 JEPG 类型，命令如下：

```
$ lsix *jpg
```

缩略图的显示质量非常好。我以为 `lsix` 会显示模糊的缩略图。但我错了，缩略图清晰可见，就像在图形图像查看器上一样。

而且，这一切都是唾手可得。如你所见，`lsix` 与 `ls` 命令非常相似，但它仅用于显示缩略图。如果你在工作中处理很多图像，`lsix` 可能会非常方便。试一试，请在下面的评论部分告诉我们你对此实用程序的看法。如果你知道任何类似的工具，也请提出建议。我将检查并更新本指南。

更多好东西即将到来。敬请关注！

干杯!

---

via: <https://www.ostechnix.com/how-to-display-thumbnail-images-in-terminal/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


开始使用 TaskBoard 吧，一款轻量级看板

Summary: 了解我们在开源工具系列中的第九个工具，它将帮助你在 2019 年提高工作效率。

了解我们在开源工具系列中的第九个工具，它将帮助你在 2019 年提高工作效率。

>
> 了解我们在开源工具系列中的第九个工具，它将帮助你在 2019 年提高工作效率。
>
>
>

![](/data/attachment/album/201902/15/102622fqth2o5tcthqqovp.png)

每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心，渴望开启新的一年，当然，“抛弃旧的，拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件，但事实上并不用这样。

这是我挑选出的 19 个新的（或者对你而言新的）开源工具中的第九个工具来帮助你在 2019 年更有效率。

### TaskBoard

正如我在本系列的[第二篇文章](/article-10454-1.html)中所写的那样，[看板](https://en.wikipedia.org/wiki/Kanban)现在非常受欢迎。但并非所有的看板都是相同的。[TaskBoard](https://taskboard.matthewross.me/) 是一个易于在现有 Web 服务器上部署的 PHP 应用，它有一些易于使用和管理的功能。

![](/data/attachment/album/201902/15/102624d2tr2717xtjncr7n.png)

[安装](https://taskboard.matthewross.me/docs/)它只需要解压 Web 服务器上的文件，运行一两个脚本，并确保目录可正常访问。第一次启动时，你会看到一个登录页面，然后可以就可以添加用户和制作看板了。看板创建选项包括添加要使用的列以及设置卡片的默认颜色。你还可以将用户分配给指定看板，这样每个人都只能看到他们需要查看的看板。

用户管理是轻量级的，所有帐户都是服务器的本地帐户。你可以为服务器上的每个用户设置默认看板，用户也可以设置自己的默认看板。当有人在多个看板上工作时，这个选项非常有用。

![](/data/attachment/album/201902/15/102626gunkqj99k2tpqtb3.png)

TaskBoard 还允许你创建自动操作，包括更改用户分配、列或卡片类别这些操作。虽然 TaskBoard 不如其他一些看板应用那么强大，但你可以设置自动操作，使看板用户更容易看到卡片、清除截止日期，并根据需要自动为人们分配新卡片。例如，在下面的截图中，如果将卡片分配给 “admin” 用户，那么它的颜色将更改为红色，并且当将卡片分配给我的用户时，其颜色将更改为蓝绿色。如果项目已添加到“待办事项”列，我还添加了一个操作来清除项目的截止日期，并在发生这种情况时自动将卡片分配给我的用户。

![](/data/attachment/album/201902/15/102628wo39bdl9ezf9sv4n.png)

卡片非常简单。虽然它们没有开始日期，但它们确实有结束日期和点数字段。点数可用于估计所需的时间、所需的工作量或仅是一般优先级。使用点数是可选的，但如果你使用 TaskBoard 进行 scrum 规划或其他敏捷技术，那么这是一个非常方便的功能。你还可以按用户和类别过滤视图。这对于正在进行多个工作流的团队非常有用，因为它允许团队负责人或经理了解进度状态或人员工作量。

![](/data/attachment/album/201902/15/102629fgrg2twrraxhiuzy.png)

如果你需要一个相当轻便的看板，请看下 TaskBoard。它安装快速，有一些很好的功能，且非常、非常容易使用。它还足够的灵活性，可用于开发团队，个人任务跟踪等等。

---

via: <https://opensource.com/article/19/1/productivity-tool-taskboard>

作者：[Kevin Sonney](https://opensource.com/users/ksonney "Kevin Sonney") 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


计算机实验室之树莓派：课程 6 屏幕01

有多想不开,使用汇编语言? 二十年前我毕业的时候,学校里主要教汇编,我到企业一看根本不会有人使用了汇编,这都9102年了,,

![](/data/attachment/album/201902/16/145001egq5zxwgy7o3qrj7.jpg)

欢迎来到屏幕系列课程。在本系列中，你将学习在树莓派中如何使用汇编代码控制屏幕，从显示随机数据开始，接着学习显示一个固定的图像和显示文本，然后格式化数字为文本。假设你已经完成了 OK 系列课程的学习，所以在本系列中出现的有些知识将不再重复。

第一节的屏幕课程教你一些关于图形的基础理论，然后用这些理论在屏幕或电视上显示一个图案。

### 1、入门

预期你已经完成了 OK 系列的课程，以及那个系列课程中在 `gpio.s` 和 `systemTimer.s` 文件中调用的函数。如果你没有完成这些，或你喜欢完美的实现，可以去下载 `OK05.s` 解决方案。在这里也要使用 `main.s` 文件中从开始到包含 `mov sp,#0x8000` 的这一行之前的代码。请删除这一行以后的部分。

### 2、计算机图形

正如你所认识到的，从根本上来说，计算机是非常愚蠢的。它们只能执行有限数量的指令，仅仅能做一些数学，但是它们也能以某种方式来做很多很多的事情。而在这些事情中，我们目前想知道的是，计算机是如何将一个图像显示到屏幕上的。我们如何将这个问题转换成二进制？答案相当简单；我们为每个颜色设计一些编码方法，然后我们为在屏幕上的每个像素保存一个编码。一个像素就是你的屏幕上的一个非常小的点。如果你离屏幕足够近，你或许能够辨别出你的屏幕上的单个像素，能够看到每个图像都是由这些像素组成的。

>
> 将颜色表示为数字有几种方法。在这里我们专注于 RGB 方法，但 HSL 也是很常用的另一种方法。
>
>
>

随着计算机时代的进步，人们希望显示越来越复杂的图形，于是发明了图形卡的概念。图形卡是你的计算机上用来在屏幕上专门绘制图像的第二个处理器。它的任务就是将像素值信息转换成显示在屏幕上的亮度级别。在现代计算机中，图形卡已经能够做更多更复杂的事情了，比如绘制三维图形。但是在本系列教程中，我们只专注于图形卡的基本使用；从内存中取得像素然后把它显示到屏幕上。

不管使用哪种方法，现在马上出现的一个问题就是我们使用的颜色编码。这里有几种选择，每个产生不同的输出质量。为了完整起见，我在这里只是简单概述它们。

| 名字 | 唯一颜色数量 | 描述 | 示例 |
| --- | --- | --- | --- |
| 单色 | 2 | 每个像素使用 1 位去保存，其中 1 表示白色，0 表示黑色。 | Monochrome image of a bird |
| 灰度 | 256 | 每个像素使用 1 个字节去保存，使用 255 表示白色，0 表示黑色，介于这两个值之间的所有值表示这两个颜色的一个线性组合。 | Geryscale image of a bird |
| 8 色 | 8 | 每个像素使用 3 位去保存，第一位表示红色通道，第二位表示绿色通道，第三位表示蓝色通道。 | 8 colour image of a bird |
| 低色值 | 256 | 每个像素使用 8 位去保存，前三位表示红色通道的强度，接下来的三位表示绿色通道的强度，最后两位表示蓝色通道的强度。 | Low colour image of a bird |
| 高色值 | 65,536 | 每个像素使用 16 位去保存，前五位表示红色通道的强度，接下来的六位表示绿色通道的强度，最后的五位表示蓝色通道的强度。 | High colour image of a bird |
| 真彩色 | 16,777,216 | 每个像素使用 24 位去保存，前八位表示红色通道，第二个八位表示绿色通道，最后八位表示蓝色通道。 | True colour image of a bird |
| RGBA32 | 16,777,216 带 256 级透明度 | 每个像素使用 32 位去保存，前八位表示红色通道，第二个八位表示绿色通道，第三个八位表示蓝色通道。只有一个图像绘制在另一个图像的上方时才考虑使用透明通道，值为 0 时表示下面图像的颜色，值为 255 时表示上面这个图像的颜色，介于这两个值之间的所有值表示这两个图像颜色的混合。 |

>
> 不过这里的一些图像只用了很少的颜色，因为它们使用了一个叫空间抖动的技术。这允许它们以很少的颜色仍然能表示出非常好的图像。许多早期的操作系统就使用了这种技术。
>
>
>

在本教程中，我们将从使用高色值开始。这样你就可以看到图像的构成，它的形成过程清楚，图像质量好，又不像真彩色那样占用太多的空间。也就是说，显示一个比较小的 800x600 像素的图像，它只需要小于 1 MiB 的空间。它另外的好处是它的大小是 2 次幂的倍数，相比真彩色这将极大地降低了获取信息的复杂度。

树莓派和它的图形处理器有一种特殊而奇怪的关系。在树莓派上，首先运行的事实上是图形处理器，它负责启动主处理器。这是很不常见的。最终它不会有太大的差别，但在许多交互中，它经常给人感觉主处理器是次要的，而图形处理器才是主要的。在树莓派上这两者之间依靠一个叫 “邮箱” 的东西来通讯。它们中的每一个都可以为对方投放邮件，这个邮件将在未来的某个时刻被对方收集并处理。我们将使用这个邮箱去向图形处理器请求一个地址。这个地址将是一个我们在屏幕上写入像素颜色信息的位置，我们称为帧缓冲，图形卡将定期检查这个位置，然后更新屏幕上相应的像素。

>
> 保存<ruby> 帧缓冲 <rt>  frame buffer </rt></ruby>给计算机带来了很大的内存负担。基于这种原因，早期计算机经常作弊，比如，保存一屏幕文本，在每次单独刷新时，它只绘制刷新了的字母。
>
>
>

### 3、编写邮差程序

接下来我们做的第一件事情就是编写一个“邮差”程序。它有两个方法：`MailboxRead`，从寄存器 `r0` 中的邮箱通道读取一个消息。而 `MailboxWrite`，将寄存器 `r0` 中的头 28 位的值写到寄存器 `r1` 中的邮箱通道。树莓派有 7 个与图形处理器进行通讯的邮箱通道。但仅第一个对我们有用，因为它用于协调帧缓冲。

>
> 消息传递是组件间通讯时使用的常见方法。一些操作系统在程序之间使用虚拟消息进行通讯。
>
>
>

下列的表和示意图描述了邮箱的操作。

表 3.1 邮箱地址

| 地址 | 大小 / 字节 | 名字 | 描述 | 读 / 写 |
| --- | --- | --- | --- | --- |
| 2000B880 | 4 | Read | 接收邮件 | R |
| 2000B890 | 4 | Poll | 不检索接收 | R |
| 2000B894 | 4 | Sender | 发送者信息 | R |
| 2000B898 | 4 | Status | 信息 | R |
| 2000B89C | 4 | Configuration | 设置 | RW |
| 2000B8A0 | 4 | Write | 发送邮件 | W |

为了给指定的邮箱发送一个消息：

1. 发送者等待，直到 `Status` 字段的头一位为 0。
2. 发送者写入到 `Write`，低 4 位是要发送到的邮箱，高 28 位是要写入的消息。

为了读取一个消息：

1. 接收者等待，直到 `Status` 字段的第 30 位为 0。
2. 接收者读取消息。
3. 接收者确认消息来自正确的邮箱，否则再次重试。

如果你觉得有信心，你现在已经有足够的信息去写出我们所需的两个方法。如果没有信心，请继续往下看。

与以前一样，我建议你实现的第一个方法是获取邮箱区域的地址。

```
.globl GetMailboxBase
GetMailboxBase:
ldr r0,=0x2000B880
mov pc,lr
```

发送程序相对简单一些，因此我们将首先去实现它。随着你的方法越来越复杂，你需要提前去规划它们。规划它们的一个好的方式是写出一个简单步骤列表，详细地列出你需要做的事情，像下面一样。

1. 我们的输入将要写什么（`r0`），以及写到什么邮箱（`r1`）。我们必须验证邮箱的真实性，以及它的低 4 位的值是否为 0。不要忘了验证输入。
2. 使用 `GetMailboxBase` 去检索地址。
3. 读取 `Status` 字段。
4. 检查头一位是否为 0。如果不是，回到第 3 步。
5. 将写入的值和邮箱通道组合到一起。
6. 写入到 `Write`。

我们来按顺序写出它们中的每一步。

1、这将实现我们验证 `r0` 和 `r1` 的目的。`tst` 是通过计算两个操作数的逻辑与来比较两个操作数的函数，然后将结果与 0 进行比较。在本案例中，它将检查在寄存器 `r0` 中的输入的低 4 位是否为全 0。

```
.globl MailboxWrite
MailboxWrite:
tst r0,#0b1111
movne pc,lr
cmp r1,#15
movhi pc,lr
```

>
> `tst reg,#val` 计算寄存器 `reg` 和 `#val` 的逻辑与，然后将计算结果与 0 进行比较。
>
>
>

2、这段代码确保我们不会覆盖我们的值，或链接寄存器，然后调用 `GetMailboxBase`。

```
channel .req r1
value .req r2
mov value,r0
push {lr}
bl GetMailboxBase
mailbox .req r0
```

3、这段代码加载当前状态。

```
wait1$:
status .req r3
ldr status,[mailbox,#0x18]
```

4、这段代码检查状态字段的头一位是否为 0，如果不为 0，循环回到第 3 步。

```
tst status,#0x80000000
.unreq status
bne wait1$
```

5、这段代码将通道和值组合到一起。

```
add value,channel
.unreq channel
```

6、这段代码保存结果到写入字段。

```
str value,[mailbox,#0x20]
.unreq value
.unreq mailbox
pop {pc}
```

`MailboxRead` 的代码和它非常类似。

1. 我们的输入将从哪个邮箱读取（`r0`）。我们必须要验证邮箱的真实性。不要忘了验证输入。
2. 使用 `GetMailboxBase` 去检索地址。
3. 读取 `Status` 字段。
4. 检查第 30 位是否为 0。如果不为 0，返回到第 3 步。
5. 读取 `Read` 字段。
6. 检查邮箱是否是我们所要的，如果不是返回到第 3 步。
7. 返回结果。

我们来按顺序写出它们中的每一步。

1、这一段代码来验证 `r0` 中的值。

```
.globl MailboxRead
MailboxRead:
cmp r0,#15
movhi pc,lr
```

2、这段代码确保我们不会覆盖掉我们的值，或链接寄存器，然后调用 `GetMailboxBase`。

```
channel .req r1
mov channel,r0
push {lr}
bl GetMailboxBase
mailbox .req r0
```

3、这段代码加载当前状态。

```
rightmail$:
wait2$:
status .req r2
ldr status,[mailbox,#0x18]
```

4、这段代码检查状态字段第 30 位是否为 0，如果不为 0，返回到第 3 步。

```
tst status,#0x40000000
.unreq status
bne wait2$
```

5、这段代码从邮箱中读取下一条消息。

```
mail .req r2
ldr mail,[mailbox,#0]
```

6、这段代码检查我们正在读取的邮箱通道是否为提供给我们的通道。如果不是，返回到第 3 步。

```
inchan .req r3
and inchan,mail,#0b1111
teq inchan,channel
.unreq inchan
bne rightmail$
.unreq mailbox
.unreq channel
```

7、这段代码将答案（邮件的前 28 位）移动到寄存器 `r0` 中。

```
and r0,mail,#0xfffffff0
.unreq mail
pop {pc}
```

### 4、我心爱的图形处理器

通过我们新的邮差程序，我们现在已经能够向图形卡上发送消息了。我们应该发送些什么呢？这对我来说可能是个很难找到答案的问题，因为它不是任何线上手册能够找到答案的问题。尽管如此，通过查找有关树莓派的 GNU/Linux，我们能够找出我们需要发送的内容。

消息很简单。我们描述我们想要的帧缓冲区，而图形卡要么接受我们的请求，给我们返回一个 0，然后用我们写的一个小的调查问卷来填充屏幕；要么发送一个非 0 值，我们知道那表示很遗憾（出错了）。不幸的是，我并不知道它返回的其它数字是什么，也不知道它意味着什么，但我们知道仅当它返回一个 0，才表示一切顺利。幸运的是，对于合理的输入，它总是返回一个 0，因此我们不用过于担心。

>
> 由于在树莓派的内存是在图形处理器和主处理器之间共享的，我们能够只发送可以找到我们信息的位置即可。这就是 DMA，许多复杂的设备使用这种技术去加速访问时间。
>
>
>

为简单起见，我们将提前设计好我们的请求，并将它保存到 `framebuffer.s` 文件的 `.data` 节中，它的代码如下：

```
.section .data
.align 4
.globl FrameBufferInfo
FrameBufferInfo:
.int 1024 /* #0 物理宽度 */
.int 768 /* #4 物理高度 */
.int 1024 /* #8 虚拟宽度 */
.int 768 /* #12 虚拟高度 */
.int 0 /* #16 GPU - 间距 */
.int 16 /* #20 位深 */
.int 0 /* #24 X */
.int 0 /* #28 Y */
.int 0 /* #32 GPU - 指针 */
.int 0 /* #36 GPU - 大小 */
```

这就是我们发送到图形处理器的消息格式。第一对两个关键字描述了物理宽度和高度。第二对关键字描述了虚拟宽度和高度。帧缓冲的宽度和高度就是虚拟的宽度和高度，而 GPU 按需要伸缩帧缓冲去填充物理屏幕。如果 GPU 接受我们的请求，接下来的关键字将是 GPU 去填充的参数。它们是帧缓冲每行的字节数，在本案例中它是 `2 × 1024 = 2048`。下一个关键字是每个像素分配的位数。使用了一个 16 作为值意味着图形处理器使用了我们上面所描述的高色值模式。值为 24 是真彩色，而值为 32 则是 RGBA32。接下来的两个关键字是 x 和 y 偏移量，它表示当将帧缓冲复制到屏幕时，从屏幕左上角跳过的像素数目。最后两个关键字是由图形处理器填写的，第一个表示指向帧缓冲的实际指针，第二个是用字节数表示的帧缓冲大小。

在这里我非常谨慎地使用了一个 `.align 4` 指令。正如前面所讨论的，这样确保了下一行地址的低 4 位是 0。所以，我们可以确保将被放到那个地址上的帧缓冲（`FrameBufferInfo`）是可以发送到图形处理器上的，因为我们的邮箱仅发送低 4 位全为 0 的值。

>
> 当设备使用 DMA 时，对齐约束变得非常重要。GPU 预期该消息都是 16 字节对齐的。
>
>
>

到目前为止，我们已经有了待发送的消息，我们可以写代码去发送它了。通讯将按如下的步骤进行：

1. 写入 `FrameBufferInfo + 0x40000000` 的地址到邮箱 1。
2. 从邮箱 1 上读取结果。如果它是非 0 值，意味着我们没有请求一个正确的帧缓冲。
3. 复制我们的图像到指针，这时图像将出现在屏幕上！

我在步骤 1 中说了一些以前没有提到的事情。我们在发送之前，在帧缓冲地址上加了 `0x40000000`。这其实是一个给 GPU 的特殊信号，它告诉 GPU 应该如何写到结构上。如果我们只是发送地址，GPU 将写到它的回复上，这样不能保证我们可以通过刷新缓存看到它。缓存是处理器使用的值在它们被发送到存储之前保存在内存中的片段。通过加上 `0x40000000`，我们告诉 GPU 不要将写入到它的缓存中，这样将确保我们能够看到变化。

因为在那里发生很多事情，因此最好将它实现为一个函数，而不是将它以代码的方式写入到 `main.s` 中。我们将要写一个函数 `InitialiseFrameBuffer`，由它来完成所有协调和返回指向到上面提到的帧缓冲数据的指针。为方便起见，我们还将帧缓冲的宽度、高度、位深作为这个方法的输入，这样就很容易地修改 `main.s` 而不必知道协调的细节了。

再一次，来写下我们要做的详细步骤。如果你有信心，可以略过这一步直接尝试去写函数。

1. 验证我们的输入。
2. 写输入到帧缓冲。
3. 发送 `frame buffer + 0x40000000` 的地址到邮箱。
4. 从邮箱中接收回复。
5. 如果回复是非 0 值，方法失败。我们应该返回 0 去表示失败。
6. 返回指向帧缓冲信息的指针。

现在，我们开始写更多的方法。以下是上面其中一个实现。

1、这段代码检查宽度和高度是小于或等于 4096，位深小于或等于 32。这里再次使用了条件运行的技巧。相信自己这是可行的。

```
.section .text
.globl InitialiseFrameBuffer
InitialiseFrameBuffer:
width .req r0
height .req r1
bitDepth .req r2
cmp width,#4096
cmpls height,#4096
cmpls bitDepth,#32
result .req r0
movhi result,#0
movhi pc,lr
```

2、这段代码写入到我们上面定义的帧缓冲结构中。我也趁机将链接寄存器推入到栈上。

```
fbInfoAddr .req r3
push {lr}
ldr fbInfoAddr,=FrameBufferInfo
str width,[fbInfoAddr,#0]
str height,[fbInfoAddr,#4]
str width,[fbInfoAddr,#8]
str height,[fbInfoAddr,#12]
str bitDepth,[fbInfoAddr,#20]
.unreq width
.unreq height
.unreq bitDepth
```

3、`MailboxWrite` 方法的输入是写入到寄存器 `r0` 中的值，并将通道写入到寄存器 `r1` 中。

```
mov r0,fbInfoAddr
add r0,#0x40000000
mov r1,#1
bl MailboxWrite
```

4、`MailboxRead` 方法的输入是写入到寄存器 `r0` 中的通道，而输出是值读数。

```
mov r0,#1
bl MailboxRead
```

5、这段代码检查 `MailboxRead` 方法的结果是否为 0，如果不为 0，则返回 0。

```
teq result,#0
movne result,#0
popne {pc}
```

6、这是代码结束，并返回帧缓冲信息地址。

```
mov result,fbInfoAddr
pop {pc}
.unreq result
.unreq fbInfoAddr
```

### 5、在一帧中一行之内的一个像素

到目前为止，我们已经创建了与图形处理器通讯的方法。现在它已经能够给我们返回一个指向到帧缓冲的指针去绘制图形了。我们现在来绘制一个图形。

第一示例中，我们将在屏幕上绘制连续的颜色。它看起来并不漂亮，但至少能说明它在工作。我们如何才能在帧缓冲中设置每个像素为一个连续的数字，并且要持续不断地这样做。

将下列代码复制到 `main.s` 文件中，并放置在 `mov sp,#0x8000` 行之后。

```
mov r0,#1024
mov r1,#768
mov r2,#16
bl InitialiseFrameBuffer
```

这段代码使用了我们的 `InitialiseFrameBuffer` 方法，简单地创建了一个宽 1024、高 768、位深为 16 的帧缓冲区。在这里，如果你愿意可以尝试使用不同的值，只要整个代码中都一样就可以。如果图形处理器没有给我们创建好一个帧缓冲区，这个方法将返回 0，我们最好检查一下返回值，如果出现返回值为 0 的情况，我们打开 OK LED 灯。

```
teq r0,#0
bne noError$

mov r0,#16
mov r1,#1
bl SetGpioFunction
mov r0,#16
mov r1,#0
bl SetGpio

error$:
b error$

noError$:
fbInfoAddr .req r4
mov fbInfoAddr,r0
```

现在，我们已经有了帧缓冲信息的地址，我们需要取得帧缓冲信息的指针，并开始绘制屏幕。我们使用两个循环来做实现，一个走行，一个走列。事实上，树莓派中的大多数应用程序中，图片都是以从左到右然后从上到下的顺序来保存的，因此我们也按这个顺序来写循环。

```
render$:

    fbAddr .req r3
    ldr fbAddr,[fbInfoAddr,#32]

    colour .req r0
    y .req r1
    mov y,#768
    drawRow$:

        x .req r2
        mov x,#1024
        drawPixel$:

            strh colour,[fbAddr]
            add fbAddr,#2
            sub x,#1
            teq x,#0
            bne drawPixel$

        sub y,#1
        add colour,#1
        teq y,#0
        bne drawRow$

    b render$

.unreq fbAddr
.unreq fbInfoAddr
```

>
> `strh reg,[dest]` 将寄存器中的低位半个字保存到给定的 `dest` 地址上。
>
>
>

这是一个很长的代码块，它嵌套了三层循环。为了帮你理清头绪，我们将循环进行缩进处理，这就有点类似于高级编程语言，而汇编器会忽略掉这些用于缩进的 `tab` 字符。我们看到，在这里它从帧缓冲信息结构中加载了帧缓冲的地址，然后基于每行来循环，接着是每行上的每个像素。在每个像素上，我们使用一个 `strh`（保存半个字）命令去保存当前颜色，然后增加地址继续写入。每行绘制完成后，我们增加绘制的颜色号。在整个屏幕绘制完成后，我们跳转到开始位置。

### 6、看到曙光

现在，你已经准备好在树莓派上测试这些代码了。你应该会看到一个渐变图案。注意：在第一个消息被发送到邮箱之前，树莓派在它的四个角上一直显示一个渐变图案。如果它不能正常工作，请查看我们的排错页面。

如果一切正常，恭喜你！你现在可以控制屏幕了！你可以随意修改这些代码去绘制你想到的任意图案。你还可以做更精彩的渐变图案，可以直接计算每个像素值，因为每个像素包含了一个 Y 坐标和 X 坐标。在下一个 [课程 7：Screen 02](https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen02.html) 中，我们将学习一个更常用的绘制任务：行。

---

via: <https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html>

作者：[Alex Chadwick](https://www.cl.cam.ac.uk) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


Pony 编程语言简介

这头图……

>
> Pony，一种“Rust 遇上 Erlang”的语言，让开发快捷、安全、高效、高并发的程序更简单。
>
>
>

![](/data/attachment/album/201902/16/153836veesmpo2c33q1jcs.jpg)

在 [Wallaroo Labs](http://www.wallaroolabs.com/)，我是工程副总裁，我们正在构建一个用 [Pony](https://www.ponylang.org/) 编程语言编写的 [高性能分布式流处理器](https://github.com/wallaroolabs/wallaroo)。大多数人没有听说过 Pony，但它一直是 Wallaroo 的最佳选择，它也可能成为你的下一个项目的最佳选择。

>
> “一门编程语言只是另一种工具。与语法无关，与表达性无关，与范式或模型无关，仅与解决难题有关。” —Sylvan Clebsch，Pony 的创建者
>
>
>

我是 Pony 项目的贡献者，但在这里我要谈谈为什么 Pony 对于像 Wallaroo 这样的应用是个好选择，并分享我使用 Pony 的方式。如果你对我们为什么使用 Pony 来编写 Wallaroo 甚感兴趣，我们有一篇关于它的 [博文](https://blog.wallaroolabs.com/2017/10/why-we-used-pony-to-write-wallaroo/)。

### Pony 是什么？

你可以把 Pony 想象成某种“Rust 遇上 Erlang”的东西。Pony 有着最引人注目的特性，它们是：

* 类型安全
* 存储安全
* 异常安全
* 无数据竞争
* 无死锁

此外，它可以被编译为高效的本地代码，它是在开放的情况下开发的，在两句版 BSD 许可证下发布。

以上说的功能不少，但在这里我将重点关注那些对我们公司来说采用 Pony 至关重要的功能。

### 为什么使用 Pony？

使用大多数我们现有的工具编写快速、安全、高效、高并发的程序并非易事。“快速、高效、高并发”是可实现的目标，但加入“安全”之后，就困难了许多。对于 Wallaroo，我们希望同时实现四个目标，而 Pony 让实现它们更加简单。

#### 高并发

Pony 让并发变得简单。部分是通过提供一个固执的并发方式实现的。在 Pony 语言中，所有的并发都是通过 [Actor 模型](https://en.wikipedia.org/wiki/Actor_model) 进行的。

Actor 模型以在 Erlang 和 Akka 中的实现最为著名。Actor 模型出现于上世纪 70 年代，细节因实现方式而异。不变的是，所有计算都由通过异步消息进行通信的 actor 来执行。

你可以用这种方式来看待 Actor 模型：面向对象中的对象是状态 + 同步方法，而 actor 是状态 + 异步方法。

当一个 actor 收到一个消息时，它执行相应的方法。该方法可以在只有该 actor 可访问的状态下运行。Actor 模型允许我们以并发安全的方式使用可变状态。每个 actor 都是单线程的。一个 actor 中的两个方法绝不会并发运行。这意味着，在给定的 actor 中，数据更新不会引起数据竞争或通常与线程和可变状态相关的其他问题。

#### 快速高效

Pony actor 通过一个高效的工作窃取调度程序来调度。每个可用的 CPU 都有一个单独 Pony 调度程序。这种每个核心一个线程的并发模型是 Pony 尝试与 CPU 协同工作以尽可能高效运行的一部分。Pony 运行时尝试尽可能利用 CPU 缓存。代码越少干扰缓存，运行得越好。Pony 意在帮你的代码与 CPU 缓存友好相处。

Pony 的运行时还会有每个 actor 的堆，因此在垃圾收集期间，没有 “停止一切” 的垃圾收集步骤。这意味着你的程序总是至少能做一点工作。因此 Pony 程序最终具有非常一致的性能和可预测的延迟。

#### 安全

Pony 类型系统引入了一个新概念：引用能力，它使得数据安全成为类型系统的一部分。Pony 语言中每种变量的类型都包含了有关如何在 actor 之间分享数据的信息。Pony 编译器用这些信息来确认，在编译时，你的代码是无数据竞争和无死锁的。

如果这听起来有点像 Rust，那是因为本来就是这样的。Pony 的引用功能和 Rust 的借用检查器都提供数据安全性；它们只是以不同的方式来接近这个目标，并有不同的权衡。

### Pony 适合你吗？

决定是否要在一个非业余爱好的项目上使用一门新的编程语言是困难的。与其他方法想比，你必须权衡工具的适当性和不成熟度。那么，Pony 和你搭不搭呢？

如果你有一个困难的并发问题需要解决，那么 Pony 可能是一个好选择。解决并发应用问题是 Pony 之所以存在的理由。如果你能用一个单线程的 Python 脚本就完成所需操作，那你大概不需要它。如果你有一个困难的并发问题，你应该考虑 Pony 及其强大的无数据竞争、并发感知类型系统。

你将获得一个这样的编译器，它将阻止你引入许多与并发相关的错误，并在运行时为你提供出色的性能特征。

### 开始使用 Pony

如果你准备好开始使用 Pony，你需要先在 Pony 的网站上访问 [学习部分](https://www.ponylang.org/learn/)。在这里你会找到安装 Pony 编译器的步骤和学习这门语言的资源。

如果你愿意为你正在使用的这个语言做出贡献，我们会在 GitHub 上为你提供一些 [初学者友好的问题](https://github.com/ponylang/ponyc/issues?q=is%3Aissue+is%3Aopen+label%3A%22complexity%3A+beginner+friendly%22)。

同时，我迫不及待地想在 [我们的 IRC 频道](https://webchat.freenode.net/?channels=%23ponylang) 和 [Pony 邮件列表](https://pony.groups.io/g/user) 上与你交谈。

要了解更多有关 Pony 的消息，请参阅 Sean Allen 2018 年 7 月 16 日至 19 日在俄勒冈州波特兰举行的 [第 20 届 OSCON 会议](https://conferences.oreilly.com/oscon/oscon-or) 上的演讲： [Pony，我如何学会停止担心并拥抱未经证实的技术](https://conferences.oreilly.com/oscon/oscon-or/public/schedule/speaker/213590)。

---

via: <https://opensource.com/article/18/5/pony>

作者：[Sean T Allen](https://opensource.com/users/seantallen) 选题：[lujun9972](https://github.com/lujun9972) 译者：[beamrolling](https://github.com/beamrolling) 校对：[wxy](https://github.com/wxy)

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


如何从 Linux 上连接到远程桌面

好文章，非常感谢，谢谢你们的努力。

>
> Remmina 的极简用户界面使得远程访问 Linux / Windows 10 变得轻松。
>
>
>

![](/data/attachment/album/201902/16/160121nf9iqddx3qdqv7sf.png)

根据维基百科，[远程桌面](https://en.wikipedia.org/wiki/Remote_desktop_software) 是一种“软件或者操作系统特性，它可以让个人电脑上的桌面环境在一个系统（通常是电脑，但是也可以是服务器）上远程运行，但在另一个分开的客户端设备显示”。

换句话说，远程桌面是用来访问在另一台电脑上运行的环境的。比如说 [ManageIQ/Integration tests](https://github.com/ManageIQ/integration_tests) 仓库的拉取请求 (PR) 测试系统开放了一个虚拟网络计算 (VNC) 连接端口，使得我能够远程浏览正被实时测试的拉取请求。远程桌面也被用于帮助客户解决电脑问题：在客户的许可下，你可以远程建立 VNC 或者远程桌面协议（RDP）连接来查看或者交互式地访问该电脑以寻找并解决问题。

运用远程桌面连接软件可以建立这些连接。可供选择的软件有很多，我用 [Remmina](https://www.remmina.org/wp/)，因为我喜欢它极简、好用的用户界面 (UI)。它是用 GTK+ 编写的，在 GNU GPL 许可证开源。

在这篇文章里，我会解释如何使用 Remmina 客户端从一台 Linux 电脑上远程连接到 Windows 10 系统 和 Red Hat 企业版 Linux 7 系统。

### 在 Linux 上安装 Remmina

首先，你需要在你用来远程访问其它电脑的的主机上安装 Remmina。如果你用的是 Fedora，你可以运行如下的命令来安装 Remmina：

```
sudo dnf install -y remmina
```

如果你想在一个不同的 Linux 平台上安装 Remmina，跟着 [安装教程](https://www.tecmint.com/remmina-remote-desktop-sharing-and-ssh-client/) 走。然后你会发现 Remmina 正和你其它软件出现在一起（在这张图片里选中了 Remmina）。

![](/data/attachment/album/201902/16/160139hkltc0ssspl008s8.png)

点击图标运行 Remmina，你应该能看到像这样的屏幕：

![](/data/attachment/album/201902/16/160141p7mo030b1hhmj1nd.png)

Remmina 提供不同种类的连接，其中包括用来连接到 Windows 系统的 RDP 和用来连接到 Linux 系统的 VNC。如你在上图左上角所见的，Remmina 的默认设置是 RDP。

### 连接到 Windows 10

在你通过 RDP 连接到一台 Windows 10 电脑之前，你必须修改权限以允许分享远程桌面并通过防火墙建立连接。

* [注意: Windows 10 家庭版没有列入 RDP 特性](https://superuser.com/questions/1019203/remote-desktop-settings-missing#1019212)

要许可远程桌面分享，在“文件管理器”界面右击“我的电脑 → 属性 → 远程设置”，接着在跳出的窗口中，勾选“在这台电脑上允许远程连接”，再点击“应用”。

![](/data/attachment/album/201902/16/160149y9aaxx7xruof7hge.png)

然后，允许远程连接通过你的防火墙。首先在“开始菜单”中查找“防火墙设置”，选择“允许应用通过防火墙”。

![](/data/attachment/album/201902/16/160154ct91zakd3v7javjd.png)

在打开的窗口中，在“允许的应用和特性”下找到“远程桌面”。根据你用来访问这个桌面的网络酌情勾选“隐私”和/或“公开”列的选框。点击“确定”。

![](/data/attachment/album/201902/16/160159jzzpqqz14qqkoyll.png)

回到你用来远程访问 Windows 主机的 Linux 电脑，打开 Remmina。输入你的 Windows 主机的 IP 地址，敲击回车键。（我怎么在 [Linux](https://opensource.com/article/18/5/how-find-ip-address-linux) 和 [Windws](https://www.groovypost.com/howto/find-windows-10-device-ip-address/) 中确定我的 IP 地址？）看到提示后，输入你的用户名和密码，点击“确定”。

![](/data/attachment/album/201902/16/160204llyvh2h4lh4how28.png)

如果你被询问是否接受证书，点击“确定”。

![](/data/attachment/album/201902/16/160207pb7ppa442avoe3ob.png)

你此时应能看到你的 Windows 10 主机桌面。

![](/data/attachment/album/201902/16/160208zn0728se8c8ad7a7.png)

### 连接到 Red Hat 企业版 Linux 7

要在你的 RHEL7 电脑上允许远程访问，在 Linux 桌面上打开“所有设置”。

![](/data/attachment/album/201902/16/160215f9nm4nw9nbaahpeh.png)

点击分享图标会打开如下的窗口：

![](/data/attachment/album/201902/16/160217ed32r4nbw9wbd9w0.png)

如果“屏幕分享”处于关闭状态，点击一下。一个窗口会弹出，你可以滑动到“打开”的位置。如果你想允许远程控制桌面，将“允许远程控制”调到“打开”。你同样也可以在两种访问选项间选择：一个能够让电脑的主要用户接受或者否绝连接要求，另一个能用密码验证连接。在窗口底部，选择被允许连接的网络界面，最后关闭窗口。

接着，从“应用菜单 → 其它 → 防火墙”打开“防火墙设置”。

![](/data/attachment/album/201902/16/160219ev4kvvbmp73plxm3.png)

勾选 “vnc-server”旁边的选框（如下图所示）关闭窗口。接着直接到你远程电脑上的 Remmina，输入你想连接到的 Linux 桌面的 IP 地址，选择 VNC 作为协议，点击回车键。

![](/data/attachment/album/201902/16/160226iwd2r5wugn703qwd.png)

如果你之前选择的验证选项是“新连接必须询问访问许可”，RHEL 系统用户会看到这样的一个弹窗：

![](/data/attachment/album/201902/16/160229wkgpdsrlk4gbykkz.png)

点击“接受”以成功进行远程连接。

如果你选择用密码验证连接，Remmina 会向你询问密码。

![](/data/attachment/album/201902/16/160232vvv6z26xx69e662b.png)

输入密码然后“确认”，你应该能连接到远程电脑。

![](/data/attachment/album/201902/16/160239eb1ph1e2dy1ihdwb.png)

### 使用 Remmina

Remmina 提供如上图所示的标签化的 UI，就好像一个浏览器一样。在上图所示的左上角你可以看到两个标签：一个是之前建立的 WIndows 10 连接，另一个新的是 RHEL 连接。

在窗口的左侧，有一个有着“缩放窗口”、“全屏模式”、“偏好”、“截屏”、“断开连接”等选项的工具栏。你可以自己探索看那种适合你。

你也可以通过点击左上角的“+”号创建保存过的连接。根据你的连接情况填好表单点击“保存”。以下是一个 Windows 10 RDP 连接的示例：

![](/data/attachment/album/201902/16/160243tgoopvohnohogfjn.png)

下次你打开 Remmina 时连接就在那了。

![](/data/attachment/album/201902/16/160244h022xd6n6l773lo6.png)

点击一下它，你不用补充细节就可以建立连接了。

### 补充说明

当你使用远程桌面软件时，你所有的操作都在远程桌面上消耗资源 —— Remmina（或者其它类似软件）仅仅是一种与远程桌面交互的方式。你也可以通过 SSH 远程访问一台电脑，但那将会让你在那台电脑上局限于仅能使用文字的终端。

你也应当注意到当你允许你的电脑远程连接时，如果一名攻击者用这种方法获得你电脑的访问权同样会给你带来严重损失。因此当你不频繁使用远程桌面时，禁止远程桌面连接以及其在防火墙中相关的服务是很明智的做法。

---

via: <https://opensource.com/article/18/6/linux-remote-desktop>

作者：[Kedar Vijay Kulkarni](https://opensource.com/users/kkulkarn) 选题：[lujun9972](https://github.com/lujun9972) 译者：[tomjlw](https://github.com/tomjlw) 校对：[wxy](https://github.com/wxy)

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


丰田汽车的 Linux 之旅

Summary: 今天，在全球市场上，丰田和雷克萨斯的全部车型都使用了 AGL。

好

来自223.104.191.208的 Opera Mobile 48.2|Android 8.1 用户

丰田车主路过……

今天，在全球市场上，丰田和雷克萨斯的全部车型都使用了 AGL。

我之前跟丰田汽车北美分公司的 Brian.R.Lyons（丰田发言人）聊了聊，话题是关于 Linux 在丰田和雷克萨斯汽车的信息娱乐系统上的实施方案。我了解到一些汽车制造商使用了 Automotive Grade Linux（AGL）。

然后我写了一篇短文，记录了我和 Brian 的讨论内容，谈及了丰田和 Linux 的一些渊源。希望 Linux 的狂热粉丝们能够喜欢这次对话。

全部的[丰田和雷克萨斯汽车都将会使用 Automotive Grade Linux（AGL）](https://www.linuxfoundation.org/press-release/2018/01/automotive-grade-linux-hits-road-globally-toyota-amazon-alexa-joins-agl-support-voice-recognition/)，主要是用于车载信息娱乐系统。这项措施对于丰田集团来说是至关重要的，因为据 Lyons 先生所说：“作为技术的引领者之一，丰田认识到，赶上科技快速进步最好的方法就是接受开源发展的理念。”

丰田和众多汽车制造公司都认为，与使用非自由软件相比，采用基于 Linux 的操作系统在更新和升级方面会更加廉价和快捷。

这简直太棒了！ Linux 终于跟汽车结合起来了。我每天都在电脑上使用 Linux；能看到这个优秀的软件在一个完全不同的产业领域里大展拳脚真是太好了。

我很好奇丰田是什么时候开始使用 [Automotive Grade Linux（AGL）](https://www.automotivelinux.org/)的。按照 Lyons 先生的说法，这要追溯到 2011 年。

>
> “自 AGL 项目在五年前启动之始，作为活跃的会员和贡献者，丰田与其他顶级制造商和供应商展开合作，着手开发一个基于 Linux 的强大平台，并不断地增强其功能和安全性。”
>
>
>

![丰田信息娱乐系统](/data/attachment/album/201902/17/093215omrgzsdxgzgmj87c.jpg)

[丰田于 2011 年加入了 Linux 基金会](https://www.linuxfoundation.org/press-release/2011/07/toyota-joins-linux-foundation/)，与其他汽车制造商和软件公司就 IVI（车内信息娱乐系统）展开讨论，最终在 2012 年，Linux 基金会内部成立了 Automotive Grade Linux 工作组。

丰田在 AGL 工作组里首先提出了“代码优先”的策略，这在开源领域是很常见的做法。然后丰田和其他汽车制造商、IVI 一线厂家，软件公司等各方展开对话，根据各方的技术需求详细制定了初始方向。

在加入 Linux 基金会的时候，丰田就已经意识到，在一线公司之间共享软件代码将会是至关重要的。因为要维护如此复杂的软件系统，对于任何一家顶级厂商都是一笔不小的开销。丰田和它的一级供货商想把更多的资源用在开发新功能和新的用户体验上，而不是用在维护各自的代码上。

各个汽车公司联合起来深入合作是一件大事。许多公司都达成了这样的共识，因为他们都发现开发维护私有软件其实更费钱。

今天，在全球市场上，丰田和雷克萨斯的全部车型都使用了 AGL。

身为雷克萨斯的销售人员，我认为这是一大进步。我和其他销售顾问都曾接待过很多回来找技术专员的客户，他们想更多的了解自己车上的信息娱乐系统到底都能做些什么。

这件事本身对于 Linux 社区和用户是个重大利好。虽然那个我们每天都在使用的操作系统变了模样，被推到了更广阔的舞台上，但它仍然是那个 Linux，简单、包容而强大。

未来将会如何发展呢？我希望它能少出差错，为消费者带来更佳的用户体验。

---

via: <https://itsfoss.com/toyota-motors-linux-journey>

作者：[Malcolm Dean](https://itsfoss.com/toyota-motors-linux-journey) 选题：[lujun9972](https://github.com/lujun9972) 译者：[jdh8383](https://github.com/jdh8383) 校对：[wxy](https://github.com/wxy)

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


4 个独特的 Linux 终端模拟器

Summary: 这四个不同的终端模拟器 —— 不仅可以完成工作，还可以增加一些乐趣。

这四个不同的终端模拟器 —— 不仅可以完成工作，还可以增加一些乐趣。

>
> 这四个不同的终端模拟器 —— 不仅可以完成工作，还可以增加一些乐趣。
>
>
>

![](/data/attachment/album/201902/17/095752ne3hg8z88zhqf4zr.jpg)

让我们面对现实，如果你是 Linux 管理员，那么你要用命令行来工作。为此，你将使用终端模拟器（LCTT 译注：常简称为“终端”，与终端本身的原意不同）。最有可能的是，你选择的发行版预先安装了一个可以完成工作的默认终端模拟器。但这是有很多选择可供选择的 Linux，所以这种思想自然也适用于终端模拟器。实际上，如果你打开发行版的图形界面的包管理器（或从命令行搜索），你将找到大量可能的选择。其中许多是非常简单的工具；然而，有些是真正独特的。

在本文中，我将重点介绍四个这样的终端模拟器，它们不仅可以完成工作，而且可以使工作变得更有趣或更好玩。那么，让我们来看看这些终端。

### Tilda

[Tilda](http://tilda.sourceforge.net/tildadoc.php) 是为 Gtk 设计的，是一种酷炫的下拉终端。这意味着该终端始终运行在后台，可以随时从显示器顶部拉下来（就像 Guake 和 Yakuake）。让 Tilda 超越许多其他产品的原因是该终端可用的配置选项数量（图 1）。

![](/data/attachment/album/201902/17/095752ogrmigvzr731ggvr.jpg)

可以从标准的软件库安装 Tilda。在基于 Ubuntu（或 Debian）的发行版上，安装非常简单：

```
sudo apt-get install tilda -y
```

安装完成后，从桌面菜单中打开 Tilda，这也将打开其配置窗口。根据你的喜好配置应用程序，然后关闭配置窗口。然后，你可以通过点击 `F1` 热键来打开和关闭 Tilda。对使用 Tilda 的一个警告是，在第一次运行后，你将找不到有关如何打开配置向导的任何提示。别担心。只要运行命令 `tilda -C`，它将打开配置窗口，同时仍会保留你之前设置的选项。

可用选项包括：

* 终端大小和位置
* 字体和颜色配置
* 自动隐藏
* 标题
* 自定义命令
* URL 处理
* 透明度
* 动画
* 滚动
* 等等

我喜欢这些类型的终端是因为当你不需要时它们很容易就会消失，只需按一下按钮即可。对于那些不断进出于终端的人来说，像 Tilda 这样的工具是理想的选择。

### Aterm

Aterm 在我心中占有特殊的位置，因为它是我第一次使用的终端之一，它让我意识到 Linux 的灵活性。 这要回到 AfterStep 成为我选择的窗口管理器时（没用了太久），而且那时我是命令行新手。Aterm 提供的是一个高度可定制的终端仿真器，同时帮助我了解了使用终端的细节（如何给命令添加选项和开关）。或许你会问：“你觉得怎么样？”。因为 Aterm 从未有过用于定制选项的图形界面。要使用任何特殊选项运行 Aterm，必须以命令选项的方式运行。例如，假设你要启用透明度、绿色文本、白色高亮和无滚动条。为此，请运行以下命令：

```
aterm -tr -fg green -bg white +xb
```

最终结果（`top` 命令运行用于说明）看起来如图 2 所示。

![Aterm](/data/attachment/album/201902/17/095753a07daa0zsaju8dn8.jpg "Aterm")

*图 2：使用了一些定制选项的 Aterm*

当然，你必须先安装 Aterm。幸运的是，这个应用程序仍然可以在标准软件库中找到，因此在 Ubuntu 上安装就像下面这样简单：

```
sudo apt-get install aterm -y
```

如果你想总是用这些选项打开 Aterm，最好的办法是在 `~/.bashrc` 文件中创建一个别名，如下所示：

```
alias=”aterm -tr -fg green -bg white +sb”
```

保存该文件，当你运行命令 `aterm` 时，它将始终打开这些选项。有关创建别名的更多信息，请查看[这个教程](https://www.linux.com/blog/learn/2018/12/aliases-diy-shell-commands)。

### Eterm

Eterm 是第二个真正告诉我 Linux 命令行可以带来多少乐趣的终端。Eterm 是 Enlightenment 桌面的默认终端模拟器。当我最终从 AfterStep 迁移到 Enlightenment 时（那时早在 20 世纪初），我担心我会失去所有那些很酷的美学选择。结果并非如此。实际上，Eterm 提供了许多独特的选项，同时使用终端工具栏使任务变得更容易。使用 Eterm，你可以通过从 “Background > Pixmap” 菜单条目中轻松地从大量背景图像中选择一个背景（如果你需要一个的话，图 3）。

![Eterm](/data/attachment/album/201902/17/095754yzi5xk74x5r9mczm.jpg "Eterm")

*图 3：从大量的背景图中为 Eterm 选择一个。*

还有许多其他配置选项（例如字体大小、映射警报、切换滚动条、亮度、对比度和背景图像的透明度等）。 你要确定的一件事是，在你配置 Eterm 以满足你的口味后，需要单击 “Eterm > Save User Settings”（否则，关闭应用程序时所有设置都将丢失）。

可以从标准软件库安装 Eterm，其命令如下：

```
sudo apt-get install eterm
```

### Extraterm

[Extraterm](http://extraterm.org) 应该可以赢得当今终端窗口项目最酷功能集的一些奖项。Extraterm 最独特的功能是能够以彩色框来包装命令（蓝色表示成功命令，红色表示失败命令。图 4）。

![Extraterm](/data/attachment/album/201902/17/095754cr8e86r166z0rk18.jpg "Extraterm")

*图 4：Extraterm 显示有两个失败的命令框。*

在运行命令时，Extraterm 会将命令包装在一个单独的颜色框中。如果该命令成功，则该颜色框将以蓝色轮廓显示。如果命令失败，框将以红色标出。

无法通过标准软件库安装 Extraterm。事实上，在 Linux 上运行 Extraterm（目前）的唯一方法是从该项目的 GitHub 页面[下载预编译的二进制文件](https://github.com/sedwards2009/extraterm/releases)，解压缩文件，切换到新创建的目录，然后运行命令 `./extraterm`。

当该应用程序运行后，要启用颜色框，你必须首先启用 Bash 集成功能。为此，请打开 Extraterm，然后右键单击窗口中的任意位置以显示弹出菜单。滚动，直到看到 “Inject Bash shell Integration” 的条目（图 5）。选择该条目，然后你可以开始使用这个颜色框选项。

![Extraterm](/data/attachment/album/201902/17/095754uz8wjiaq5ns8nkv1.jpg "Extraterm")

*图 5：为 Extraterm 插入 Bash 集成。。*

如果你运行了一个命令，并且看不到颜色框，则可能必须为该命令创建一个新的颜色框（因为 Extraterm 仅附带一些默认颜色框）。为此，请单击 “Extraterm” 菜单按钮（窗口右上角的三条水平线），选择 “Settings”，然后单击 “Frames” 选项卡。在此窗口中，向下滚动并单击 “New Rule” 按钮。 然后，你可以添加要使用颜色框的命令（图 6）。

![frames](/data/attachment/album/201902/17/095755l4u5duu3fu35gdbt.jpg "frames")

*图 6：为颜色框添加新规则。*

如果在此之后仍然没有看到颜色框出现，请从[下载页面](https://github.com/sedwards2009/extraterm/releases)下载 `extraterm-commands` 文件，解压缩该文件，切换到新创建的目录，然后运行命令 `sh setup_extraterm_bash.sh`。这应该可以为 Extraterm 启用颜色框。

还有更多可用于 Extraterm 的选项。我相信，一旦你开始在终端窗口上玩这个新花招，你就不会想回到标准终端了。希望开发人员可以尽快将这个应用程序提供给标准软件库（因为它很容易就可以成为最流行的终端窗口之一）。

### 更多

正如你可能预期的那样，Linux 有很多可用的终端。这四个代表四个独特的终端（至少对我来说），每个都可以帮助你运行 Linux 管理员需要运行的命令。如果你对其中一个不满意，用你的包管理器找找有什么可用的软件包。你一定会找到适合你的东西。

---

via: <https://www.linux.com/blog/learn/2018/12/4-unique-terminals-linux>

作者：[Jack Wallen](https://www.linux.com/users/jlwallen) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


极客漫画：Windows 更新

Win10的自动更新简直令人崩溃！晚上偷偷摸摸就自动更新重启了。第二天上班一看，悲剧啊！

关闭更新

关闭更新

特别是Windows 10的更新，那叫个“惨”！随时会出现蓝屏！

慢得出奇

windows还总是提醒更新，关机就要更新，然后我就进入系统设置把更新关闭了

真的是非常的真实了

来自117.136.72.19的 Microsoft Edge 18.17763|Windows 10 用户

Windows正在更新……请不要关闭您的计算机，已完成100%

……几小时过去了……

Windows正在更新……请不要关闭您的计算机，已完成100%

对不起，更新失败，正在回滚至之前的版本，已完成0%

????????????

Windows正在更新...

windows服务管理中禁用windows update服务（右键属性禁用）然后点进windows更新，提示，您的组织已关闭自动更新，yeah！

哈哈哈，看了这幅漫画都笑出眼泪了，如此的真实贴切。换Linux，换Linux，换Linux；强烈建议换Ubuntu，Fedora。

linux不一样需要更新吗

时间上，差数量级。<br />
Linux一般几分钟搞定。Windows的话，看运气吧。

就事论事啊，我的windows10更新一般10分钟内就搞定了，那种1个小时的更新很难遇到一次；

![](/data/attachment/album/201902/17/112427ewsgwd747m46k675.png)

嗨，还在使用 Windows 的兄弟们，你是不是又更新了？

那么，拿起手机，去喝杯咖啡吧，请稍………………候……………再…………回………来……吧…

---

via: <http://turnoff.us/geek/windows-update/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者 & 点评：[wxy](https://github.com/wxy) 校对 & 合成：[wxy](https://github.com/wxy)

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


14 个依然很棒的 Linux ASCII 游戏

Summary: 你或许不相信，有一些 ASCII 游戏被证明是非常容易上瘾的

不错不错。我上学的时候在终端玩Bash脚本写的俄罗斯方块。那时候学校BBS还在，不少同学喜欢玩 ASCII art。

你或许不相信，有一些 ASCII 游戏被证明是非常容易上瘾的

基于文本的（或者我应该说是[基于终端的](https://itsfoss.com/best-command-line-games-linux/)）游戏在十年前非常流行 —— 当时还没有像<ruby> 战神 <rt>  God Of War </rt></ruby>、<ruby> 荒野大镖客：救赎 2 <rt>  Red Dead Redemption 2 </rt></ruby>或<ruby> 蜘蛛侠 <rt>  Spiderman </rt></ruby>这样的视觉游戏大作。

当然，Linux 平台有很多好游戏 —— 虽然并不总是“最新和最好”。但是，有一些 ASCII 游戏，却是你永远不会玩腻的。

你或许不相信，有一些 ASCII 游戏被证明是非常容易上瘾的（所以，我可能需要一段时间才能继续写下一篇文章，或者我可能会被解雇？ —— 帮帮我！）

哈哈，开个玩笑。让我们来看看最好的 ASCII 游戏吧。

**注意：**安装 ASCII 游戏可能要花费不少时间（有些可能会要求你安装其他依赖项或根本不起作用）。你甚至可能会遇到一些需要你从源代码构建的 ASCII 游戏。因此，我们只筛选出那些易于安装和运行的产品 —— 不用费劲。

### 在运行和安装 ASCII 游戏之前需要做的事情

如果你没有安装的话，某些 ASCII 游戏可能需要你安装 [Simple DirectMedia Layer](https://www.libsdl.org/)。因此，以防万一，你应该先尝试安装它，然后再尝试运行本文中提到的任何游戏。

要安装它，你需要键入如下命令：

```
sudo apt install libsdl2-2.0
sudo apt install libsdl2_mixer-2.0
```

### Linux 上最好的 ASCII 游戏

![Best Ascii games for Linux](/data/attachment/album/201902/17/210223dllgv5llluppbp0u.png)

如下列出的游戏排名不分先后。

#### 1、战争诅咒

![Curse of War ascii games](/data/attachment/album/201902/17/210226mexn291r1gczie1r.jpg)

<ruby> <a href="http://a-nikolaev.github.io/curseofwar/">  战争诅咒 </a> <rt>  Curse of War </rt></ruby>是一个有趣的策略游戏。一开始你可能会发现它有点令人困惑，但一旦你掌握了，就会喜欢上它。在启动游戏之前，我建议你在其 [主页](http://a-nikolaev.github.io/curseofwar/) 上查看该游戏规则。

你将建设基础设施、保护资源并指挥你的军队进行战斗。你所要做的就是把你的旗帜放在一个合适的位置，让你的军队来完成其余的任务。不仅仅是攻击敌人，你还需要管理和保护资源以帮助赢得战斗。

如果你之前从未玩过任何 ASCII 游戏，请耐心花一些时间来学习它、体验它的全部潜力。

##### 如何安装？

你可以在官方软件库里找到它。键入如下命令来安装它：

```
sudo apt install curseofwar
```

#### 2、ASCII 领域

![ascii sector](/data/attachment/album/201902/17/210228ekskkhggdpp7s111.jpg)

讨厌策略游戏？不用担心，<ruby> ASCII 领域 <rt>  ASCII Sector </rt></ruby>是一款具有空间环境的游戏，可让你进行大量探索。

此外，不仅仅局限于探索，你还想要采取一些行动吗？也是可以的。当然，虽然战斗体验不是最好的，但它也很有趣。当你看到各种基地、任务和探索时，会让你更加兴奋。你会在这个小小的游戏中遇到一个练级系统，你必须赚取足够的钱或进行交易才能升级你的宇宙飞船。

而这个游戏最好的地方是你可以创建自己的任务，也可以玩其他人的任务。

##### 如何安装？

你需要先从其 [官方网站](http://www.asciisector.net/download/) 下载并解压缩归档包。完成后，打开终端并输入这些命令（将 “Downloads” 文件夹替换为你解压缩文件夹所在的位置，如果解压缩文件夹位于你的主目录中，则忽略它）：

```
cd Downloads
cd asciisec
chmod +x asciisec
./asciisec
```

#### 3、DoomRL

![doom ascii game](/data/attachment/album/201902/17/210231bmyii6obdava2mib.jpg)

你肯定知道经典游戏“<ruby> 毁灭战士 <rt>  DOOM </rt></ruby>”，所以，如果你想把它像 Rogue 类游戏一样略微体验一下，DoomRL 就是适合你的游戏。它是一个基于 ASCII 的游戏，这或许让你想不到。

这是一个非常小的游戏，但是可以玩很久。

##### 如何安装？

与你对 “ASCII 领域”所做的类似，你需要从其 [下载页面](https://drl.chaosforge.org/downloads) 下载官方归档文件，然后将其解压缩到一个文件夹。

解压缩后，输入以下命令：

```
cd Downloads // navigating to the location where the unpacked folder exists
cd doomrl-linux-x64-0997
chmod +x doomrl
./doomrl
```

#### 4、金字塔建造者

![Pyramid Builder ascii game for Linux](/data/attachment/album/201902/17/210232g0n6677gkogg9agk.jpg)

<ruby> 金字塔建造者 <rt>  Pyramid Builder </rt></ruby> 是一款创新的 ASCII 游戏，你可以通过帮助建造金字塔来提升你的文明。

你需要指导工人耕种、卸载货物、并移动巨大的石头，以成功建造金字塔。

这确实是一个值得下载的 ASCII 游戏。

##### 如何安装？

只需前往其官方网站并下载包以解压缩。提取后，导航到该文件夹并运行可执行文件。

```
cd Downloads
cd pyramid_builder_linux
chmod +x pyramid_builder_linux.x86_64
./pyramid_builder_linux.x86_64
```

#### 5、DiabloRL

![Diablo ascii RPG game](/data/attachment/album/201902/17/210233o3oizcnpxfvwxwff.jpg)

如果你是一位狂热的游戏玩家，你一定听说过暴雪的<ruby> 暗黑破坏神 <rt>  Diablo </rt></ruby> 1 代，毫无疑问这是一个精彩的游戏。

现在你有机会玩一个该游戏的独特演绎版本 —— 一个 ASCII 游戏。DiabloRL 是一款非常棒的基于回合制的 Rogue 类的游戏。你可以从各种职业（战士、巫师或盗贼）中进行选择。每个职业都具有一套不同的属性，可以带来不同游戏体验。

当然，个人偏好会有所不同，但它是一个不错的暗黑破坏神“降级版”。你觉得怎么样？

#### 6、Ninvaders

![Ninvaders terminal game for Linux](/data/attachment/album/201902/17/210234bz2il6esjbplyslj.jpg)

Ninvaders 是最好的 ASCII 游戏之一，因为它是如此简单，且可以消磨时间的街机游戏。

你必须防御入侵者，需要在它们到达之前击败它们。这听起来很简单，但它极具挑战性。

##### 如何安装？

与“战争诅咒”类似，你可以在官方软件库中找到它。所以，只需输入此命令即可安装它：

```
sudo apt install ninvaders
```

#### 7、帝国

![Empire terminal game](/data/attachment/album/201902/17/210235jo46hkshiommbui0.jpg)

<ruby> 帝国 <rt>  Empire </rt></ruby>这是一款即时战略游戏，你需要互联网连接。我个人不是实时战略游戏的粉丝，但如果你是这类游戏的粉丝，你可以看看他们的 [指南](http://www.wolfpackempire.com/infopages/Guide.html) 来玩这个游戏，因为学习起来非常具有挑战性。

游戏区域包含城市、土地和水。你需要用军队、船只、飞机和其他资源扩展你的城市。通过快速扩张，你可以通过在对方动作之前摧毁它们来捕获其他城市。

##### 如何安装？

安装很简单，只需输入以下命令：

```
sudo apt install empire
```

#### 8、Nudoku

![Nudoku is a terminal version game of Sudoku](/data/attachment/album/201902/17/210237fzl75zvjsow717az.jpg)

喜欢数独游戏？好吧，你也有个 Nudoku 游戏，这是它的克隆。这是当你想放松时的一个完美的消磨时间的 ASCII 游戏。

它为你提供三个难度级别：简单、正常和困难。如果你想要挑战电脑，其难度会非常难！如果你只是想放松一下，那么就选择简单难度吧。

##### 如何安装？

安装它很容易，只需在终端输入以下命令：

```
sudo apt install nudoku
```

#### 9、Nethack

最好的地下城式 ASCII 游戏之一。如果你已经知道一些 Linux 的 ASCII 游戏，我相信这是你的最爱之一。

它具有许多不同的层（约 45 个），并且包含一堆武器、卷轴、药水、盔甲、戒指和宝石。你也可以选择“永久死亡”模式来玩试试。

在这里可不仅仅是杀戮，你还有很多需要探索的地方。

##### 如何安装？

只需按照以下命令安装它：

```
sudo apt install nethack
```

#### 10、ASCII 滑雪

![ascii jump game](/data/attachment/album/201902/17/210239wtpdpx7tlppppp3d.jpg)

<ruby> ASCII 滑雪 <rt>  ASCII Jump </rt></ruby> 是一款简单易玩的游戏，你必须沿着各种轨道滑动，同时跳跃、改变位置，并尽可能长时间地移动以达到最大距离。

即使看起来很简单，但是看看这个 ASCII 游戏视觉上的表现也是很神奇的。你可以从训练模式开始，然后进入世界杯比赛。你还可以选择你的竞争对手以及你想要开始游戏的山丘。

##### 如何安装？

只需按照以下命令安装它：

```
sudo apt install asciijump
```

#### 11、Bastet

![Bastet is tetris game in ascii form](/data/attachment/album/201902/17/210241qg111ng9nkns9a6q.jpg)

不要被这个名字误导，它实际上是俄罗斯方块游戏的一个有趣的克隆。

你不要觉得它只是另一个普通的俄罗斯方块游戏，它会为你丢下最糟糕的砖块。祝你玩得开心！

##### 如何安装？

打开终端并键入如下命令：

```
sudo apt install bastet
```

#### 12、Bombardier

![Bomabrdier game in ascii form](/data/attachment/album/201902/17/210243x5bsjbskf2zosnpk.jpg)

Bombardier 是另一个简单的 ASCII 游戏，它会让你迷上它。

在这里，你有一架直升机（或许你想称之为飞机），每一圈它都会降低，你需要投掷炸弹才能摧毁你下面的街区/建筑物。当你摧毁一个街区时，游戏还会在它显示的消息里面添加一些幽默。很好玩。

##### 如何安装？

Bombardier 可以在官方软件库中找到，所以只需在终端中键入以下内容即可安装它：

```
sudo apt install bombardier
```

#### 13、Angband

![Angband ascii game](/data/attachment/album/201902/17/210245ymuj00ummwjovsoe.jpg)

一个很酷的地下城探索游戏，界面整洁。在探索该游戏时，你可以在一个屏幕上看到所有重要信息。

它包含不同种类的种族可供选择角色。你可以是精灵、霍比特人、矮人或其他什么，有十几种可供选择。请记住，你需要在最后击败黑暗之王，所以尽可能升级你的武器并做好准备。

##### 如何安装？

直接键入如下命令：

```
sudo apt install angband
```

#### 14、GNU 国际象棋

![GNU Chess is a chess game that you can play in Linux terminal](/data/attachment/album/201902/17/210247mvzw18lluavrhv8w.jpg)

为什么不下盘棋呢？这是我最喜欢的策略游戏了！

但是，除非你知道如何使用代表的符号来描述下一步行动，否则 GNU 国际象棋可能很难玩。当然，作为一个 ASCII 游戏，它不太好交互，所以它会要求你记录你的移动并显示输出（当它等待计算机思考它的下一步行动时）。

##### 如何安装？

如果你了解国际象棋的代表符号，请输入以下命令从终端安装它：

```
sudo apt install gnuchess
```

#### 一些荣誉奖

正如我之前提到的，我们试图向你推荐最好的（也是最容易在 Linux 机器上安装的那些） ASCII 游戏。

然而，有一些标志性的 ASCII 游戏值得关注，它们需要更多的安装工作（你可以获得源代码，但需要构建它/安装它）。

其中一些游戏是：

* [Cataclysm: Dark Days Ahead](https://github.com/CleverRaven/Cataclysm-DDA)
* [Brogue](https://sites.google.com/site/broguegame/)
* [Dwarf Fortress](http://www.bay12games.com/dwarves/index.html)

你可以按照我们的 [从源代码安装软件的完全指南](/article-9172-1.html) 来进行。

### 总结

我们提到的哪些 ASCII 游戏适合你？我们错过了你最喜欢的吗？

请在下面的评论中告诉我们你的想法。

---

via: <https://itsfoss.com/best-ascii-games/>

作者：[Ankush Das](https://itsfoss.com/author/ankush/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


开始使用 Budgie 吧，一款 Linux 桌面环境

Alt+space能唤出窗口菜单，其中的选项有对应的快捷键吗？

>
> 使用 Budgie 按需配置你的桌面，这是我们开源工具系列中的第 18 个工具，它将在 2019 年提高你的工作效率。
>
>
>

![](/data/attachment/album/201902/17/212759ge0j9a5j0tpzsffs.png)

每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心，渴望开启新的一年，当然，“抛弃旧的，拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件，但事实上并不用这样。

这是我挑选出的 19 个新的（或者对你而言新的）开源工具中的第 18 个工具来帮助你在 2019 年更有效率。

### Budgie 桌面

Linux 中有许多桌面环境。从易于使用并有令人惊叹图形界面的 [GNOME 桌面](https://www.gnome.org/)（在大多数主要 Linux 发行版上是默认桌面）和 [KDE](https://www.kde.org/)，到极简主义的 [Openbox](http://openbox.org/wiki/Main_Page)，再到高度可配置的平铺化的 [i3](https://i3wm.org/)，有很多选择。我要寻找的桌面环境需要速度、不引人注目和干净的用户体验。当桌面不适合你时，很难会有高效率。

[Budgie 桌面](https://getsol.us/solus/experiences/)是 [Solus](https://getsol.us/home/) Linux 发行版的默认桌面，它在大多数主要 Linux 发行版的附加软件包中提供。它基于 GNOME，并使用了许多你可能已经在计算机上使用的相同工具和库。

其默认桌面非常简约，只有面板和空白桌面。Budgie 包含一个集成的侧边栏（称为 Raven），通过它可以快速访问日历、音频控件和设置菜单。Raven 还包含一个集成的通知区域，其中包含与 MacOS 类似的统一系统消息显示。

![](/data/attachment/album/201902/17/212816y3dc6t6oa2ka624q.png)

点击 Raven 中的齿轮图标会显示 Budgie 的控制面板及其配置。由于 Budgie 仍处于开发阶段，与 GNOME 或 KDE 相比，它的选项有点少，我希望随着时间的推移它会有更多的选项。顶部面板选项允许用户配置顶部面板的排序、位置和内容，这很不错。

![](/data/attachment/album/201902/17/212824s4z8kkqho9pgo9zq.png)

Budgie 的 Welcome 应用（首次登录时展示）包含安装其他软件、面板小程序、截图和 Flatpack 软件包的选项。这些小程序有处理网络、截图、额外的时钟和计时器等等。

![](/data/attachment/album/201902/17/212830ghxppvfhczuvzzvn.png)

Budgie 提供干净稳定的桌面。它响应迅速，有许多选项，允许你根据需要自定义它。

---

via: <https://opensource.com/article/19/1/productivity-tool-budgie-desktop>

作者：[Kevin Sonney](https://opensource.com/users/ksonney "Kevin Sonney") 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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