2016年9月

你在 Python 中用过异步编程吗?本文中我会告诉你怎样做,而且用一个能工作的例子来展示它:这是一个流行的贪吃蛇游戏,而且是为多人游戏而设计的。

介绍和理论部分参见“第一部分 异步化”。

3、编写游戏循环主体

游戏循环是每一个游戏的核心。它持续地运行以读取玩家的输入、更新游戏的状态,并且在屏幕上渲染游戏结果。在在线游戏中,游戏循环分为客户端和服务端两部分,所以一般有两个循环通过网络通信。通常客户端的角色是获取玩家输入,比如按键或者鼠标移动,将数据传输给服务端,然后接收需要渲染的数据。服务端处理来自玩家的所有数据,更新游戏的状态,执行渲染下一帧的必要计算,然后将结果传回客户端,例如游戏中对象的新位置。如果没有可靠的理由,不混淆客户端和服务端的角色是一件很重要的事。如果你在客户端执行游戏逻辑的计算,很容易就会和其它客户端失去同步,其实你的游戏也可以通过简单地传递客户端的数据来创建。

游戏循环的一次迭代称为一个 嘀嗒 tick 。嘀嗒是一个事件,表示当前游戏循环的迭代已经结束,下一帧(或者多帧)的数据已经就绪。

在后面的例子中,我们使用相同的客户端,它使用 WebSocket 从一个网页上连接到服务端。它执行一个简单的循环,将按键码发送给服务端,并显示来自服务端的所有信息。客户端代码戳这里

例子 3.1:基本游戏循环

我们使用 aiohttp 库来创建游戏服务器。它可以通过 asyncio 创建网页服务器和客户端。这个库的一个优势是它同时支持普通 http 请求和 websocket。所以我们不用其他网页服务器来渲染游戏的 html 页面。

下面是启动服务器的方法:

app = web.Application()
app["sockets"] = []

asyncio.ensure_future(game_loop(app))

app.router.add_route('GET', '/connect', wshandler)
app.router.add_route('GET', '/', handle)

web.run_app(app)

web.run_app 是创建服务主任务的快捷方法,通过它的 run_forever() 方法来执行 asyncio 事件循环。建议你查看这个方法的源码,弄清楚服务器到底是如何创建和结束的。

app 变量就是一个类似于字典的对象,它用于在所连接的客户端之间共享数据。我们使用它来存储连接的套接字的列表。随后会用这个列表来给所有连接的客户端发送消息。asyncio.ensure_future() 调用会启动主游戏循环的任务,每隔2 秒向客户端发送嘀嗒消息。这个任务会在同样的 asyncio 事件循环中和网页服务器并行执行。

有两个网页请求处理器:handle 是提供 html 页面的处理器;wshandler 是主要的 websocket 服务器任务,处理和客户端之间的交互。在事件循环中,每一个连接的客户端都会创建一个新的 wshandler 任务。这个任务会添加客户端的套接字到列表中,以便 game_loop 任务可以给所有的客户端发送消息。然后它将随同消息回显客户端的每个击键。

在启动的任务中,我们在 asyncio 的主事件循环中启动 worker 循环。任务之间的切换发生在它们之间任何一个使用 await语句来等待某个协程结束时。例如 asyncio.sleep 仅仅是将程序执行权交给调度器一段指定的时间;ws.receive 等待 websocket 的消息,此时调度器可能切换到其它任务。

在浏览器中打开主页,连接上服务器后,试试随便按下键。它们的键值会从服务端返回,每隔 2 秒这个数字会被游戏循环中发给所有客户端的嘀嗒消息所覆盖。

我们刚刚创建了一个处理客户端按键的服务器,主游戏循环在后台做一些处理,周期性地同时更新所有的客户端。

例子 3.2: 根据请求启动游戏

在前一个例子中,在服务器的生命周期内,游戏循环一直运行着。但是现实中,如果没有一个人连接服务器,空运行游戏循环通常是不合理的。而且,同一个服务器上可能有不同的“游戏房间”。在这种假设下,每一个玩家“创建”一个游戏会话(比如说,多人游戏中的一个比赛或者大型多人游戏中的副本),这样其他用户可以加入其中。当游戏会话开始时,游戏循环才开始执行。

在这个例子中,我们使用一个全局标记来检测游戏循环是否在执行。当第一个用户发起连接时,启动它。最开始,游戏循环没有执行,标记设置为 False。游戏循环是通过客户端的处理方法启动的。

  if app["game_is_running"] == False:
        asyncio.ensure_future(game_loop(app))

game_loop() 运行时,这个标记设置为 True;当所有客户端都断开连接时,其又被设置为 False

例子 3.3:管理任务

这个例子用来解释如何和任务对象协同工作。我们把游戏循环的任务直接存储在游戏循环的全局字典中,代替标记的使用。在像这样的一个简单例子中并不一定是最优的,但是有时候你可能需要控制所有已经启动的任务。

    if app["game_loop"] is None or \
       app["game_loop"].cancelled():
        app["game_loop"] = asyncio.ensure_future(game_loop(app))

这里 ensure_future() 返回我们存放在全局字典中的任务对象,当所有用户都断开连接时,我们使用下面方式取消任务:

    app["game_loop"].cancel()

这个 cancel() 调用将通知调度器不要向这个协程传递执行权,而且将它的状态设置为已取消:cancelled,之后可以通过 cancelled() 方法来检查是否已取消。这里有一个值得一提的小注意点:当你持有一个任务对象的外部引用时,而这个任务执行中发生了异常,这个异常不会抛出。取而代之的是为这个任务设置一个异常状态,可以通过 exception() 方法来检查是否出现了异常。这种悄无声息地失败在调试时不是很有用。所以,你可能想用抛出所有异常来取代这种做法。你可以对所有未完成的任务显式地调用 result() 来实现。可以通过如下的回调来实现:

    app["game_loop"].add_done_callback(lambda t: t.result())

如果我们打算在我们代码中取消这个任务,但是又不想产生 CancelError 异常,有一个检查 cancelled 状态的点:

    app["game_loop"].add_done_callback(lambda t: t.result()
                                       if not t.cancelled() else None)

注意仅当你持有任务对象的引用时才需要这么做。在前一个例子,所有的异常都是没有额外的回调,直接抛出所有异常。

例子 3.4:等待多个事件

在许多场景下,在客户端的处理方法中你需要等待多个事件的发生。除了来自客户端的消息,你可能需要等待不同类型事件的发生。比如,如果你的游戏时间有限制,那么你可能需要等一个来自定时器的信号。或者你需要使用管道来等待来自其它进程的消息。亦或者是使用分布式消息系统的网络中其它服务器的信息。

为了简单起见,这个例子是基于例子 3.1。但是这个例子中我们使用 Condition 对象来与已连接的客户端保持游戏循环的同步。我们不保存套接字的全局列表,因为只在该处理方法中使用套接字。当游戏循环停止迭代时,我们使用 Condition.notify_all() 方法来通知所有的客户端。这个方法允许在 asyncio 的事件循环中使用发布/订阅的模式。

为了等待这两个事件,首先我们使用 ensure_future() 来封装任务中这个可等待对象。

    if not recv_task:
        recv_task = asyncio.ensure_future(ws.receive())
    if not tick_task:
        await tick.acquire()
        tick_task = asyncio.ensure_future(tick.wait())

在我们调用 Condition.wait() 之前,我们需要在它后面获取一把锁。这就是我们为什么先调用 tick.acquire() 的原因。在调用 tick.wait() 之后,锁会被释放,这样其他的协程也可以使用它。但是当我们收到通知时,会重新获取锁,所以在收到通知后需要调用 tick.release() 来释放它。

我们使用 asyncio.wait() 协程来等待两个任务。

    done, pending = await asyncio.wait(
        [recv_task,
         tick_task],
        return_when=asyncio.FIRST_COMPLETED)

程序会阻塞,直到列表中的任意一个任务完成。然后它返回两个列表:执行完成的任务列表和仍然在执行的任务列表。如果任务执行完成了,其对应变量赋值为 None,所以在下一个迭代时,它可能会被再次创建。

例子 3.5: 结合多个线程

在这个例子中,我们结合 asyncio 循环和线程,在一个单独的线程中执行主游戏循环。我之前提到过,由于 GIL 的存在,Python 代码的真正并行执行是不可能的。所以使用其它线程来执行复杂计算并不是一个好主意。然而,在使用 asyncio 时结合线程有原因的:当我们使用的其它库不支持 asyncio 时就需要。在主线程中调用这些库会阻塞循环的执行,所以异步使用他们的唯一方法是在不同的线程中使用他们。

我们使用 asyncio 循环的run_in_executor() 方法和 ThreadPoolExecutor 来执行游戏循环。注意 game_loop() 已经不再是一个协程了。它是一个由其它线程执行的函数。然而我们需要和主线程交互,在游戏事件到来时通知客户端。asyncio 本身不是线程安全的,它提供了可以在其它线程中执行你的代码的方法。普通函数有 call_soon_threadsafe(),协程有 run_coroutine_threadsafe()。我们在 notify() 协程中增加了通知客户端游戏的嘀嗒的代码,然后通过另外一个线程执行主事件循环。

def game_loop(asyncio_loop):
    print("Game loop thread id {}".format(threading.get_ident()))
    async def notify():
        print("Notify thread id {}".format(threading.get_ident()))
        await tick.acquire()
        tick.notify_all()
        tick.release()

    while 1:
        task = asyncio.run_coroutine_threadsafe(notify(), asyncio_loop)
        # blocking the thread
        sleep(1)
        # make sure the task has finished
        task.result()

当你执行这个例子时,你会看到 “Notify thread id” 和 “Main thread id” 相等,因为 notify() 协程在主线程中执行。与此同时 sleep(1) 在另外一个线程中执行,因此它不会阻塞主事件循环。

例子 3.6:多进程和扩展

单线程的服务器可能运行得很好,但是它只能使用一个 CPU 核。为了将服务扩展到多核,我们需要执行多个进程,每个进程执行各自的事件循环。这样我们需要在进程间交互信息或者共享游戏的数据。而且在一个游戏中经常需要进行复杂的计算,例如路径查找之类。这些任务有时候在一个游戏嘀嗒中没法快速完成。在协程中不推荐进行费时的计算,因为它会阻塞事件的处理。在这种情况下,将这个复杂任务交给其它并行执行的进程可能更合理。

最简单的使用多个核的方法是启动多个使用单核的服务器,就像之前的例子中一样,每个服务器占用不同的端口。你可以使用 supervisord 或者其它进程控制的系统。这个时候你需要一个像 HAProxy 这样的负载均衡器,使得连接的客户端分布在多个进程间。已经有一些可以连接 asyncio 和一些流行的消息及存储系统的适配系统。例如:

你可以在 github 或者 pypi 上找到其它的软件包,大部分以 aio 开头。

使用网络服务在存储持久状态和交换某些信息时可能比较有效。但是如果你需要进行进程间通信的实时处理,它的性能可能不足。此时,使用标准的 unix 管道可能更合适。asyncio 支持管道,在aiohttp仓库有个 使用管道的服务器的非常底层的例子

在当前的例子中,我们使用 Python 的高层类库 multiprocessing 来在不同的核上启动复杂的计算,使用 multiprocessing.Queue 来进行进程间的消息交互。不幸的是,当前的 multiprocessing 实现与 asyncio 不兼容。所以每一个阻塞方法的调用都会阻塞事件循环。但是此时线程正好可以起到帮助作用,因为如果在不同线程里面执行 multiprocessing 的代码,它就不会阻塞主线程。所有我们需要做的就是把所有进程间的通信放到另外一个线程中去。这个例子会解释如何使用这个方法。和上面的多线程例子非常类似,但是我们从线程中创建的是一个新的进程。

def game_loop(asyncio_loop):
    # coroutine to run in main thread
    async def notify():
        await tick.acquire()
        tick.notify_all()
        tick.release()

    queue = Queue()

    # function to run in a different process
    def worker():
        while 1:
            print("doing heavy calculation in process {}".format(os.getpid()))
            sleep(1)
            queue.put("calculation result")

    Process(target=worker).start()

    while 1:
        # blocks this thread but not main thread with event loop
        result = queue.get()
        print("getting {} in process {}".format(result, os.getpid()))
        task = asyncio.run_coroutine_threadsafe(notify(), asyncio_loop)
        task.result()

这里我们在另外一个进程中运行 worker() 函数。它包括一个执行复杂计算并把计算结果放到 queue 中的循环,这个 queuemultiprocessing.Queue 的实例。然后我们就可以在另外一个线程的主事件循环中获取结果并通知客户端,就和例子 3.5 一样。这个例子已经非常简化了,它没有合理的结束进程。而且在真实的游戏中,我们可能需要另外一个队列来将数据传递给 worker

有一个项目叫 aioprocessing,它封装了 multiprocessing,使得它可以和 asyncio 兼容。但是实际上它只是和上面例子使用了完全一样的方法:从线程中创建进程。它并没有给你带来任何方便,除了它使用了简单的接口隐藏了后面的这些技巧。希望在 Python 的下一个版本中,我们能有一个基于协程且支持 asynciomultiprocessing 库。

注意!如果你从主线程或者主进程中创建了一个不同的线程或者子进程来运行另外一个 asyncio 事件循环,你需要显式地使用 asyncio.new_event_loop() 来创建循环,不然的话可能程序不会正常工作。

via: https://7webpages.com/blog/writing-online-multiplayer-game-with-python-and-asyncio-writing-game-loop/

作者:Kyrylo Subbotin 译者:chunyang-wen 校对:wxy

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

(题图来自:deviantart.com

对新一代的打包格式开始渗透到 Linux 生态系统中的深入观察

最近我们听到越来越多的有关于 Ubuntu 的 Snap 包和由 Red Hat 员工 Alexander Larsson 创造的 Flatpak (曾经叫做 xdg-app)的消息。

这两种下一代打包方法在本质上拥有相同的目标和特点:即不依赖于第三方系统功能库的独立包装。

这种 Linux 新技术方向似乎自然会让人脑海中浮现这样的问题:独立包的优点/缺点是什么?这是否让我们拥有更好的 Linux 系统?其背后的动机是什么?

为了回答这些问题,让我们先深入了解一下 Snap 和 Flatpak。

动机

根据 FlatpakSnap 的声明,背后的主要动机是使同一版本的应用程序能够运行在多个 Linux 发行版。

“从一开始它的主要目标是允许相同的应用程序运行在各种 Linux 发行版和操作系统上。” —— Flatpak
“……‘snap’ 通用 Linux 包格式,使简单的二进制包能够完美的、安全的运行在任何 Linux 桌面、服务器、云和设备上。” —— Snap

说得更具体一点,站在 Snap 和 Flatpak (以下称之为 S&F)背后的人认为,Linux 平台存在碎片化的问题。

这个问题导致了开发者们需要做许多不必要的工作来使他的软件能够运行在各种不同的发行版上,这影响了整个平台的前进。

所以,作为 Linux 发行版(Ubuntu 和 Red Hat)的领导者,他们希望消除这个障碍,推动平台发展。

但是,是否是更多的个人收益刺激了 S&F 的开发?

个人收益?

虽然没有任何官方声明,但是试想一下,如果能够创造这种可能会被大多数发行版(即便不是全部)所采用的打包方式,那么这个项目的领导者将可能成为一个能够决定 Linux 大船航向的重要人物。

优势

这种独立包的好处多多,并且取决于不同的因素。

这些因素基本上可以归为两类:

用户角度

+ 从 Liunx 用户的观点来看:Snap 和 Flatpak 带来了将任何软件包(软件或应用)安装在用户使用的任何发行版上的可能性。

例如你在使用一个不是很流行的发行版,由于开发工作的缺乏,它的软件仓库只有很稀少的包。现在,通过 S&F 你就可以显著的增加包的数量,这是一个多么美好的事情。

+ 同样,对于使用流行的发行版的用户,即使该发行版的软件仓库上有很多的包,他也可以在不改变它现有的功能库的同时安装一个新的包。

比方说, 一个 Debian 的用户想要安装一个 “测试分支” 的包,但是他又不想将他的整个系统变成测试版(来让该包运行在更新的功能库上)。现在,他就可以简单的想安装哪个版本就安装哪个版本,而不需要考虑库的问题。

对于持后者观点的人,可能基本上都是使用源文件编译他们的包的人,然而,除非你使用类似 Gentoo 这样基于源代码的发行版,否则大多数用户将从头编译视为是一个恶心到吐的事情。

+ 高级用户,或者称之为 “拥有安全意识的用户” 可能会觉得更容易接受这种类型的包,只要它们来自可靠来源,这种包倾向于提供另一层隔离,因为它们通常是与系统包想隔离的。

* 不论是 Snap 还是 Flatpak 都在不断努力增强它们的安全性,通常他们都使用 “沙盒化” 来隔离,以防止它们可能携带病毒感染整个系统,就像微软 Windows 系统中的 .exe 程序一样。(关于微软和 S&F 后面还会谈到)

开发者角度

与普通用户相比,对于开发者来说,开发 S&F 包的优点可能更加清楚。这一点已经在上一节有所提示。

尽管如此,这些优点有:

+ S&F 通过统一开发的过程,将多发行版的开发变得简单了起来。对于需要将他的应用运行在多个发行版的开发者来说,这大大的减少了他们的工作量。

++ 因此,开发者能够更容易的使他的应用运行在更多的发行版上。

+ S&F 允许开发者私自发布他的包,不需要依靠发行版维护者在每一个/每一次发行版中发布他的包。

++ 通过上述方法,开发者可以不依赖发行版而直接获取到用户安装和卸载其软件的统计数据。

++ 同样是通过上述方法,开发者可以更好的直接与用户互动,而不需要通过中间媒介,比如发行版这种中间媒介。

缺点

膨胀。就是这么简单。Flatpak 和 Snap 并不是凭空变出来它的依赖关系。相反,它是通过将依赖关系预构建在其中来代替使用系统中的依赖关系。

就像谚语说的:“山不来就我,我就去就山”。

之前提到安全意识强的用户会喜欢 S&F 提供的额外的一层隔离,只要该应用来自一个受信任的来源。但是从另外一个角度看,对这方面了解较少的用户,可能会从一个不靠谱的地方弄来一个包含恶意软件的包从而导致危害。

上面提到的观点可以说是有很有意义的,虽说今天的流行方法,像 PPA、overlay 等也可能是来自不受信任的来源。

但是,S&F 包更加增加这个风险,因为恶意软件开发者只需要开发一个版本就可以感染各种发行版。相反,如果没有 S&F,恶意软件的开发者就需要创建不同的版本以适应不同的发行版。

原来微软一直是正确的吗?

考虑到上面提到的,很显然,在大多数情况下,使用 S&F 包的优点超过缺点。

至少对于二进制发行版的用户,或者重点不是轻量级的发行版的用户来说是这样的。

这促使我问出这个问题,可能微软一直是正确的吗?如果是的,那么当 S&F 变成 Linux 的标准后,你还会一如既往的使用 Linux 或者类 Unix 系统吗?

很显然,时间会是这个问题的最好答案。

不过,我认为,即使不完全正确,但是微软有些地方也是值得赞扬的,并且以我的观点来看,所有这些方式在 Linux 上都立马能用也确实是一个亮点。


via: http://www.iwillfolo.com/ubuntus-snap-red-hats-flatpack-and-is-one-fits-all-linux-packages-useful/

作者:Liron 译者:Chao-zhi 校对:wxy

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

Linux 用户又有一个木马需要苦恼了,就像以往一样,这些坏蛋大多部署在被劫持的 Linux 系统上,并在接受到命令后发起 DDoS 攻击。

发现了这件事的 Dr.Web 的安全研究人员说,木马似乎是通过 破壳漏洞 Shellshock 感染的这些 Linux 机器——现在仍然有很多设备没有补上这个漏洞。

该木马被命名为 Linux.DDoS.93,它首要会修改 /var/run/dhcpclient-eth0.pid 这个文件,并通过它在计算机启动时运行。如果该文件不存在,就会自己创建一个。

当该木马运行起来以后会进行初始化,它会启动两个进程,一个用于与 C&C (控制)服务器通讯,另外一个用于确保木马的父进程一直运行。

该木马启动 25 个子进程进行 DDoS 攻击

当控制该木马网络的攻击者发起攻击命令时,这个木马会启动 25 个子进程来进行 DDoS 攻击。

当前,该木马可以发出 UDP 洪泛(针对随机或特定端口),TCP 洪泛(简单的包,或给每个包随机增加至多 4096 字节的数据)和 HTTP 洪泛(通过 POST、GET 或 HEAD 请求)。

而且,该木马还能自我更新、自我删除、终止自己的进程、ping、从 C&C 服务器下载和运行文件。

当它发现某些名字时会关闭

这个木马还包括一个功能,如果在扫描计算机内存并列出活动的进程时发现如下字符串会关闭自己:

privmsg
getlocalip
kaiten
brian krebs
botnet
bitcoin mine
litecoin mine
rootkit
keylogger
ddosing
nulling
hackforums
skiddie
script kiddie
blackhat
whitehat
greyhat
grayhat
doxing
malware
bootkit
ransomware
spyware
botkiller

这些字符串大多数与信息安全领域有关,似乎是为了防止安全研究人员的反向工程研究,或者是为了避免感染该恶意软件作者自己的机器。

在感染过程中,该木马也会扫描它的旧版本,并会关闭旧版本然后安装一个新的。这意味着这是一个自动更新系统,该木马的最新版本总是会出现在被感染的机器上。

Linux 是过去一个月以来最热门的木马攻击平台,在最近 30 天内,安全研究人员已经发现、分析和曝光了其它五个 Linux 木马: RexPNScanMiraiLuaBotLinux.BackDoor.Irc

Multiload-ng 是一个 GTK2 图形化系统监视器应用,可集成到 Xfce、LXDE 及 MATE 的桌面面板中, 它 fork 自原来的 GNOME Multiload 应用。它也可以运行在一个独立的窗口中。

Multiload-ng 的特点有:

  • 支持以下资源的图形块: CPU,内存,网络,交换空间,平均负载,磁盘以及温度;
  • 高度可定制;
  • 支持配色方案;
  • 自动适应容器(面板或窗口)的改变;
  • 极低的 CPU 和内存占用;
  • 提供基本或详细的提示信息;
  • 可自定义双击触发的动作。

相比于原来的 Multiload 应用,Multiload-ng 含有一个额外的图形块(温度),以及更多独立的图形自定义选项,例如独立的边框颜色,支持配色方案,可根据自定义的动作对鼠标的点击做出反应,图形块的方向可以被设定为与面板的方向无关。

它也可以运行在一个独立的窗口中,而不需要面板:

另外,它的 GitHub page 上说还会带来更多的图形块支持。

下图展示的是在带有一个垂直面板的 Xubuntu 16.04 中,该应用分别处于水平和垂直方向的效果:

这个应用的偏好设置窗口虽然不是非常好看,但是有计划去改进它:

Multiload-ng 当前使用的是 GTK2,所以它不能在构建自 GTK3 下的 Xfce 或 MATE 桌面环境(面板)下工作。

对于 Ubuntu 系统而言,只有 Ubuntu MATE 16.10 使用 GTK3。但是鉴于 MATE 的系统监视器应用也是 Multiload GNOME 的一个分支,所以它们大多数的功能相同(除了 Multiload-ng 提供的额外自定义选项和温度图形块)。

该应用的愿望清单 中提及到了计划支持 GTK3 的集成以及各种各样的改进,例如温度块资料的更多来源,能够显示十进制(KB、MB、GB……)或二进制(KiB、MiB、GiB……)单位等等。

安装 Multiload-ng

请注意因为依赖的关系, Multiload-ng 不能在 Lubuntu 14.04 上构建。

Multiload-ng 可在 WebUpd8 的主 PPA (针对 Ubuntu 14.04 - 16.04 / Linux Mint 17.x 和 18)中获取到。可以使用下面的命令来添加 PPA 并更新软件源:

sudo add-apt-repository ppa:nilarimogard/webupd8
sudo apt update

然后可以使用下面的命令来安装这个应用:

对于 LXDE (Lubuntu):

sudo apt install lxpanel-multiload-ng-plugin

对于 Xfce (Xubuntu,Linux Mint Xfce):

sudo apt install xfce4-multiload-ng-plugin

对于 MATE (Ubuntu MATE,Linux Mint MATE):

sudo apt install mate-multiload-ng-applet

独立安装 (不需要集成到面板):

sudo apt install multiload-ng-standalone

一旦安装完毕,便可以像其他应用那样添加到桌面面板中了。需要注意的是在 LXDE 中,Multiload-ng 不能马上出现在面板清单中,除非重新启动面板。你可以通过重启会话(登出后再登录)或者使用下面的命令来重启面板:

lxpanelctl restart

独立的 Multiload-ng 应用可以像其他正常应用那样从菜单中启动。

如果要下载源码或报告 bug 等,请看 Multiload-ng 的 GitHub page


via: http://www.webupd8.org/2016/08/alternative-system-monitor-applet-for.html

作者:Andrew 译者:FSSlc 校对:wxy

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

之前我们还哀叹,谷歌的 AngularJS 2.0 的稳定版看起来年底也未必能见到,然而,在 9 月 14 日谷歌总部召开的一个会议上,突然就宣布最终的稳定版发布了——而这距离前一个版本 RC7 的发布才过去了一天。

AngularJS 2.0 的开发始于 2014 年秋天,最初计划是一年后发布正式版本,然而随着项目的日渐庞大,就日复一日的拖延下来了,不过,还好,终于在两年后正式发布了。

这个最终版,按照其官方的说法是:

“最终版”意味着什么?意味着它的稳定性已经得到了大范围用例的验证;意味着它已经针对产品化、文件尺寸和性能进行过优化;意味着借助预编译技术和内置的延迟加载机制,我们可以确信你能发布出最快、最小的应用,并且横跨浏览器、桌面和移动平台;意味着为开发人员准备的 Angular CLI 和风格指南得到了大幅强化。

为什么这么期待 AngularJS 2 呢?这个框架是一个革命性的 Web 开发框架,它在 2010 年 10 月的时候,采用微软的 TypeScript 重写后,更是如虎添翼,不但性能提升、功能增强,资源占用也更少了。不过,有一个不好的消息是, AngularJS 2.0 和 1.x 是不兼容的,因此如果是用 1.x 编写的应用,可能面临着大量的重写和移植工作。

作为一个持续了两年才开发完的前端框架,它的功能特性和亮点显然不是我们一篇短文就可以道尽的,因此这里只是提到一些最引人注目的特性:

  • 提前(AOT)编译
  • 内置按需加载
  • 新的 Angular 命令行接口
  • Angular 样式指南
  • 支持 ES5 和 ES6
  • 集成 React Native 和 NativeScript
  • ……

好了,渴望尝试的 AngularJS 用户们,可以从其官网 https://angular.io/或[GitHub](https://github.com/angular/angular)上下载,这里还有一个[五分钟入门教程](https://angular.io/docs/ts/latest/quickstart.html)。(显然,你知道的,这些都是墙外的。)另外,也有一个官方认可的中文站可以去访问:https://angular.cn/

[更新] 文末补充了小米公司的申明。

你是否拥有一台小米,HTC,三星或者是一加的 Android 手机呢?

如果回答是肯定的,那么你应该意识到,几乎所有的智能手机厂商提供的定制 ROM,如 CyanogenMod、Paranoid Android、 MIUI 或者一些其它的 ROM 都带有预装主题和用来提高设备的性能的应用。

但是,对于这些设备制造商预装的程序和服务,你是否多有考虑呢?它们的目的是什么,它们是否会对个人的安全或者是隐私构成威胁。

出于这些问题答案的好奇心,一位来自荷兰的计算机专业的学生,同时也是一位安全爱好者,他拥有一台小米 4 智能手机,
正着手调查一个名为 “AnalyticsCore.apk” 的神秘预装程序。它 7 * 24 小时不间断的在后台运行,即使你删除它了还会重新出现!

小米是世界上最大的智能手机制造商之一,此前一直被批评为传播恶意软件,(它)发售预装了间谍软件/广告软件和 Android 操作系统的分支版本的手机,在没有经过用户同意的情况下,从设备中秘密窃取用户的数据

小米能够在你的设备上静默安装任何应用

在向该厂商的支持论坛询问 AnalyticsCore 的目的无果之后, Thijs Broenink 开始着手逆向此应用的代码,发现这个应用每隔 24 小时,都会从公司的服务器检查是否有该程序的更新。

在这些查询请求里,该应用将会发送设备的识别信息,包括手机的 IMEI、型号、MAC 地址、随机数、软件包名称及其签名。

如果在服务器上检测到名为 “Analytics.apk” 软件有更新的版本,它将会在后台自动的开始下载,然后安装,这一切都发生在用户不知情的情况下。

“我无法在 Analytics 中找到任何证据,所以我猜测应该有权限更高的小米应用在后台进行安装。”Broenink 在他的博客中如是说。

当前的问题是,你的设备如何验证此 APK 的正确性,以确保它真的是一个 “Analytics” 程序呢。

Broenink 发现,手机端根本没有进行任何的检查就将此程序安装到用户的手机中,这也就意味着黑客有利用此漏洞的可能。

这也就意味着小米能够远程静默的将任何程序在服务器端重命名为“Analytics.apk”后安装到用户的手机。

“所以看起来小米可以在 24 小时内把他们想要静默安装的任何(签名的?)程序包替换到你的手机上。我无法确定这个应用程序安装器什么时候被调用。但是我猜测,要是将自己的程序重命名为 Analytics.apk 后放置在正确的目录下,然后等着就会被安装了。”Broenink 说。

黑客也能利用此后门

研究人员无论是在该公司网站还是 Google 找了许久都没有发现 AnalyticsCore 程序的实际目的。很难说小米为什么在数百万的设备上放置这个神秘的“后门”。

正如我以前说过的:没有一个后门是只有他的创造者才能访问的。

所以,黑客或者是情报机构,是不是可以利用小米的这一后门在 24 小时内将恶意软件推送到数百万的设备上呢?!

更加讽刺的是,整个过程采用 HTTP 连接,也就是说它很容易受到中间人攻击。

“这听起来是一个致命的漏洞,因为它们拥有我的 IMEI 和设备的型号,它们可以专门为我的设备安装任何 APK。”Broenink 说。

即使在小米论坛,也有很多的用户对此神秘的 APK 及其目的表示疑虑。

“根本不知道这货的目的,就算是删除了它,一段时间后,它又出现了。”一位网友说道。
另一个用户表示,“如果查看电池用量程序,你会发现这货总是在最上面,鬼知道它吃了我多少电量。”

如何阻止它秘密安装呢?作为一个临时的解决方案,小米用户可以安装一个防火墙应用,然后在其中屏蔽所有小米相关域名的网络连接。

截至目前,在公司论坛上还没有小米团队的成员对 Broenink 提出的问题表示回应。我们将会持续关注此事件。

同时,如果你是小米的用户,如果在使用过程中有神秘奇怪的事情,在下方评论,以让我们知道。

来自小米的官方申明

一位小米的发言人联系到了最初发表本文的 The Hacker News,按 Thijs Broenink 的要求给出了一份官方声明,解释了关于该后门可以让黑客及小米自己在数以百万计的受影响设备上隐秘地安装任意应用的情况,声明说到:

“AnalyticsCore 是一个内置的 MIUI 系统部件,其用途是数据分析,以帮助改善用户体验,比如 MIUI 错误分析。”

虽然该公司并没有对在无需干预的情况下就能够在你的设备上自动地后台安装任何应用表示否认或发表评论,不过该发言人澄清说黑客不能够利用这个“自升级”功能。

“出于安全考虑,MIUI 会在安装或升级过程中检查 Analytics.apk 的签名,只有该 APK 来自官方并正确签名才会安装。”发言人补充道。
“任何没有官方签名的 APK 都不能安装。因为 AnalyticsCore 是确保更佳的用户体验的关键,它支持自升级功能。从发布于 4 月/ 5 月的 MIUI V7.3 开始,会启用 HTTPS 用于以后的安全数据传输,以防止任何中间人攻击。”

我们将会进一步接触小米了解其无需用户干预自动安装应用的能力。